Commit 6ceb02e6 authored by ricow@chromium.org's avatar ricow@chromium.org

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
parent 8e56358e
......@@ -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);
}
}
......
......@@ -54,16 +54,25 @@ bool DateParser::Parse(Vector<Char> 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').
......
......@@ -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},
......
......@@ -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 <typename Char>
static bool Parse(Vector<Char> 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_;
......
......@@ -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.)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment