Skip to content

Commit 32c74ff

Browse files
ossy-szegedrerobika
authored andcommitted
Fix Date.prototype.toString() and toISOString() (#3175)
The implementation was incorrect for negative years and years bigger than 9999. -1 was 000/ because the negative (year%10) was added to '0' character, years bigger than 9999 was truncated to 4 digits. ES5.1 15.9.1.15.1 defines extended years format with 6 digits, but toString() and toISOString() sections don't mention anything about extended years. ES6 20.3.4.3 already clarifies that Date.prototype.toISOString() should use this extended year format if it is necessary. Changes: - Date.prototype.toString() uses 4 digits for years by default, 5 or 6 if it is necessary and put '-' sign for negative years, no sign for positive years. Date.prototype.toString() was implementation dependent until ES9, but ES9 already specify exactly this format. - Date.prototype.toISOString() uses fixed 4 digits for years 0 - 9999, otherwise sign + 6 digits (extended years). - Tests added for corner cases. JerryScript-DCO-1.0-Signed-off-by: Csaba Osztrogonác [email protected]
1 parent fbca37f commit 32c74ff

File tree

3 files changed

+119
-3
lines changed

3 files changed

+119
-3
lines changed

jerry-core/ecma/builtin-objects/ecma-builtin-helpers-date.c

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,7 @@ ecma_date_to_string_format (ecma_number_t datetime_number, /**< datetime */
587587
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
588588
};
589589

590-
const uint32_t date_buffer_length = 34;
590+
const uint32_t date_buffer_length = 37;
591591
JERRY_VLA (lit_utf8_byte_t, date_buffer, date_buffer_length);
592592

593593
lit_utf8_byte_t *dest_p = date_buffer;
@@ -611,7 +611,32 @@ ecma_date_to_string_format (ecma_number_t datetime_number, /**< datetime */
611611
case LIT_CHAR_UPPERCASE_Y: /* Year. */
612612
{
613613
number = (int32_t) ecma_date_year_from_time (datetime_number);
614-
number_length = 4;
614+
615+
if (number >= 100000 || number <= -100000)
616+
{
617+
number_length = 6;
618+
}
619+
else if (number >= 10000 || number <= -10000)
620+
{
621+
number_length = 5;
622+
}
623+
else
624+
{
625+
number_length = 4;
626+
}
627+
break;
628+
}
629+
case LIT_CHAR_LOWERCASE_Y: /* ISO Year: -000001, 0000, 0001, 9999, +012345 */
630+
{
631+
number = (int32_t) ecma_date_year_from_time (datetime_number);
632+
if (0 <= number && number <= 9999)
633+
{
634+
number_length = 4;
635+
}
636+
else
637+
{
638+
number_length = 6;
639+
}
615640
break;
616641
}
617642
case LIT_CHAR_UPPERCASE_M: /* Month. */
@@ -723,6 +748,17 @@ ecma_date_to_string_format (ecma_number_t datetime_number, /**< datetime */
723748
/* Print right aligned number values. */
724749
JERRY_ASSERT (number_length > 0);
725750

751+
if (number < 0)
752+
{
753+
number = -number;
754+
*dest_p++ = '-';
755+
}
756+
else if (*(format_p - 1) == LIT_CHAR_LOWERCASE_Y && number_length == 6)
757+
{
758+
/* positive sign is compulsory for extended years */
759+
*dest_p++ = '+';
760+
}
761+
726762
dest_p += number_length;
727763
lit_utf8_byte_t *buffer_p = dest_p;
728764

@@ -785,7 +821,7 @@ ecma_date_value_to_utc_string (ecma_number_t datetime_number) /**< datetime */
785821
ecma_value_t
786822
ecma_date_value_to_iso_string (ecma_number_t datetime_number) /**<datetime */
787823
{
788-
return ecma_date_to_string_format (datetime_number, "$Y-$O-$DT$h:$m:$s.$iZ");
824+
return ecma_date_to_string_format (datetime_number, "$y-$O-$DT$h:$m:$s.$iZ");
789825
} /* ecma_date_value_to_iso_string */
790826

791827
/**

tests/jerry/date-toisostring.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright JS Foundation and other contributors, http://js.foundation
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
try {
16+
d = new Date (-8640000000000001)
17+
assert (d == "Invalid Date")
18+
d.toISOString()
19+
assert(false);
20+
} catch (e) {
21+
assert(e instanceof RangeError)
22+
}
23+
24+
assert (new Date (-8640000000000000).toISOString() == "-271821-04-20T00:00:00.000Z")
25+
26+
assert (new Date(-62167219200001).toISOString() == "-000001-12-31T23:59:59.999Z")
27+
assert (new Date(-62167219200000).toISOString() == "0000-01-01T00:00:00.000Z")
28+
29+
assert (new Date(-61851600000001).toISOString() == "0009-12-31T23:59:59.999Z")
30+
assert (new Date(-61851600000000).toISOString() == "0010-01-01T00:00:00.000Z")
31+
32+
assert (new Date(-59011459200001).toISOString() == "0099-12-31T23:59:59.999Z")
33+
assert (new Date(-59011459200000).toISOString() == "0100-01-01T00:00:00.000Z")
34+
35+
assert (new Date(-30610224000001).toISOString() == "0999-12-31T23:59:59.999Z")
36+
assert (new Date(-30610224000000).toISOString() == "1000-01-01T00:00:00.000Z")
37+
38+
assert (new Date(-1).toISOString() == "1969-12-31T23:59:59.999Z")
39+
assert (new Date(0).toISOString() == "1970-01-01T00:00:00.000Z")
40+
assert (new Date(1).toISOString() == "1970-01-01T00:00:00.001Z")
41+
42+
assert (new Date(253402300799999).toISOString() == "9999-12-31T23:59:59.999Z")
43+
assert (new Date(253402300800000).toISOString() == "+010000-01-01T00:00:00.000Z")
44+
45+
assert (new Date (8640000000000000).toISOString() == "+275760-09-13T00:00:00.000Z")
46+
47+
try {
48+
d = new Date (8640000000000001)
49+
assert (d == "Invalid Date")
50+
d.toISOString()
51+
assert(false);
52+
} catch (e) {
53+
assert(e instanceof RangeError)
54+
}

tests/jerry/date-tostring.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,29 @@ assert (Date (2015, 1, 1) == (new Date ()).toString ());
142142
assert (Date (Number.NaN) == Date ());
143143

144144
assert (new Date ("2015-07-08T11:29:05.023Z").toISOString() == "2015-07-08T11:29:05.023Z");
145+
146+
// corner cases
147+
assert (new Date (-8640000000000001).toString() == "Invalid Date")
148+
assert (new Date (-8640000000000000).toString() == "Tue Apr 20 -271821 00:00:00 GMT+00:00")
149+
150+
assert (new Date(-62167219200001).toString() == "Fri Dec 31 -0001 23:59:59 GMT+00:00")
151+
assert (new Date(-62167219200000).toString() == "Sat Jan 01 0000 00:00:00 GMT+00:00")
152+
153+
assert (new Date(-61851600000001).toString() == "Thu Dec 31 0009 23:59:59 GMT+00:00")
154+
assert (new Date(-61851600000000).toString() == "Fri Jan 01 0010 00:00:00 GMT+00:00")
155+
156+
assert (new Date(-59011459200001).toString() == "Thu Dec 31 0099 23:59:59 GMT+00:00")
157+
assert (new Date(-59011459200000).toString() == "Fri Jan 01 0100 00:00:00 GMT+00:00")
158+
159+
assert (new Date(-30610224000001).toString() == "Tue Dec 31 0999 23:59:59 GMT+00:00")
160+
assert (new Date(-30610224000000).toString() == "Wed Jan 01 1000 00:00:00 GMT+00:00")
161+
162+
assert (new Date(-1).toString() == "Wed Dec 31 1969 23:59:59 GMT+00:00")
163+
assert (new Date(0).toString() == "Thu Jan 01 1970 00:00:00 GMT+00:00")
164+
assert (new Date(1).toString() == "Thu Jan 01 1970 00:00:00 GMT+00:00")
165+
166+
assert (new Date(253402300799999).toString() == "Fri Dec 31 9999 23:59:59 GMT+00:00")
167+
assert (new Date(253402300800000).toString() == "Sat Jan 01 10000 00:00:00 GMT+00:00")
168+
169+
assert (new Date (8640000000000000).toString() == "Sat Sep 13 275760 00:00:00 GMT+00:00")
170+
assert (new Date (8640000000000001).toString() == "Invalid Date")

0 commit comments

Comments
 (0)