android java time - java

i'm building an android application which have a chat.
in this chat i each message to have its time sent signature.
my question is as follow:
lets say that the time in my country is X. my friend is abroad and his time is X minus 7 hours.
i'm sending him a message at 16:00 local time.
i want to avoid the situation that he will get at 09:00 a message which it signature will be 16:00 (which is a time in future if you're looking in the eyes of that friend in his country).
is there a way that in my phone the message will be written as 16:00 and in his phone it will be written as 09:00 ? i there a way to convert a time to a local time ?

System.currentTimeMillis() does give you the number of milliseconds since January 1, 1970 00:00:00 UTC. Date object does not save your local timezone.
You can use DateFormats to convert Dates to Strings in any timezone:
DateFormat df = DateFormat.getTimeInstance();
df.setTimeZone(TimeZone.getTimeZone("gmt"));
String gmtTime = df.format(new Date());
linked response

You should keep all time communications using UTC time. Then localize it for display based on the devices current timezone setting.

Use a long to save your time information as milliseconds since "epoch" (which is January 1, 1970, 00:00:00 GMT). It can be retreived with the Date.getTime() method and new Date objects are easily created using the Date(long millis) constructor. The Date objects are then displayed using the local timezone settings on each device.
EDIT:
Epoch is a defined point in time which is expressed differently in different time zones: 1970-01-01 00:00:00 GMT but
1969-12-31 19:00:00 EST. The timestamp is just the number of milliseconds elapsed since that time. So, for example the timestamp 1341169200 corresponds to 2012-07-01 19:00:00 GMT and 2012-07-01 14:00:00 EST.

You will need to save the time zone which your message will be saved in, and transfer it (or send the unix epoch time) and then on the other side make sure you read it in with the Locale time (using the Android documentation for things like http://developer.android.com/reference/java/util/Calendar.html can help).

Take a look at the answer over here:
https://stackoverflow.com/a/6094475/346232
You need to change the time to UTC and then convert on the device to the timezone.

Avoid java.util.Date/.Calendar
The java.util.Date/.Calendar classes bundled with Java (and Android) are notoriously troublesome, flawed in both design and implementation.
Joda-Time
The Joda-Time library is the way to go. This library inspired the java.time package now built into Java 8 (not available on Android).
UTC
As other answers suggested, the best practice (generally) is to keep your business logic and data storage/communication in UTC time zone (which some think of as no time zone or an "anti" time zone). Adjust to a specific time zone only when expected by the user or data-consumer.
Time Zone
The DateTime class in Joda-Time represents a date-time value along with an assigned time zone.
Note that it is best to specify a time zone in all your operations. Otherwise you will be implicitly relying on the JVM’s current default time zone. This is risky because that zone can change – even at runtime at any moment by any code in any thread of any app running within your app’s JVM. And use proper time zone names, never the 3-4 letter codes.
Example Code
Example code in Joda-Time 2.7.
DateTime sent = DateTime.now( DateTimeZone.getDefault() ) ;
DateTime sentUtc = nowMine.withZone( DateTimeZone.UTC ) ; // Generally, use this for your work, including communicating to other threads and apps and such.
When ready to display to the other user, adjust to the expected time zone.
DateTimeZone zone = DateTimeZone.forID( "America/Montreal" ) ; // Or DateTimeZone.getDefault() if you want to rely on their JVM’s current default. To be absolutely sure of expected time zone, you really must ask the user.
DateTime sentMontréal = sentUtc.withZone( zone );
To generate a textual representation of those date-time objects, search the many Questions and Answers on StackOverflow.com on that subject. Search for terms like "joda" and "DateTimeFormatter" and "DateTimeFormat".

Related

Java epoch time on server converted to client time

A server is storing the date/time of a client action with System.currentTimeMillis(). Let's say this server is in the EST time zone.
A client in France wants to see what time that action was made. That long value stored via System.currentTimeMillis() (on the US server) is returned to the client in France.
I'm having problems understanding how to make that conversion on the client side to accurately describe their action time. My understanding is that on the server the System.currentTimeMillis() is a zoneless UTC time. Things seem strange when I instantiate a Calendar object with a "UTC" timezone, so is the server storing a time zoned epoch time when it saves with currentTimeMillis()
First attempt:
String timezone = clientTimezone;//Lets say france
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(time); //This time var is the server stored value (currentTimeMillis)
if(!timezone.equals("")) {
long timezoneAlteredTime = time + TimeZone.getTimeZone(timezone).getRawOffset();
cal = Calendar.getInstance(TimeZone.getTimeZone(timezone));
cal.setTimeInMillis(timezoneAlteredTime);
}
Other attempt:
String timezone = clientTimezone;//Lets say france
TimeZone utc = TimeZone.getTimeZone("UTC");
Calendar cal = Calendar.getInstance(utc);
cal.setTimeInMillis(time); //This time var is the server stored value
if(!timezone.equals("")) {
long timezoneAlteredTime = time + TimeZone.getTimeZone(timezone).getRawOffset();
cal = Calendar.getInstance(TimeZone.getTimeZone(timezone));
cal.setTimeInMillis(timezoneAlteredTime);
}
Am I misinterpreting this issue altogether? How would you go about this conversion
The Answer by Ole V.V. is correct: Call Instant::atZone to adjust a moment from UTC to a particular time zone. Same point on the timeline, different wall-clock time.
Here are a few more thoughts.
Let's say this server is in the EST time zone.
FYI, generally best to set UTC as the time zone on servers.
the System.currentTimeMillis() is a zoneless UTC time
Not zoneless. That method returns the number of milliseconds since the epoch reference of the first moment of 1970 as seen in UTC. (An offset-from-UTC of zero hours-minutes-seconds)
Without the context of an offset-from-UTC or a time zone, you cannot represent a moment, a specific point on the timeline.
Things seem strange when I instantiate a Calendar object
Everything about the Calendar class is strange.
That is why we stopped using that terrible class years ago. Use only the java.time classes.
A server is storing the date/time of a client action with System.currentTimeMillis().
We have a class for that: Instant. So no need to use a mere integer number, now you can use a type-safe and handy class.
The Instant class represents a moment as seen in UTC. Its objects use a resolution of nanoseconds, though most computer clocks nowadays can capture a moment as microseconds.
Instant instant = Instant.now() ;
You can convert between your count-of-milliseconds and Instant.
Instant instant = Instant.ofEpochMilli( yourCountOfMillis ) ;
An Instant is in UTC, by definition. To see the same moment from an on other offset, use OffsetDateTime. To see the same moment in a particular time zone, use ZonedDateTime.
Understand that a time zone is a history of past, present, and future changes to the offset used by the people of a particular region. Politicians frequently change the offset of their jurisdiction(s) for various reasons.
Search Stack Overflow to learn more. These issues have been covered many many times already.
java.time
This is pretty straightforward when you know how. And I recommend that you leave the work to java.time, the modern Java date and time API.
String clientTimezone = "Europe/Paris";
long time = 1_607_708_578_154L;
ZonedDateTime timeInClientTimeZone = Instant.ofEpochMilli(time)
.atZone(ZoneId.of(clientTimezone));
System.out.println(timeInClientTimeZone);
Output from this example code snippet is:
2020-12-11T18:42:58.154+01:00[Europe/Paris]
What went wrong in your code?
My understanding is that on the server the System.currentTimeMillis()
is a zoneless UTC time.
This far your understanding is correct.
Even though the epoch is usually defined in UTC, the clue here is zoneless. So you don’t need any date-time object in UTC. You also don’t need to make any adjustments to the millisecond count, so by doing so, you are turning a correct time into an incorrect one.
Link
Oracle tutorial: Date Time explaining how to use java.time.

What is logic of manipulation with timezones in Java/Kotlin?

Let's assume that I have client's time saved in my database as 2020-09-22T10:50:37.276240900
I need to present this date in web-service for client app depending on client timezone, for example I need to add 2 hours to saved date if client lives in UTC+2 timezone.
So what am I doing for ?
Getting date from entity and adding timezone to time taken from database (startDate: LocalDateTime)
entity.startDate.atZone(ZoneId.of("Europe/Vienna"))
what gives me the value of ZonedDateTime 2020-09-22T10:50:37.276240900+02:00[Europe/Vienna]
This value is what I'm expecting for, basically "initial time plus 2 hours". After that I would to format this time to have output with this 2 hours of being added, some kind of this
12:50 22.09.2020
but when I do format like this
entity.startDate
.atZone(ZoneId.of("Europe/Vienna"))
.format(DateTimeFormatter.ofPattern(NotificationListener.EUROPEAN_DATE_FORMAT, Locale.ENGLISH))
where const val EUROPEAN_DATE_FORMAT = "HH:mm dd.MM.yyyy"
I get this output 10:50 22.09.2020 which looks like my format is not applied properly, so I cannot see my 2 hours.
So my questions are:
am I correct to adding timezone of client app in described way ?
how to apply timezone in more precise way and format this date to see timezone zone applied ?
LocalDateTime.atZone does not "move" the point in time. In fact it tries to present the point in time where the local time in the given timezone is exactly what the LocalDateTime shows.
In other words: if your LocalDateTime represented 10:00 at some date, then the ZonedDateTime output of atZone will also represent 10:00 local time at the specified time zone (except in cases where that local time doesn't exist due to DST changes).
So if your stored time is actually in UTC, you need to add one more step:
ZonedDateTime utcTime = entity.startDate.atZone(ZoneOffset.UTC);
ZonedDateTime localTime = utcTime.withZoneSameInstant(ZoneId.of("Europe/Vienna"));
Alternatively you can avoid calculating the localTime each time and instead configure the DateTimeFormatter to use a given time zone (which means it'll do the necessary calculations internally) using DateTimeFormatter.withZone. If you do this then you can pass the utcTime to it directly.

What is the right way to format Time between different timezones?

I want to format time like 19:19:00 to different time zones. If I use SimpleDateFormat it always takes into account the start of the epoch: 1970.01.01.
Some timezones have different offsets on the start of the epoch and now. For example, the default offset from Europe/Kiev now is UTC+0200 but in 1970 it was UTC+0300. That means if I run my server under Europe/Kiev the client which login under Europe/Berlin(UTC+0100) will see three hours different instead of two.
I can solve this problem by writing a custom formatter for java.sql.Time. But I want to ask maybe there are some common approach or Java tools/libraries which can solve it.
Another solution can be using joda-time:
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Kiev"));
DateTimeZone.setDefault(DateTimeZone.forID("Europe/Kiev"));
DateTimeFormat.forPattern("HH:mm:ss.SSS")
.withZone(DateTimeZone.forID("Europe/Berlin"))
.print(Time.valueOf("19:00:00").getTime());
You can't format just a time to different time zones. You need a date.
If you want to assume that the date of that time is today, you can try this code:
ZoneId originalZone = ZoneId.of("Europe/Kiev");
ZoneId targetZone = ZoneId.of("Europe/Berlin");
LocalTime originalTime = LocalTime.parse("19:19:00");
LocalTime convertedTime = LocalDate.now(originalZone)
.atTime(originalTime)
.atZone(originalZone)
.withZoneSameInstant(targetZone)
.toLocalTime();
System.out.println(convertedTime);
Is java.time.instant an alternative for you? It handles all Timestamps internally as UTC-Time.
One way to parse it from a string is Instant.parse("2018-05-30T19:00:00")
If you want to have the time for a specific timezone you can get it with myInstant.atZone("Zone")
ZoneId originalZone = ZoneId.of("Europe/Kiev");
ZoneId targetZone = ZoneId.of("Europe/Berlin");
LocalDate assumedDate = LocalDate.now(originalZone);
String formattedTime = assumedDate.atTime(LocalTime.parse("19:19:00"))
.atZone(originalZone)
.withZoneSameInstant(targetZone)
.format(DateTimeFormatter.ofPattern("HH:mm:ss"));
System.out.println(formattedTime);
Today this printed:
18:19:00
When you know the date, you should of course use that instead of just today. In the case of Kyiv and Berlin I think they follow the same rules for summer time (DST), so the precise date may not be important. If converting between zones that don’t use the same transitions, or between a time zone that uses summer time and one that doesn’t, it’s suddenly crucial. And who knows in which of those two countries the politicians will change the rules next year? Better be safe.
Link: Oracle tutorial: Date Time explaining how to use java.time.

java print date different than the system

I need to set the system date in Centos 6.6 so what i did
cp /usr/share/zoneinfo/Europe/Paris /etc/localtime
And I wrote a small java application to print date and I print the date with the command date and i got this
[root#sandbox ~]# date
Fri May 20 19:13:32 CEST 2016
[root#sandbox ~]# java t
Fri May 20 17:13:35 UTC 2016
I really need to know why i have different time and how to fix it?
And i don't want to make change to the java code i want to fix the system date
We cannot precisely assist you until you post the source code for that little Java app.
Tracking date-time
One general concept you seem to be misunderstanding is that a date-time as tracked by a computer has no time zone. If you are using the old outmoded class java.util.Date, it tracks a number of milliseconds since the epoch reference date of first moment of 1970 in UTC.
Date-time != String
Another concept: A date-time object is not a string. You can generate a String to represent the date-time value in your date-time object, but that string is distinct from the date-time. Remember, internally that date-time is actually a count of milliseconds since 1970 UTC).
Your app is likely calling the toString method on java.util.Date class. That method confusingly applies the JVM’s current default time zone to the stored date-time creating the false illusion that the java.util.Date has that zone assigned.
Default time zone
The default time zone is usually picked up from the host OS when the JVM launches, but not always. Configuration flags for the JVM may indicate another time zone as default. And any code in any thread of any app within the JVM can change the JVM’s default time zone at any moment, during runtime! Because of being undependable, I suggest you avoid using the default, and instead always specify the desired/expected time zone.
Generally best practice is to keep servers on UTC. But I do not want my app to be vulnerable to such externalities as some sysadmin changing the server’s time zone, I always specify the desired/expected time zone in my Java code (shown further down).
No problem
So you have no problem to fix. Paris time (CEST) of 19:13:3x is two hours ahead of UTC, which your Java app is correctly showing as 17:13:3x for UTC time zone. These values make sense. These two date-time strings are two different representations of the very same moment on the timeline.
If you want a Paris time in your Java app, ask for a Paris time (shown further down below). If you want UTC, ask for UTC in your Java app (also shown further down).
As to why your Java app is showing the time in UTC remains a mystery until you show us your source code.
In the mean time, I can show the basics of capturing the current time and adjusting into a desired time zone.
java.time
You are use old date-time classes that have proven to be troublesome, confusing, and flawed. Avoid them. These old classes have been supplanted by the java.time framework built into Java 8 and later. Much of the java.time functionality has been back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP.
An Instant is the current moment on the timeline in UTC, with resolution of nanoseconds (finer than the milliseconds in java.util.Date).
Instant instant = Instant.now();
Generally best to much of your business logic, database storage, other storage, and data exchange in UTC. So make frequent use of Instant.
Wall-clock time
Apply a time zone to get the wall-clock time for some locality. Apply a ZoneId to get a ZonedDateTime.
ZoneId zoneId = ZoneId.of( "Europe/Paris" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
Generating ISO 8601 strings
The toString methods in java.time by default generate strings in the standard ISO 8601 formats. The ZonedDateTime class’ toString method extends the standard by appending the name of the time zone in square brackets.
String output = instant.toString();
2016-05-21T00:52:53.375Z
String output = zdt.toString();
2016-05-21T02:52:53.375+02:00[Europe/Paris]
You can adjust into yet another time zone. Notice the date being previous to that of Paris, 20 versus 21 of May (still “yesterday” in Montréal).
ZonedDateTime zdt_Montréal = zdt.withZoneSameInstant( ZoneId.of( "America/Montreal" ) ) ;
2016-05-20T20:52:53.375-04:00[America/Montreal]
So we have generated three different textual representations of the very same moment on the timeline (UTC, Paris, & Montréal).
Time zones
Avoid using 3-4 letter zone abbreviations like CEST. These are neither standardized, nor unique(!). Furthermore, they are not true time zones. Always use proper time zone names, in the format of continent/region.
if you don't like or you can't change java code then you have to change server/system/centos timeZone, First you have to see list of possible timezones in
ls /usr/share/zoneinfo
and result
see we have date Sat May 21 02:54:11 IRDT 2016 we are now going to change you need to change (or set) the symbolic link /etc/localtime so make a backup of the existing `localtime file
sudo mv /etc/localtime /etc/localtime.bak
Next, create the link:
sudo ln -s /usr/share/zoneinfo/America/Chicago /etc/localtime
Make sure to replace America/Chicago with the directory (if your zone has one) and filename of the timezone you wish to use for example
sudo ln -s /usr/share/zoneinfo/UTC /etc/localtime
Now you just need to test your change. Run date from the command line, i done it and result are
and for see huge list of timezone click here
Make sure you also check your /etc/timezone file and adjust accordingly
Ok first you should think of using #Basil-Bourque answer to change your code. it's a good practice
and for changing you Centos timezone try to export TZ to Europe/Paris like the following
export TZ="Europe/Paris"

Setting server timezone to add/subtract time from date

I have users that set their timezone when they create their account. Their account can expire after so many days and the user is able to search for accounts expiring on X day. When the search is run it uses the browser's timezone instead of the users timezone. I have set the timezone like so:
CountryDAO countryDao = new CountryDAO();
String timezone = countryDao.findTimezone(advisor.getPlannerID());
TimeZone.setDefault(TimeZone.getTimeZone(timezone));
DateFormat sdf = new SimpleDateFormat();
sdf.setTimeZone(TimeZone.getDefault());
this code does not set the time zone to the server. I use datapicker to select the date and search but it still uses GMT and not the timezone that is set.
How do I use the time zone that is set?
As the correct answer by Meno Hochschild, java.util.TimeZone.setDefault() is a static method affecting your entire JVM. Not what you want.
Avoid using java.util.Date & Calendar classes. They are badly designed and implemented.
Instead, use the Joda-Time library to manipulate your date-times. Nearly all of Joda-Time is immutable and thread-safe. So it is good for use in servlets & JSP.
Generally you want to work in UTC/GMT, meaning no time zone offset. When presenting to the user, then localize to a particular time zone, format, and language.
I don't know how you are doing it, but it seems that you are determining the user's time zone. Good. (a) Be sure your time zone string is a name of a time zone rather than the outmoded 3-letter code. Those 3-letter codes are neither standardized nor unique. (b) If you are using some kind of JavaScript or other trick to detect and report system settings on the client machine, consider offering the user a way to select a time zone as well. The user may be "thinking" in one time zone while their machine is set for another.
Use that time zone name string to instantiate a DateTimeZone in Joda-Time. Pass that timeZone as an argument to various Joda-Time methods.
DateTimeZone timeZone = DateTimeZone.forId( timeZoneName );
In Joda-Time, a DateTime knows its own time zone (in contrast to a java.util.Date). If you do not specify a time zone, you get the JVM's default time zone. Big tip: Always specify a time zone rather than rely on default, to avoid surprises when running in production.
DateTime dateTimeInUTC = new DateTime( DateTimeZone.UTC );
DateTime dateTimeInParis = dateTimeInUTC.toDateTime( DateTimeZone.forId( "Europe/Paris" ) );
You can add and subtract years, months, days, hours, and such in Joda-Time. And comparison methods test if dates come before or after each other. To find the beginning of a day, call withTimeAtStartOfDay (do not just set hours to zero, as not all days in all zones start at midnight).
DateTime aWeekAgoDateTime = new DateTime( timeZone ).withTimeAtStartOfDay().minusWeeks( 1 ).withTimeAtStartOfDay();
…
boolean isMoreThanWeekOld = someDateTime.isBefore( aWeekAgoDateTime );
Beyond that, I cannot help any more. Your question is not clear. What search? A database? An array or other collection? In JavaScript on client? In Java on server?
TimeZone.setDefault(...) is statically setting the time zone of the JVM (here on the server) for all users. I assume you rather want to set the time zone of the current user session. If so, then you need a special jsp session attribute where you store and read the time zone preference of the user.

Categories

Resources