Difference Timezones Browser and Java - javascript

I have a question regarding Date/Time/Timezones differences in the Browser (JS) and Java running on the same machine in the same timezone. I am aware that systems should agree on the timezone (UTC mainly, use Date.UTC) to avoid such issues. Nevertheless I thought this example should work fine.
For this I created some dates with the Browser (Chrome) and used the same millis to create a Date with Java.
Here is an example which I don't understand. Please help me to understand.
Chrome (JavaScript):
new Date(1980,9,10,0,0,0,0)
Fri Oct 10 1980 00:00:00 GMT+0200 (Mitteleuropäische Sommerzeit)
The millis are: 339976800000
Java:
new Date(339976800000l)
Thu Oct 09 23:00:00 CET 1980
Please note Java applies CET wheras JavaScript applies CEST.

tl;dr
Definition of Daylight Saving Time (DST) changed between 1980 and 2016.
Previously DST ended on last Sunday of September, later changed to end on last Sunday of October.
Detailed Answer
The missing piece of the puzzle is knowing the specific time zone used in your calculations. Your Question and example code fails to tell us exactly what time zones were utilized. My discussion here assumes you used a time zone similar to that of Europe/Berlin (based on your use of text apparently localized in German language), in that its definition of DST changed.
CET and CEST are not actually time zones. Such abbreviations are not standardized, nor even unique. Avoid them.
Instead use proper time zone names as defined in the tz database. A true time zone is an offset-from-UTC plus a set of rules for handling anomalies past, present, and future, such as Daylight Saving Time (DST).
The time zone rules change, and change surprisingly often. Bored politicians, I suppose.
For example, Europe/Berlin changed in 1980 to end DST on last Sunday in September. So DST does not apply to your date of October 1980. Since 1996 EU rules apply, extending DST to last Sunday of October rather than September. Thus DST does apply to your October 10th date in 2016.
The code in the Question uses month “9” which actually means “10”, October. One of the many problems with the old java.util.Date class is that it counts months by zero-based counting, 0 = January. One of many many reasons to avoid the old date-time classes. In contrast, in java.time the month number for October is indeed 10 as you would expect, and you can use a constant from the Month enum to be even more clear.
By the way, another poor design choice in java.util.Date is that when constructing a Date object as you did in the Question, your JVM’s current default time zone was applied, and the result adjusted back to UTC. This further complicates your Question as you did not report the time zone in use at the time you ran your code.
By the way, JavaScript, like nearly every development platform, has poor support for date-time work. Try to use Java and its built-in java.time framework whenever possible. See Oracle Tutorial. You can witness java.time in action in the following example code. We get October 10th in 1980 and in 2016 for Europe/Berlin.
ZoneId zoneId = ZoneId.of ( "Europe/Berlin" );;
ZonedDateTime zdt_1980 = ZonedDateTime.of ( 1980 , Month.OCTOBER.getValue () , 10 , 0 , 0 , 0 , 0 , zoneId );
long seconds_1980 = zdt_1980.toEpochSecond ();
ZonedDateTime zdt_2016 = ZonedDateTime.of ( 2016 , Month.OCTOBER.getValue () , 10 , 0 , 0 , 0 , 0 , zoneId );
long seconds_2016 = zdt_2016.toEpochSecond ();
Dump to console.
System.out.println ( "zoneId: " + zoneId );
System.out.println ( "zdt_1980: " + zdt_1980 + " | seconds_1980: " + seconds_1980 );
System.out.println ( "zdt_2016: " + zdt_2016 + " | seconds_2016: " + seconds_2016 );
You can see in the results that the offset-from-UTC changed from one hour ahead of UTC (+01:00) in the old days to now two hours ahead of UTC (+02:00). The difference is because of the re-definition of DST.
So, this explains why you got "CET" in 1980 but "CEST" in 2016. The S in CEST that you got for 2016 means "Summer", and “Summer Time” means DST. In this year of 2016, most of October is in "Summer Time" (DST). In 1980, October was not in DST/"Summer Time"/"CEST".
zoneId: Europe/Berlin
zdt_1980: 1980-10-10T00:00+01:00[Europe/Berlin] | seconds_1980: 339980400
zdt_2016: 2016-10-10T00:00+02:00[Europe/Berlin] | seconds_2016: 1476050400

