Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why date is changing with same number of milliseconds on different time zones?

We know that getTime method of java.util.Date returns the number of milliseconds since January 1, 1970, 00:00:00 GMT represented by this Date object.

I noticed a weird situation as below;

System time zone is:(UTC+02:00) Istanbul

Date currentDate = new Date();
System.out.println(currentDate .getTime());
System.out.println(currentDate);

Java ConsoleOutput:

1360753217219

Wed Feb 13 13:00:17 VET 2013


Then my javascript plugin is using this long object like below;

Javascript:

console.log(new Date(1360753217219));

Browser ConsoleOutput:

Date {Wed Feb 13 2013 13:00:17 GMT+0200 (Turkey Standard Time)}


Thats all ok, however! After change my local time zone as (UTC-04:30) Caracas, situation and hour is changing as below with same number of milliseconds;


Javascript:

console.log(new Date(1360753217219));

Browser ConsoleOutput:

Date {Wed Feb 13 2013 06:30:17 GMT-0430 (Venezuela Standard Time)}

Can someone explain this? Is that js bug? Or more importantly, how should I handle this on java side, to get same date with same number of miliseconds for different time zones on js side?

Thanks!

like image 407
gokhansari Avatar asked Feb 13 '13 11:02

gokhansari


3 Answers

The milliseconds are time zone agnostic. Time is measured as an absolute since Jan 1, 1970 GMT. So, the idea is that you get the milliseconds and then work out what the local time for a given time zone is after the fact. If you think about it, it makes sense. The number of milliseconds that have passed since 1970 are the same no matter where you are.

It gets a bit confusing but do NOT noodle around with the milliseconds in order to adjust for time zones. Every Date library has mechanisms to translate a millisecond stamp into a time zone specific local time.

So if your specific question is how to communicate the date effectively between the server and the client (what languages you're using is not important), the answer is it's perfectly safe to pass milliseconds back and forth and work out on either side what global specific time you're talking about, if that's important to the context of what you're doing with that time.

like image 121
Yevgeny Simkin Avatar answered Oct 23 '22 17:10

Yevgeny Simkin


not a bug, that's just how time zones work.

if you call someone in Venezuela right now and ask him what time it is, he'll tell you it's 6.5 (according to your example) hours earlier than the time in turkey.

as you mentioned, the number you're dealing with represents the number of milliseconds since 1970, 00:00:00 GMT, in Caracas at that very same second, the time was 31.12.1969 19:30 GMT-0430

so, however many seconds later, the time in Venezuela will still be 4:30 hours earlier compared to GMT.

you can't get the exact same date in different time zones if you use the same input (milliseconds) because that would simply be wrong.

if you want to get the same result, you could add the difference in timezones (6.5 hours in this case) to the output. following Dr.Dredel's advice, you probably shouldn't mess with the milliseconds.

like image 28
yurib Avatar answered Oct 23 '22 16:10

yurib


tl;dr

Instant.ofEpochMilli( 1_360_753_217_219L )         // UTC

2013-02-13T11:00:17.219Z

Instant.ofEpochMilli( 1_360_753_217_219L )    
       .atZone( ZoneId.of( "Europe/Istanbul" ) )   // Same moment, two hours *ahead* of UTC.

2013-02-13T13:00:17.219+02:00[Europe/Istanbul]

Instant.ofEpochMilli( 1_360_753_217_219L )    
       .atZone( ZoneId.of( "America/Caracas" ) )   // Same moment, four-and-a-half hours *behind* UTC.

2013-02-13T06:30:17.219-04:30[America/Caracas]

Using java.time

You are using troublesome old date-time classes bundled with the earliest versions of Java. They are now legacy, supplanted by the java.time classes, the best date-time library on any platform.

Start with your number of milliseconds since an epoch reference date of the beginning of 1970 in UTC (1970-01-01T00:00:00Z). Others point out that you may not grasp that an epoch reference date has a time zone, and here with this epoch that zone is UTC, an offset of zero hours. All other offsets are measured against this one, a number of hours and minutes ahead of UTC or behind UTC.

The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).

long input = 1_360_753_217_219L ;
Instant instant = Instant.ofEpochMilli( input ) ;

instant.toString(): 2013-02-13T11:00:17.219Z

If you want to see that same moment through the lens of a particular region’s wall-clock time, apply a time zone.

A time zone is a history of past, present, and future changes to the offset in use by a particular region.

Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

ZoneId zEurope_Istanbul = ZoneId.of( "Europe/Istanbul" ) ;
ZonedDateTime zdtEurope_Istanbul = instant.atZone( zEurope_Istanbul ) ;

zdtEurope_Istanbul.toString(): 2013-02-13T13:00:17.219+02:00[Europe/Istanbul]

You can apply another time zone.

ZoneId zAmerica_Caracas = ZoneId.of( "America/Caracas" ) ;
ZonedDateTime zdtAmerica_Caracas = zdtEurope_Istanbul.withZoneSameInstant( zAmerica_Caracas ) ;

zdtAmerica_Caracas.toString(): 2013-02-13T06:30:17.219-04:30[America/Caracas]

See this code live at IdeOne.com.

These three objects, instant & zdtEurope_Istanbul & zdtAmerica_Caracas, all represent the very same simultaneous moment, the same point on the timeline.

Your count-from-epoch represents 11 AM in UTC. Istanbul is two hours ahead of UTC, so the time-of-day there at the same moment is two hours after 11 AM, 1 PM (13:00). Venezuela is four and a half hours behind UTC, so the time-of-day there at the same moment is 6:30 AM. These all make sense, all the same moment but different wall-clock time.

ISO 8601

Do not use a count-from-epoch for exchanging or storing date-time values. That is error-prone, being impposible to read meaningfully by a human, and ambiguous as there are at least a couple dozen epoch reference dates in use by various software systems and at different granularities (whole seconds, milliseconds, microseconds, nanoseconds, etc.).

When passing date-time values outside your JVM, use the standard ISO 8601 formats for textual representation. The java.time classes use the standard formats by default when parsing/generating strings. You can see those formats in this Answer’s example code.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

Where to obtain the java.time classes?

  • Java SE 8, Java SE 9, and later
    • Built-in.
    • Part of the standard Java API with a bundled implementation.
    • Java 9 adds some minor features and fixes.
  • Java SE 6 and Java SE 7
    • Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android
    • The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
    • See How to use ThreeTenABP….

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

like image 20
Basil Bourque Avatar answered Oct 23 '22 15:10

Basil Bourque