Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ES 5.1 Extended years and Date.prototype.toISOString #66

Closed
Yaffle opened this issue Sep 27, 2011 · 20 comments
Closed

ES 5.1 Extended years and Date.prototype.toISOString #66

Yaffle opened this issue Sep 27, 2011 · 20 comments

Comments

@Yaffle
Copy link
Contributor

Yaffle commented Sep 27, 2011

Your implementaion is not full compatible with ES!
see http://es5.github.com/#x15.9.1.15

when year < 0 or year > 9999
6 digits format with sign for year < 0 should be used

test case:
alert(new Date(-1,1,0).toISOString()); // alerts "0-1-01-30T18:00:00.000Z"

@Yaffle
Copy link
Contributor Author

Yaffle commented Sep 27, 2011

Some browser implementations (Opera) fails too
Some test suits (test.ecmascript.org) doen't have such tests

Date.parse fails with extended years too.

@Yaffle
Copy link
Contributor Author

Yaffle commented Sep 27, 2011

test case for Date.parse:

Date.parse("+033658-09-27T01:46:40.000Z") === 1e15

@michaelficarra
Copy link
Member

Pinging @kitcambridge, who recently rewrote Date::toISOString and Date.parse (mid-August 2011).

@ghost
Copy link

ghost commented Sep 27, 2011

I'm on it...I originally avoided implementing extended years due to cases where Date.UTC would choke on them, but there may be a way to circumvent that.

@Yaffle
Copy link
Contributor Author

Yaffle commented Sep 27, 2011

https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/UTC

The UTC method differs from the Date constructor in two ways.
Date.UTC uses universal time instead of the local time.
Date.UTC returns a time value as a number instead of creating a Date object.

So Date constructor can be used instead of Date.UTC with adjustment to local time, am i right?

@Yaffle
Copy link
Contributor Author

Yaffle commented Sep 27, 2011

and why "Date.UTC would choke on them" would choke on extended years?

@ghost
Copy link

ghost commented Sep 27, 2011

I did not add support for extended years to Date.parse for two reasons. The first is that you cannot pass extended years to either the date constructor or Date.UTC, which my implementation uses internally to compute a millisecond value for the provided date time string. Consider the following examples of date time strings containing extended years from section 15.9.1.15.1 of the spec:

-283457-03-21T15:00:59.008Z (283458 B.C.)
-000001-01-01T00:00:00Z (2 B.C.)
+000000-01-01T00:00:00Z (1 B.C.)
+000001-01-01T00:00:00Z (1 A.D.)
+001970-01-01T00:00:00Z (1970 A.D.)
+002009-12-15T00:00:00Z (2009 A.D.)
+287396-10-12T08:59:00.992Z (287396 A.D.)

Here are the corresponding millisecond values produced by a native implementation of Date.parse:

Date.parse("-283457-03-21T15:00:59.008Z") == -9007199254740992;
Date.parse("-000001-01-01T00:00:00Z") == -62198755200000;
Date.parse("+000000-01-01T00:00:00Z") == -62167219200000;
Date.parse("+000001-01-01T00:00:00Z") == -62135596800000;
Date.parse("+001970-01-01T00:00:00Z") == 0;
Date.parse("+002009-12-15T00:00:00Z")== 1260835200000;
Date.parse("+287396-10-12T08:59:00.992Z")== 9007199168340992;

Contrastingly, here are the values produced by my Date.parse implementation, where the various date time string components are passed directly to Date.UTC. Note that my implementation accounts for timezone offsets as well; however, since the examples in 15.9.1.15.1 do not specify offsets, I've omitted them for brevity:

Date.UTC(-283457, 2, 21, 15, 0, 59, 8); // NaN.
Date.UTC(-1, 0, 1) == -62198755200000; // Correct.
Date.UTC(0, 0, 1) == -2208988800000; // Incorrect.
Date.UTC(1, 0, 1) == -2177452800000; // Incorrect.
Date.UTC(1970, 0, 1) == 0; // Correct.
Date.UTC(2009, 11, 15) == 1260835200000; // Correct.
Date.UTC(287396, 9, 12, 8, 59, 0, 992); // NaN.

Quite a disparity.