Related

Creating Date by iso ''0001-01-01T01:00:00' adding 16 second

new Date("0001-01-01T01:00:00Z") --> Mon Jan 01 0001 02:50:16 GMT+0150 (Moscow Standard Time)
Incorrect GMT: my timezone GMT+3000, but date creates GMT+0150
For dates, you can (and should, in my opinion) define them in UTC ISO 8601 "Z" format ("YYYY-MM-DDTHH:MM:SSZ"), just as you did.
However, to get a user-friendly string representation of those dates, it will depend on your client and on the Javascript engine used. You can constrain the output if you explicitly specify a reference timezone with toLocaleString().
var date = new Date("1990-01-01T01:00:00Z");
console.log(date.toLocaleString("en-US", {timeZone: "Asia/Jerusalem"}));
console.log(date.toLocaleString("en-US", {timeZone: "Europe/Moscow"}));
console.log(date.toLocaleString("en-US", {timeZone: "Africa/Djibouti"}));
// output on my machine, should be the same on yours :
// 1/1/1990, 3:00:00 AM
// 1/1/1990, 4:00:00 AM
// 1/1/1990, 4:00:00 AM
console.log(date.toString());
// output **on my machine**, should **not** be the same on yours
// Mon Jan 01 1990 02:00:00 GMT+0100 (Central European Standard Time)
For the 16 seconds issue, this is linked to the way offset are defined by the rules for those dates before the notion of IANA timezone existed.
They probably don't make sense in your application, and I discourage you to use dates like 1st January of year 0001 for your examples.
Examples :
var date = new Date("0001-01-01T01:00:00Z");
console.log(date.toLocaleString("en-US", {timeZone: "Asia/Jerusalem"}));
console.log(date.toLocaleString("en-US", {timeZone: "Europe/Moscow"}));
console.log(date.toLocaleString("en-US", {timeZone: "Africa/Djibouti"}));
// output on my machine, should be the same on yours :
// 1/1/1, 3:20:54 AM
// 1/1/1, 3:30:17 AM
// 1/1/1, 3:27:16 AM
console.log(date.toString());
// output **on my machine**, should **not** be the same on yours
// Mon Jan 01 0001 01:09:21 GMT+0009 (Central European Standard Time)
More information here (thanks Johan Karlsson for the link) :
https://bugs.chromium.org/p/chromium/issues/detail?id=849404
The most relevant comment from this link is, I think :
This is working as intended and working per spec. The spec says that
we have to follow the IANA timezone database.
In 1880, there's no standard timezone and America/Los_Angeles timezone
offset was based on its longitude. The same is true of other
timezones.
Also note that there are many timezone around the world the zone
offset (and whether or not to have DST or when to start DST) have
changed multiple times even since 2000 (e.g. Europe/Moscow). The
change to make them work correctly also brought in what's reported
here.
Pac0's answer is correct (and you should accept that answer since it came first, not this one). But just to provide a detailed explanation:
Dates from before recorded history of time zones are marked in the time zone database as LMT - which stands for Local Mean Time. The offsets are derived from the latitude and longitude of the city, not by any current political determination.
Since the offset shown is 1:50:16 ahead of UTC, I can derive that your system time zone is Europe/Minsk. This is seen in the tzdb sources here:
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Europe/Minsk 1:50:16 - LMT 1880
This is just the first line of the zone entry for Europe/Minsk, which says that until 1880, use the LMT entry of UTC+1:50:16.
As to why it says "Moscow Standard Time" - that string comes from the Unicode CLDR data, which in the /common/supplemental/metaZones.xml file we can see:
<timezone type="Europe/Minsk">
<usesMetazone to="1991-03-30 23:00" mzone="Moscow"/>
<usesMetazone to="2011-03-27 00:00" from="1991-03-30 23:00" mzone="Europe_Eastern"/>
<usesMetazone to="2014-10-26 22:00" from="2011-03-27 00:00" mzone="Europe_Further_Eastern"/>
<usesMetazone from="2014-10-26 22:00" mzone="Moscow"/>
</timezone>
So Europe/Minsk uses the Moscow metazone up until 1991. Then, using one of the language files such as /common/main/en.xml for English, we can see the actual text assigned to this metazone:
<metazone type="Moscow">
<long>
<generic>Moscow Time</generic>
<standard>Moscow Standard Time</standard>
<daylight>Moscow Summer Time</daylight>
</long>
</metazone>
And now you have a complete picture for how the string Mon Jan 01 0001 02:50:16 GMT+0150 (Moscow Standard Time) was derived from 0001-01-01T01:00:00Z.
A timezone is an offset plus a date range. To format your date, javascript wants to know what the timezone offset was for Moscow in the year zero. This is hard information to come by, and might not be accurate ! You think you're asking something simple, but it's actually pretty extreme. If you want to use the date object to represent durations, you should take the epoch as your starting point.

Why in javascript, creating date between 1st October 1941 and 14th October 1945 adding GMT+0630 as time zone

My Time Zone is (UTC +05:30)Chennai, Kolkata, Mumbai, New Delhi.
For Example:
var date1 = new Date(1944,04,22,0,0,0);
console.log("date1: " + date1);
// output :
// date1: Mon May 22 1944 00:00:00 GMT+0630 (India Standard Time)
var date2 = new Date(1992,11,28,0,0,0);
console.log("date2: " + date2);
// output :
// date2: Mon Dec 28 1992 00:00:00 GMT+0530 (India Standard Time)
date1 is adding GMT+0630 at the end. But if I will take a date after 1945 then it is fine i.e it adds GMT+0530.
Why one extra hour is getting added in Time zone for dates between 1st October 1941 and 14th October 1945.
When i convert date1 in C# with:
Convert.ToDateTime("1944-05-21T17:30:00.000Z").ToString("dd/MM/yyyy");
It gives me 21/05/1944 instead of 22/05/1944.
How can i get correct Date and Time in C#?
A few things:
Indeed, India did use UTC+6:30 for several periods in the 1940's. This information is recorded in the IANA time zone database. You can also refer to the detail of time in India here.
.NET (when running on Windows) does not use the IANA time zone database, but rather the Microsoft Windows time zone database. You can read about some of the differences between these two data sets in the timezone tag wiki.
The Windows time zone database generally does not have the long term history of most time zones. For India Standard Time, it doesn't have any history - assuming that UTC+5:30 has always been in effect. If your application needs to know about historical time zone information, then you have two options:
If you are using .NET Core, you can run on a non-Windows OS (Linux, MacOS, etc.) which uses the full IANA time zone database. The standard TimeZoneInfo, DateTime, and DateTimeOffset APIs will use this data on non-Windows machines.
You can bring your own copy of the IANA TZDB data via a library such as Noda Time. Then you can run on any OS you want. Of course, you will need to stay updated to get changes to the TZDB.
A Noda Time example for your scenario looks like this:
Instant utcTime = Instant.FromUtc(1944, 5, 21, 17, 30);
DateTimeZone tz = DateTimeZoneProviders.Tzdb["Asia/Kolkata"];
ZonedDateTime zdt = utcTime.InZone(tz);
LocalDateTime ldt = zdt.LocalDateTime;
Console.WriteLine(ldt.ToString("dd/MM/yyyy", CultureInfo.InvariantCulture));
There are, of course, shorter ways to write this - and APIs within NodaTime for parsing, formatting, manipulation, conversion etc. But I think you get the point.

Weird behavior of javascript date api for the year 1941/1942

