mde / timezone-js

DEPRECATED: Timezone-enabled JavaScript Date object. Uses Olson zoneinfo files for timezone data.
824 stars 182 forks source link

Arithmetic around DST results in incorrect times #34

Closed divide0 closed 4 years ago

divide0 commented 12 years ago

Code

            console.log("Testing timezone-js dst transition...\n");
            var dt = new timezoneJS.Date(2006, 9, 29, 0, 59, 'America/Los_Angeles');
            console.log("12:59AM: " + dt.toString("EEE, dd MMM yyyy HH:mm:ss Z"));
            dt.setTime(dt.getTime() + (1 * 60 * 1000));
            console.log("Add 1 minute (First 1AM): " + dt.toString("EEE, dd MMM yyyy HH:mm:ss Z"));
            dt.setTime(dt.getTime() + (60 * 60 * 1000));
            console.log("Add 1 hour (Second 1AM): " + dt.toString("EEE, dd MMM yyyy HH:mm:ss Z"));

            console.log("\n\nTesting native dst transition...\n");
            var dt = new Date(2006, 9, 29, 0, 59);
            console.log("12:59AM: " + dt.toString());
            dt.setTime(dt.getTime() + (1 * 60 * 1000));
            console.log("Add 1 minute (First 1AM): " + dt.toString());
            dt.setTime(dt.getTime() + (60 * 60 * 1000));
            console.log("Add 1 hour (Second 1AM): " + dt.toString());

Output

Testing timezone-js dst transition... 12:59AM: Sun, 29 Oct 2006 00:59:00 PDT Add 1 minute (First 1AM): Sun, 29 Oct 2006 01:00:00 PDT Add 1 hour (Second 1AM): Sun, 29 Oct 2006 02:00:00 PST

Testing native dst transition... 12:59AM: Sun Oct 29 2006 00:59:00 GMT-0700 (Pacific Daylight Time) Add 1 minute (First 1AM): Sun Oct 29 2006 01:00:00 GMT-0700 (Pacific Daylight Time) Add 1 hour (Second 1AM): Sun Oct 29 2006 02:00:00 GMT-0700 (Pacific Daylight Time)

Upshot

The native date is more correct because although it doesn't have the correct time zone offset (says pacific daylight time instead of pacific standard time), the time that is outputted results in the correct point in time.

longlho commented 12 years ago

Hmm I'll take a look at this

divide0 commented 12 years ago

Forgot to mention that I tested this in Firefox, Chrome, and IE8.

divide0 commented 12 years ago

Another interesting tidbit. I am on Windows 7. The native date is not showing the PST time zone for October 29, because it doesn't use the historical transition rules. It uses the current transition rules to determine if we are in DST or not. This doesn't work for 2006, since DST was changed in 2007. It incorrectly identifies the fall 2006 transition date as Nov 5, which it would have been if the current rules were applied to the date in 2006.

var d = new Date(2006,10,5);
console.log(d.toString())

d.setTime(d.getTime() + 2 * 60 *60 * 1000);
console.log(d.toString())

output

Sun Nov 05 2006 00:00:00 GMT-0700 (Pacific Daylight Time) Sun Nov 05 2006 01:00:00 GMT-0800 (Pacific Standard Time)

ericontech commented 11 years ago

Currently experiencing this same issue. Browser is in America/Los_Angeles zone (PST). When parsing a date on DST transition offset if calculated incorrectly, example:

tzt = new timezoneJS.Date("2012-11-04T00:00:00-04:00", "America/New_York"); tzt.toString();

Output:

"2012-11-03 23:00:00"

markrcote commented 11 years ago

Not sure if this is related or not, but I see some very weird behaviour with setTime() and DST-ST transitions. This is with latest timezone-js code and the Olson db from about a week ago.

I'm doing a three-step process to initialize the Date object because it doesn't appear possible to give the constructor a Unix timestamp.

timezoneJS.timezone.zoneFileBasePath = "tz";
timezoneJS.timezone.init();

function logDate(d) {
  console.log(d.getTime());
  console.log(d.getFullYear() + '/' + (d.getMonth() + 1) + '/' + d.getDate() + ' ' + d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds());
}

var d = new timezoneJS.Date();
d.setTimezone('UTC')
d.setTime(1351990800000);
logDate(d);
d.setTime(1351994400000);
logDate(d);
d.setTime(1351998000000);
logDate(d);

Output:

1351990800000
2012/11/4 1:0:0
1351990800000
2012/11/4 1:0:0
1351994400000
2012/11/4 2:0:0

There are (at least) two problems here: UTC doesn't have DST, and, as far as I know, setTime() and getTime() should be reciprocal regardless of timezone or DST rules (number of milliseconds since the epoch is independent of DST rules, which should only affect calendar and clock time).

SlainVeteran commented 11 years ago

It seems you cannot even rely on the UTC handling around DST crossovers:

 (new timezoneJS.Date("2013-03-31T01:30:00Z", "Europe/London")).toISOString()

I would expect this to output "2013-03-31T01:30:00Z" but it outputs "2013-03-31T00:30:00Z" which is incorrect.