From 4f58fb12e31d8cc50e964c1c7f47ffd289b3c866 Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Wed, 19 Apr 2017 17:48:56 +0300 Subject: [PATCH] Fixed parsing ISO 8601 format in Date.parse(). Fixed parsing in case milliseconds are not specified. Added converting to local time in case "Z" suffix is not specified. Also minor style fixes included. --- njs/njs_date.c | 51 ++++++++++++++++++++++++++++++---------- njs/test/njs_unit_test.c | 36 ++++++++++++++++++++++++++-- 2 files changed, 73 insertions(+), 14 deletions(-) diff --git a/njs/njs_date.c b/njs/njs_date.c index 8d5bfe6d..4136d1b4 100644 --- a/njs/njs_date.c +++ b/njs/njs_date.c @@ -304,9 +304,10 @@ njs_date_parse(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, static nxt_noinline double njs_date_string_parse(njs_value_t *date) { - int ext, ms; + int ext, ms, ms_length, skipped; + double time; struct tm tm; - nxt_bool_t sign, week; + nxt_bool_t sign, week, utc; const u_char *p, *next, *end; njs_string_prop_t string; @@ -319,11 +320,7 @@ njs_date_string_parse(njs_value_t *date) return NAN; } - if (*p == '+') { - p++; - sign = 1; - - } else if (*p == '-') { + if (*p == '+' || *p == '-') { p++; sign = 1; @@ -403,6 +400,14 @@ njs_date_string_parse(njs_value_t *date) return NAN; } + utc = 1; + end--; + + if (*end != 'Z') { + utc = 0; + end++; + } + p = njs_date_time_parse(&tm, p + 1, end); if (nxt_slow_path(p == NULL)) { return NAN; @@ -412,20 +417,42 @@ njs_date_string_parse(njs_value_t *date) goto done; } - if (nxt_slow_path(p >= end || *p != '.')) { + if (nxt_slow_path(p > end || *p != '.')) { return NAN; } - p = njs_date_number_parse(&ms, p + 1, end, 3); + p++; + + ms_length = (end - p < 3) ? end - p : 3; + + p = njs_date_number_parse(&ms, p, end, ms_length); if (nxt_slow_path(p == NULL)) { return NAN; } - if (nxt_slow_path(p >= end || *p != 'Z')) { - return NAN; + if (end > p) { + p = njs_date_number_parse(&skipped, p, end, end - p); + if (nxt_slow_path(p == NULL)) { + return NAN; + } + } + + if (ms_length == 1) { + ms *= 100; + + } else if (ms_length == 2) { + ms *= 10; + } + + if (utc) { + time = njs_timegm(&tm); + + } else { + tm.tm_isdst = -1; + time = mktime(&tm); } - return njs_timegm(&tm) * 1000 + ms; + return time * 1000 + ms; } if (sign) { diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index 4a5aaa7c..f6b38e46 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -5713,15 +5713,47 @@ static njs_unit_test_t njs_test[] = { nxt_string("Date.parse('2011-06-24T06')"), nxt_string("NaN") }, - { nxt_string("Date.parse('2011-06-24T06:01')"), + { nxt_string("Date.parse('2011-06-24T06:')"), + nxt_string("NaN") }, + + { nxt_string("Date.parse('2011-06-24T06:01:')"), + nxt_string("NaN") }, + + { nxt_string("Date.parse('2011-06-24T06:01Z')"), nxt_string("1308895260000") }, - { nxt_string("Date.parse('2011-06-24T06:01:02')"), + { nxt_string("Date.parse('2011-06-24T06:01:02:')"), + nxt_string("NaN") }, + + { nxt_string("Date.parse('2011-06-24T06:01:02Z')"), nxt_string("1308895262000") }, + { nxt_string("Date.parse('2011-06-24T06:01:02.Z')"), + nxt_string("NaN") }, + + { nxt_string("Date.parse('2011-06-24T06:01:02.6Z')"), + nxt_string("1308895262600") }, + + { nxt_string("Date.parse('2011-06-24T06:01:02.62Z')"), + nxt_string("1308895262620") }, + + { nxt_string("Date.parse('2011-06-24T06:01:02:625Z')"), + nxt_string("NaN") }, + { nxt_string("Date.parse('2011-06-24T06:01:02.625Z')"), nxt_string("1308895262625") }, + { nxt_string("Date.parse('2011-06-24T06:01:02.6255555Z')"), + nxt_string("1308895262625") }, + + { nxt_string("Date.parse('2011-06-24T06:01:02.625555Z5')"), + nxt_string("NaN") }, + + { nxt_string("var d = new Date(); var str = d.toISOString();" + "var diff = Date.parse(str) - Date.parse(str.substring(0, str.length - 1));" + "d.getTimezoneOffset() == -diff/1000/60"), + nxt_string("true") }, + { nxt_string("Date.parse('24 Jun 2011')"), nxt_string("1308873600000") }, -- 2.47.3