From: ricow@chromium.org Date: Mon, 3 May 2010 06:43:25 +0000 (+0000) Subject: Added support for ES5 date time string format to Date.parse. X-Git-Tag: upstream/4.7.83~21898 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6ceb02e6eb791f837ed84b7ed41332058cd3f1dc;p=platform%2Fupstream%2Fv8.git Added support for ES5 date time string format to Date.parse. Review URL: http://codereview.chromium.org/1704016 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4557 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/date.js b/src/date.js index 216d5df..b9e19d6 100644 --- a/src/date.js +++ b/src/date.js @@ -620,7 +620,7 @@ function DatePrintString(time) { // ------------------------------------------------------------------- // Reused output buffer. Used when parsing date strings. -var parse_buffer = $Array(7); +var parse_buffer = $Array(8); // ECMA 262 - 15.9.4.2 function DateParse(string) { @@ -628,13 +628,13 @@ function DateParse(string) { if (IS_NULL(arr)) return $NaN; var day = MakeDay(arr[0], arr[1], arr[2]); - var time = MakeTime(arr[3], arr[4], arr[5], 0); + var time = MakeTime(arr[3], arr[4], arr[5], arr[6]); var date = MakeDate(day, time); - if (IS_NULL(arr[6])) { + if (IS_NULL(arr[7])) { return TimeClip(UTC(date)); } else { - return TimeClip(date - arr[6] * 1000); + return TimeClip(date - arr[7] * 1000); } } diff --git a/src/dateparser-inl.h b/src/dateparser-inl.h index d5921d5..be353a3 100644 --- a/src/dateparser-inl.h +++ b/src/dateparser-inl.h @@ -54,16 +54,25 @@ bool DateParser::Parse(Vector str, FixedArray* out) { } else { // n + ":" if (!time.Add(n)) return false; + in.Skip('.'); } + } else if (in.Skip('.') && time.IsExpecting(n)) { + time.Add(n); + if (!in.IsAsciiDigit()) return false; + int n = in.ReadUnsignedNumber(); + time.AddFinal(n); } else if (tz.IsExpecting(n)) { tz.SetAbsoluteMinute(n); } else if (time.IsExpecting(n)) { time.AddFinal(n); - // Require end or white space immediately after finalizing time. - if (!in.IsEnd() && !in.SkipWhiteSpace()) return false; + // Require end, white space or Z immediately after finalizing time. + if (!in.IsEnd() && !in.SkipWhiteSpace() && !in.Is('Z')) return false; } else { if (!day.Add(n)) return false; in.Skip('-'); // Ignore suffix '-' for year, month, or day. + // Skip trailing 'T' for ECMAScript 5 date string format but make + // sure that it is followed by a digit (for the time). + if (in.Skip('T') && !in.IsAsciiDigit()) return false; } } else if (in.IsAsciiAlphaOrAbove()) { // Parse a "word" (sequence of chars. >= 'A'). diff --git a/src/dateparser.cc b/src/dateparser.cc index 51a63e1..e68532f 100644 --- a/src/dateparser.cc +++ b/src/dateparser.cc @@ -33,6 +33,16 @@ namespace v8 { namespace internal { bool DateParser::DayComposer::Write(FixedArray* output) { + // Set year to 0 by default. + if (index_ < 1) { + comp_[index_++] = 1; + } + + // Day and month defaults to 1. + while (index_ < kSize) { + comp_[index_++] = 1; + } + int year = 0; // Default year is 0 (=> 2000) for KJS compatibility. int month = kNone; int day = kNone; @@ -88,6 +98,7 @@ bool DateParser::TimeComposer::Write(FixedArray* output) { int& hour = comp_[0]; int& minute = comp_[1]; int& second = comp_[2]; + int& millisecond = comp_[3]; if (hour_offset_ != kNone) { if (!IsHour12(hour)) return false; @@ -95,11 +106,13 @@ bool DateParser::TimeComposer::Write(FixedArray* output) { hour += hour_offset_; } - if (!IsHour(hour) || !IsMinute(minute) || !IsSecond(second)) return false; + if (!IsHour(hour) || !IsMinute(minute) || + !IsSecond(second) || !IsMillisecond(millisecond)) return false; output->set(HOUR, Smi::FromInt(hour)); output->set(MINUTE, Smi::FromInt(minute)); output->set(SECOND, Smi::FromInt(second)); + output->set(MILLISECOND, Smi::FromInt(millisecond)); return true; } @@ -134,6 +147,7 @@ const int8_t DateParser::KeywordTable:: {'p', 'm', '\0', DateParser::AM_PM, 12}, {'u', 't', '\0', DateParser::TIME_ZONE_NAME, 0}, {'u', 't', 'c', DateParser::TIME_ZONE_NAME, 0}, + {'z', '\0', '\0', DateParser::TIME_ZONE_NAME, 0}, {'g', 'm', 't', DateParser::TIME_ZONE_NAME, 0}, {'c', 'd', 't', DateParser::TIME_ZONE_NAME, -5}, {'c', 's', 't', DateParser::TIME_ZONE_NAME, -6}, diff --git a/src/dateparser.h b/src/dateparser.h index d339a4f..d999d9c 100644 --- a/src/dateparser.h +++ b/src/dateparser.h @@ -44,13 +44,14 @@ class DateParser : public AllStatic { // [3]: hour // [4]: minute // [5]: second - // [6]: UTC offset in seconds, or null value if no timezone specified + // [6]: millisecond + // [7]: UTC offset in seconds, or null value if no timezone specified // If parsing fails, return false (content of output array is not defined). template static bool Parse(Vector str, FixedArray* output); enum { - YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, UTC_OFFSET, OUTPUT_SIZE + YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, MILLISECOND, UTC_OFFSET, OUTPUT_SIZE }; private: @@ -189,7 +190,9 @@ class DateParser : public AllStatic { TimeComposer() : index_(0), hour_offset_(kNone) {} bool IsEmpty() const { return index_ == 0; } bool IsExpecting(int n) const { - return (index_ == 1 && IsMinute(n)) || (index_ == 2 && IsSecond(n)); + return (index_ == 1 && IsMinute(n)) || + (index_ == 2 && IsSecond(n)) || + (index_ == 3 && IsMillisecond(n)); } bool Add(int n) { return index_ < kSize ? (comp_[index_++] = n, true) : false; @@ -207,8 +210,9 @@ class DateParser : public AllStatic { static bool IsHour(int x) { return Between(x, 0, 23); } static bool IsHour12(int x) { return Between(x, 0, 12); } static bool IsSecond(int x) { return Between(x, 0, 59); } + static bool IsMillisecond(int x) { return Between(x, 0, 999); } - static const int kSize = 3; + static const int kSize = 4; int comp_[kSize]; int index_; int hour_offset_; diff --git a/test/mjsunit/date-parse.js b/test/mjsunit/date-parse.js index 4bbb2c6..23a6993 100644 --- a/test/mjsunit/date-parse.js +++ b/test/mjsunit/date-parse.js @@ -205,7 +205,6 @@ var testCasesPDT = [ 'Saturday, 01-Jan-00 01:00:00 PDT', '01 Jan 00 01:00 -0700']; - // Local time cases. var testCasesLocalTime = [ // Allow timezone ommision. @@ -233,6 +232,27 @@ var testCasesMisc = [ ['Saturday, 01-Jan-00 08:00 PM UT', 946756800000], ['01 Jan 00 08:00 PM +0000', 946756800000]]; +// Test different version of the ES5 date time string format. +var testCasesES5Misc = [ + ['2000-01-01T08:00:00.000Z', 946713600000], + ['2000-01-01T08:00:00Z', 946713600000], + ['2000-01-01T08:00Z', 946713600000], + ['2000-01T08:00:00.000Z', 946713600000], + ['2000T08:00:00.000Z', 946713600000], + ['2000T08:00Z', 946713600000], + ['2000-01T00:00:00.000-08:00', 946713600000], + ['2000-01T08:00:00.001Z', 946713600001], + ['2000-01T08:00:00.099Z', 946713600099], + ['2000-01T08:00:00.999Z', 946713600999], + ['2000-01T00:00:00.001-08:00', 946713600001]]; + +var testCasesES5MiscNegative = [ + '2000-01-01TZ', + '2000-01-01T60Z', + '2000-01-01T60:60Z', + '2000-01-0108:00Z', + '2000-01-01T08Z']; + // Run all the tests. testCasesUT.forEach(testDateParse); @@ -248,6 +268,12 @@ testCasesPDT.forEach(testDateParse); testCasesLocalTime.forEach(testDateParseLocalTime); testCasesMisc.forEach(testDateParseMisc); +// ES5 date time string format compliance. +testCasesES5Misc.forEach(testDateParseMisc); +testCasesES5MiscNegative.forEach(function (s) { + assertTrue(isNaN(Date.parse(s)), s + " is not NaN."); +}); + // Test that we can parse our own date format. // (Dates from 1970 to ~2070 with 150h steps.)