Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

javascript incorrectly determines daylight savings time line -- an example out of 2006

I have read many StackOverflow questions on the javascript new Date() object when it comes to daylight savings time lines -- as in when they are crossed. However, I haven't seen an answer about this particular problem or a way to work around it while still relying on 'unix time'.

I have personally chosen to work around this issue by passing the javascript date as a date to my PHP code rather than the unix time. Yet, the nagging question still remains! I have confirmed this behavior on IE8, Chrome, and FF so I'm assuming it will behave the same for you. (Update: OSX users might not be able to generate this behavior)

My Research; the closest questions to my issue:

  • This user was working on the particular hours right around the DST change.
  • This user was worried about the presentation of the time depending on the user's time zone. The accepted answer on that page mentioned that getTimezoneOffset is "flaky" which led me to not delve into that.
  • See my answer below on other questions that have some great insights

I have generated a test scenario around November 1st, 2006. This may or may not work the same for you depending on the time zone you are in. If I understand the javascript aspect correctly, you will need to synchronize your PC's clock to

Eastern Time (US & Canada) and check the 'Automatically adjust clock for Daylight Saving Time'.

I am basing this experiment off of the "Indianapolis" time zone in PHP. My javascript result, when I find the unix time for November 1st, 2006 is one hour off of what the PHP generates (3600 seconds). According to this page (Thanks Jon!) javascript is wrong.

The two languages results' come back into agreement on 11/06/2006!

This and other research causes me to believe that Javascript got its history wrong and picked the wrong Sunday to 'Fall back' out of DST -- thereby causing the discrepancy I am seeing.

I have tried to simplify this as much as possible but there are still quite a few gears in motion.

  1. Here is the PHP code and output that shows the CORRECT number of milliseconds until the date 11/01/2006.

    date_default_timezone_set("America/Indiana/Indianapolis"); echo "Unixtime for November 1, 2006 is: ".strtotime("11/01/2006")."\n"; echo "Unixtime for November 6, 2006 is: ".strtotime("11/06/2006");

The result is:

Unixtime for November 1, 2006 is: 1162357200 (where the disagreement lies)
Unixtime for November 6, 2006 is: 1162789200

Both of them are based off of GMT-0500.

  1. In Javascript, (see my jsfiddle**), I call new Date and then getTime() upon it like so (and remove the milliseconds):

    new Date("2006/11/01").getTime()/1000 new Date("2006/11/06").getTime()/1000

This generates the values

1162353600 <-- PHP outputs: 1162357200
1162789200 <-- the same as PHP for '2006/11/06'; congruence is restored

which is a difference (for 2006/11/01) from the output via PHP of 3600 seconds -- or one hour. This value (one hour earlier) when processed in my PHP application generated the prior day (2006/10/31) which was unacceptable since it broke my navigation forward. (see more explanation of my particular scenario)

Outputting in Javascript: Date("2006/11/01") without calling getTime() clears up some of the mystery because javascript reveals the offset it was using GMT-0400.

My jsfiddle** experiment (also listed above) shows these results.

**(you may need to change your computer's timezone to see the identical behavior).

Possibly coming into play is that according to Wikipedia 2006 was the first year that Indiana began using DST. A curious puzzle either way.

Since I have already worked out my solution (by avoiding relying on unix time in my javascript) I thought I should post this for posterity and hopefully someone might know how to correct the value javascript is showing.

The question is this: How does one bring the two 'unix time' results between PHP and javascript into alignment? I would be grateful to learn how around the DST 'line' or in general. (I'm currently assuming the DST line is the problem).

Update: an iMac running Chrome generated the results that PHP is generating. What??? Wild. Any javascript-side fix to this behavior looks like it would be a great undertaking (or at least ugly). Perhaps this is not a javascript problem since it generates the correct answer depending on the OS (or other factors?).

Notably, on this iMac I did not force the timezone and I'm not sure this Apple computer would allow it. The settings for "Set date and time automatically" was checked (true) and disabled. The time zone was set to Eastern Daylight Time. The box to 'Set timezone automatically' was unchecked (false) and disabled.

I added the Windows tag to highlight that it doesn't seem to be a problem in OSX.

Update: According to the site linked above, I verified that all the following dates crossed into a new GMT offset on the appropriate dates (updated fiddle) -- unlike how the 2006 response was one week off. I.e., on November 4th, 2007, it was GMT-4 and November 5th, 2007, it returned GMT-5.

  • 2007 Sunday, March 11 at 2:00 AM Sunday, November 4 at 2:00 AM
  • 2008 Sunday, March 9 at 2:00 AM Sunday, November 2 at 2:00 AM
  • 2009 Sunday, March 8 at 2:00 AM Sunday, November 1 at 2:00 AM
  • 2010 Sunday, March 14 at 2:00 AM Sunday, November 7 at 2:00 AM
  • 2011 Sunday, March 13 at 2:00 AM Sunday, November 6 at 2:00 AM

Lastly, if you know the proper channels to submit this error in 2006 to whatever timezone source Javascript is relying on, please do so and let me know about it.

like image 812
veeTrain Avatar asked May 09 '12 18:05

veeTrain


1 Answers

Firstly, time in Indiana is very complicated.

But in this case, I believe Javascript is wrong. The output of your Javascript on my machine (having set the time zone) is "Wed Nov 01 2006 00:00:00 GMT-0400 (Eastern Daylight Time)" on Chrome and "Wed Nov 1 00:00:00 EDT 2006" on Internet Explorer - but daylight saving time ended in Indianapolis in 2006 on October 29th.

.NET's TimeZoneInfo class gives the same result:

// Ignore the daft ID; it really means Eastern time
var zone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
var local = new DateTime(2006, 11, 1);
Console.WriteLine(zone.GetUtcOffset(local));

Output:

-5:00:00

(So it knows it's not in daylight saving time then.)

Likewise in Noda Time (my own date and time library, which uses the tzdb database):

var zone = DateTimeZone.ForId("America/Indiana/Indianapolis");
var instant = new Instant(1162357200 * NodaConstants.TicksPerSecond);
var zoned = new ZonedDateTime(instant, zone);
Console.WriteLine(zoned);

Result:

Local: 01/11/2006 00:00:00 Offset: -05 Zone: America/Indiana/Indianapolis
like image 52
Jon Skeet Avatar answered Nov 16 '22 16:11

Jon Skeet