I noticed an odd interpretation of timestamps by the javascript Date api.
For all the Dates included between 01/10/1941 and 31/03/1942, the interpretation subtract 1 to the actual hour, leading to display errors when the stored time is 0h00.
I store thoses dates in a SQLServer db; then they are retrieved in a Java entity through Hibernate, and eventually they are served to the client browser as a webservice.
In the following 2 exemples, you can see that according to whether the date is between 01/10/1941 and 31/03/1942 or not, the result displayed by javascript Date constructor is not the same...
I know this period was quite a mess in France (where the browser is running) : the 2nd world war and France occupation by a foreign administration made the standards quite erratic... but I am quite sceptic about the fact that this is the cause of my problem : that would imply that the javascript Date api applies very specific rules... and that java does not apply the same!
Indeed, I may be wrong... but I still have a problem anyway : though there are not that many users born during that period, I still need to display their birthday correctly.
So, any tip, explanation, suggestion are welcomed here!
------------- SQLSERVER --------------
User.birthday : DATETIME
=> update user set birthday = cast('31/10/1941' as date) where id = xxx
=> select User.birthday where id = xxx
=> 1941-10-31 00:00:00.000
------------- JAVA --------------
User.java => User.birthDay : java.util.Date
=> Hibernate => User u = selectById(xxx);
=> u.getBirthDay().cdate : 1941-10-31T00:00:00.000+0200
=> u.getBirthDay().getTime() : -888976800000
=> u.getBirthDay().getClass() : java.sql.Timestamp
------------ JAVASCRIPT ------------------
new Date(-888976800000) => Thu Oct 30 1941 23:00:00 GMT+0100
------------- SQLSERVER --------------
User.birthday : DATETIME
=> update user set birthday = cast('26/09/1941' as date) where id = xxx
=> select User.birthday where id = xxx
=> 1941-09-26 00:00:00.000
------------- JAVA --------------
User.java => User.BirthDay : java.util.Date
=> Hibernate => User u = selectById(xxx);
=> u.getBirthDay().cdate : 1941-09-26T00:00:00.000+0200
=> u.getBirthDay().getTime() : -892000800000
=> u.getBirthDay().getClass() : java.sql.Timestamp
------------ JAVASCRIPT ------------------
new Date(-892000800000) => Fri Sep 26 1941 00:00:00 GMT+0200
Thanks for reading until here.
Your assumption about France time zones is most probably correct.
If you print GMT/UTC time, it outputs correctly:
new Date(-888976800000).toUTCString(); // "Thu, 30 Oct 1941 22:00:00 GMT"
new Date(-892000800000).toUTCString(); // "Thu, 25 Sep 1941 22:00:00 GMT"
My advice would be to use UTC dates for everything, and only as a last step apply timezone correction.
Ask yourself: if John was born on Feb 12th in Japan, and it's Feb 12th in Japan, but only Feb 11th in France, does he already have a birthday or not?
I had a similar issue with dates for Italy (Italy kept daylight saving during both winters of 1940/1941 and 1941/1942).
Since all major browser (Chrome, Firefox, Edge) showed the same behavior, I suspected that they were working as intended. In fact, checking the JavaScript specs I noted that until version 5.1 of the standard it was stated that
The implementation of ECMAScript should not try to determine whether the
exact time was subject to daylight saving time, but just whether daylight
saving time would have been in effect if the current daylight saving time
algorithm had been used at the time. This avoids complications such as
taking into account the years that the locale observed daylight saving
time year round.
From this i think that it means that it will simply apply the timezone rules currently in use even if at the time they were not valid. This would explain your issue.
In version 6 the same thing has been worded differently:
An implementation dependent algorithm using best available information on
time zones to determine the local daylight saving time adjustment
DaylightSavingTA(t), measured in milliseconds. An implementation of
ECMAScript is expected to make its best effort to determine the local
daylight saving time adjustment.
NOTE It is recommended that implementations use the time zone information
of the IANA Time Zone Database http://www.iana.org/time-zones/.
This means that in theory we can expect an ES6 compliant browser to return the correct answer, but since it is still a "best effort", this is not guaranteed (and in fact no one of the browser I tried did it correctly).
If you already use moment.js to handle date/time in javascript, you may want to use moment-timezone, since it has its own timezone database and will return the right answer (minus converting from ms to seconds and vice-versa).
> new Date(-888976800000)
Thu Oct 30 1941 23:00:00 GMT+0100 (CET) [wrong answer]
> moment("1941-10-31 00:00:00").unix()
-888973200 [wrong answer]
> moment.tz("1941-10-31 00:00:00", "Europe/Paris").unix()
-888976800 [right answer]

Javascript: Why a date does not return the right day?

I'm from Brazil and I've written this piece of code in Javascript
var dt = new Date(2012,9,21); // Oct-21-2012
alert(dt.getDate());
However, it produces 20 and not 21. I've tested with Firefox 18, Chrome 24 and Internet Explorer 8.
How it is possible?
You came across a huge coincidence.
In Brazil, Oct-21-2012 is the start of daylight saving time in most of the country, so local dates at Oct-21-2012 between 0:0 and 1:0 doesn't exist in Brazil!
Some people from other countries did not face the same problem in the same date.
See: http://www.timeanddate.com/news/time/brazil-dst-2012.html
In Brazil the code inside the question really outputs 20
var dt = new Date(2012,9,21); // 21-Oct-2012 0:0
alert(dt.getDate());
However, a slight change generates 21, because 1 hour is enough to "jump over" the lost hour:
var dt = new Date(2012,9,21,1); // 21-Oct-2012 1:00
alert(dt.getDate());
See: http://www.timeanddate.com/time/dst/2013.html
Edit after comments: In United States, for instance, at 10 March, 2013 will start the daylight saving time.
var dt = new Date(2013,02,10); // March-10-2013
alert(dt.getDate()); // Output: 10
Why it is right? Because in the USA the daylight saving time jumps at 2:00 and not 0:00 like in Brazil, therefore implicit 0 hour protect the generated date against problems.However, it is still possible errors in hours elapsing calculation.
-/-
In Brazil the situation should to induce a bug in many sites that handle with dates, regardless of time. One can enter a date in a form and the algorithm calculating elapsed days in a wrong way.
For instance, if somebody uses this nice javascript code to enter dates in a form (
DHML Goodies Calendar ), and after one decides to save that date in a database, it is possible that one get the wrong date, if one has a bad luck to meet special dates.
The definitive solution is use UTC (Coordinated Universal Time) time, because there is no Daylight Saving changes and you use a kind of abstract time. In most practical applications there is no problem.
var dt = new Date( Date.UTC(2012, 9, 21, 8, 5, 12));
alert( (dt.getUTCMonth()+1) + '/' + dt.getUTCDate() + '/' +
dt.getUTCFullYear() + " " + dt.getUTCHours()+ ':' +
dt.getUTCMinutes() + ':' + dt.getUTCSeconds() );
Instead of using UTC, it is easier, if someone doesn't use hours, minutes and seconds, just put a dummy hour value greater or equal than 1, as I have shown above, in Date() call.
Edit after comments: So the Brazil (and countries like Iran,Lebanon, Paraguay, Chile and Portugal ) should change the start of daylight saving time to 2:00 and not 0:00, in order to avoid this confusion and get aligned to more developed countries.
-/-

If javascript "(new Date()).getTime()" is run from 2 different Timezones

If JavaScript (new Date()).getTime() is run from 2 different timezones simultaneously, will you get the same value?
Will this value be affected by the system time set on the machine where the browser is running?
Yes, it's affected by system time. However, if the local time is correct (for whatever time zone the computer's set to), it should be the same in any time zone.
The ECMAScript standard says (§15.9.1.1):
"Time is measured in ECMAScript in
milliseconds since 01 January, 1970
UTC."
Code:
var today = new Date();
console.log(today);
var t = today.getTime();
console.log(t);
My Computer in the UK:
Sat Sep 21 2013 03:45:20 GMT+0100 (GMT Daylight Time)
1379731520112
My VPS:
Sat, 21 Sep 2013 02:44:31 GMT
1379731471743
Difference between getTime values is 48,369 milliseconds (48s) out of sync not the 1 hour zone difference
You won't get the same value - difference between two client's browsers picking up their system time, but if their time is set up ok, you should get two times with a minimal difference since getting the timestamp using new Date(), you can get the UTC value (new Date() returns number of milliseconds ellapsed since January 1, 1970, and that won't change), which is universal time and is location agnostic.
There will most likely always be a deviation between times attained between machines, but (I was wrong before) JavaScript Date() takes the UTC timezone as default.
Usually when time is essential, it's best to simply use the Server time and apply timezone corrections to that in the output if required.

Categories