The second reason that I did not implement extended year support is practicality. According to section 15.9.1.1 of the spec, valid ECMAScript date values (i.e., the primitive millisecond values of date objects, obtained by Date::getTime or Date::valueOf) range from -8.64e15 to 8.64e15. Hence, for any date object Q to be valid, -8.64e15 < Q.getTime() < 8.64e15. If the value of Q.getTime() falls outside this range, Q is an invalid date and, consequently, its millisecond value is NaN. Furthermore, this proof suggests that, if -8.64e15 < P < 8.64e15, where P is a primitive millisecond value computed by Date.parse(Y, M - 1, D, H, M, S, MS), then new Date(P).getTime() == P, and, by implication, new Date(Date.parse(Y, M - 1, D, H, M, S, MS)).getTime() == P.

This implication does not hold true for extended years, however. Notice that, in the first example, -9007199254740992 < -8.64e15 and 9007199168340992 > -8.64e15. Hence, P = Date.parse(Y, M - 1, D, H, M, S, MS), but new Date(P).getTime() != P. As such, dates containing particularly large or small extended year components cannot be meaningfully used in JavaScript, except perhaps for basic arithmetic or number manipulation.

@Yaffle
Copy link
Contributor Author

Yaffle commented Sep 27, 2011

Date.UTC(0, 0, 1) == -2208988800000; // Incorrect.
Date.UTC(1, 0, 1) == -2177452800000; // Incorrect.
why incorrect?
if year is not NaN and 0 <= ToInteger(year) <= 99 ... then let year be 1900 + ...

@Yaffle
Copy link
Contributor Author

Yaffle commented Sep 27, 2011

15.9.1.1
1e8 DAYS, not milliseconds!

am i right?

@ghost
Copy link

ghost commented Sep 27, 2011

why incorrect?
if year is not NaN and 0 <= ToInteger(year) <= 99 ... then let year be 1900 + ...

@Yaffle That's why. Because the date time string components are currently converted to numbers and passed directly to Date.UTC, the current Date.parse implementation will return an incorrect millisecond value for some extended years. Date.UTC is returning the expected result; the Date.parse shim wouldn't.

@ghost
Copy link

ghost commented Sep 27, 2011

am i right?

@Yaffle Yes, you're correct. Apologies.

@Yaffle
Copy link
Contributor Author

Yaffle commented Sep 27, 2011

also in which browser use receive:

Date.parse("-283457-03-21T15:00:59.008Z") == -9007199254740992;
?
Date.parse("-283457-03-21T15:00:59.008Z") === NaN in Chrome

@ghost
Copy link

ghost commented Sep 27, 2011

@Yaffle Date.parse("-283457-03-21T15:00:59.008Z") works in Safari 5.1 and Firefox 6.0. Odd that it doesn't work in Chrome.

@Yaffle
Copy link
Contributor Author

Yaffle commented Sep 27, 2011

Date.parse("+275760-09-13T00:00:00.000Z") === 8.64e15 - biggest correct value

@Yaffle
Copy link
Contributor Author

Yaffle commented Sep 27, 2011

@kitcambridge in my Firefox and Safari it doesn't work
It seems, only Chrome support extended years...

@ghost
Copy link

ghost commented Sep 27, 2011

@Yaffle Yikes, those inconsistencies aren't encouraging at all! The latest WebKit nightly builds seem to support extended years as well. Should we just patch Date::toISOString and note in the documentation that extended years aren't supported for Date.parse at this point?

@Yaffle
Copy link
Contributor Author

Yaffle commented Sep 28, 2011

I can't understand why it's impossible to support extended years in Date.parse...

@Yaffle
Copy link
Contributor Author

Yaffle commented Sep 28, 2011

Current implementaion also fails for year between 0 and 99,
because Date.UTC converts year to 1900 + year

It seems, there is simple workaround:
in javascript: each period of 400 years has same number of milliseconds
so for years between 0 and 99
you could call Date.UTC(400 + year, ....) , then subtrack 12622780800000
(12622780800000 - number of milliseconds in period of 400 years)

@Yaffle
Copy link
Contributor Author

Yaffle commented Sep 28, 2011

here is my patched Date.parse with some tests (tested in IE7-9, FF 6, Opera 12, Chrome 14):
(Chrome 14 uses native implementation)
https://gist.github.com/1247258

@Yaffle
Copy link
Contributor Author

Yaffle commented Sep 28, 2011

and my patched "toISOString"
https://gist.github.com/1247301

@Yaffle Yaffle closed this as completed Oct 3, 2011
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants