blob: d096a7ec9fc58ce24c970075b09b2409357fb972 [file] [log] [blame]
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Steve Blocka7e24c12009-10-30 11:49:00 +00004
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#include "src/dateparser.h"
Steve Blocka7e24c12009-10-30 11:49:00 +00006
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007#include "src/char-predicates-inl.h"
8#include "src/objects-inl.h"
9
Steve Blocka7e24c12009-10-30 11:49:00 +000010namespace v8 {
11namespace internal {
12
13bool DateParser::DayComposer::Write(FixedArray* output) {
Kristian Monsen25f61362010-05-21 11:50:48 +010014 if (index_ < 1) return false;
Steve Block6ded16b2010-05-10 14:33:55 +010015 // Day and month defaults to 1.
16 while (index_ < kSize) {
Kristian Monsen25f61362010-05-21 11:50:48 +010017 comp_[index_++] = 1;
Steve Block6ded16b2010-05-10 14:33:55 +010018 }
19
Steve Blocka7e24c12009-10-30 11:49:00 +000020 int year = 0; // Default year is 0 (=> 2000) for KJS compatibility.
21 int month = kNone;
22 int day = kNone;
23
24 if (named_month_ == kNone) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000025 if (is_iso_date_ || (index_ == 3 && !IsDay(comp_[0]))) {
Steve Blocka7e24c12009-10-30 11:49:00 +000026 // YMD
27 year = comp_[0];
28 month = comp_[1];
29 day = comp_[2];
30 } else {
31 // MD(Y)
32 month = comp_[0];
33 day = comp_[1];
34 if (index_ == 3) year = comp_[2];
35 }
36 } else {
37 month = named_month_;
Steve Blocka7e24c12009-10-30 11:49:00 +000038 if (index_ == 1) {
39 // MD or DM
40 day = comp_[0];
41 } else if (!IsDay(comp_[0])) {
42 // YMD, MYD, or YDM
43 year = comp_[0];
44 day = comp_[1];
45 } else {
46 // DMY, MDY, or DYM
47 day = comp_[0];
48 year = comp_[1];
49 }
50 }
51
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000052 if (!is_iso_date_) {
53 if (Between(year, 0, 49)) year += 2000;
54 else if (Between(year, 50, 99)) year += 1900;
55 }
Steve Blocka7e24c12009-10-30 11:49:00 +000056
57 if (!Smi::IsValid(year) || !IsMonth(month) || !IsDay(day)) return false;
58
Leon Clarke4515c472010-02-03 11:58:03 +000059 output->set(YEAR, Smi::FromInt(year));
60 output->set(MONTH, Smi::FromInt(month - 1)); // 0-based
61 output->set(DAY, Smi::FromInt(day));
Steve Blocka7e24c12009-10-30 11:49:00 +000062 return true;
63}
64
65
66bool DateParser::TimeComposer::Write(FixedArray* output) {
67 // All time slots default to 0
68 while (index_ < kSize) {
69 comp_[index_++] = 0;
70 }
71
72 int& hour = comp_[0];
73 int& minute = comp_[1];
74 int& second = comp_[2];
Steve Block6ded16b2010-05-10 14:33:55 +010075 int& millisecond = comp_[3];
Steve Blocka7e24c12009-10-30 11:49:00 +000076
77 if (hour_offset_ != kNone) {
78 if (!IsHour12(hour)) return false;
79 hour %= 12;
80 hour += hour_offset_;
81 }
82
Steve Block6ded16b2010-05-10 14:33:55 +010083 if (!IsHour(hour) || !IsMinute(minute) ||
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000084 !IsSecond(second) || !IsMillisecond(millisecond)) {
85 // A 24th hour is allowed if minutes, seconds, and milliseconds are 0
86 if (hour != 24 || minute != 0 || second != 0 || millisecond != 0) {
87 return false;
88 }
89 }
Steve Blocka7e24c12009-10-30 11:49:00 +000090
Leon Clarke4515c472010-02-03 11:58:03 +000091 output->set(HOUR, Smi::FromInt(hour));
92 output->set(MINUTE, Smi::FromInt(minute));
93 output->set(SECOND, Smi::FromInt(second));
Steve Block6ded16b2010-05-10 14:33:55 +010094 output->set(MILLISECOND, Smi::FromInt(millisecond));
Steve Blocka7e24c12009-10-30 11:49:00 +000095 return true;
96}
97
Ben Murdochb8a8cc12014-11-26 15:28:44 +000098
Steve Blocka7e24c12009-10-30 11:49:00 +000099bool DateParser::TimeZoneComposer::Write(FixedArray* output) {
100 if (sign_ != kNone) {
101 if (hour_ == kNone) hour_ = 0;
102 if (minute_ == kNone) minute_ = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000103 // Avoid signed integer overflow (undefined behavior) by doing unsigned
104 // arithmetic.
105 unsigned total_seconds_unsigned = hour_ * 3600U + minute_ * 60U;
106 if (total_seconds_unsigned > Smi::kMaxValue) return false;
107 int total_seconds = static_cast<int>(total_seconds_unsigned);
108 if (sign_ < 0) {
109 total_seconds = -total_seconds;
110 }
111 DCHECK(Smi::IsValid(total_seconds));
Leon Clarke4515c472010-02-03 11:58:03 +0000112 output->set(UTC_OFFSET, Smi::FromInt(total_seconds));
Steve Blocka7e24c12009-10-30 11:49:00 +0000113 } else {
Leon Clarke4515c472010-02-03 11:58:03 +0000114 output->set_null(UTC_OFFSET);
Steve Blocka7e24c12009-10-30 11:49:00 +0000115 }
116 return true;
117}
118
119const int8_t DateParser::KeywordTable::
120 array[][DateParser::KeywordTable::kEntrySize] = {
121 {'j', 'a', 'n', DateParser::MONTH_NAME, 1},
122 {'f', 'e', 'b', DateParser::MONTH_NAME, 2},
123 {'m', 'a', 'r', DateParser::MONTH_NAME, 3},
124 {'a', 'p', 'r', DateParser::MONTH_NAME, 4},
125 {'m', 'a', 'y', DateParser::MONTH_NAME, 5},
126 {'j', 'u', 'n', DateParser::MONTH_NAME, 6},
127 {'j', 'u', 'l', DateParser::MONTH_NAME, 7},
128 {'a', 'u', 'g', DateParser::MONTH_NAME, 8},
129 {'s', 'e', 'p', DateParser::MONTH_NAME, 9},
130 {'o', 'c', 't', DateParser::MONTH_NAME, 10},
131 {'n', 'o', 'v', DateParser::MONTH_NAME, 11},
132 {'d', 'e', 'c', DateParser::MONTH_NAME, 12},
133 {'a', 'm', '\0', DateParser::AM_PM, 0},
134 {'p', 'm', '\0', DateParser::AM_PM, 12},
135 {'u', 't', '\0', DateParser::TIME_ZONE_NAME, 0},
136 {'u', 't', 'c', DateParser::TIME_ZONE_NAME, 0},
Steve Block6ded16b2010-05-10 14:33:55 +0100137 {'z', '\0', '\0', DateParser::TIME_ZONE_NAME, 0},
Steve Blocka7e24c12009-10-30 11:49:00 +0000138 {'g', 'm', 't', DateParser::TIME_ZONE_NAME, 0},
139 {'c', 'd', 't', DateParser::TIME_ZONE_NAME, -5},
140 {'c', 's', 't', DateParser::TIME_ZONE_NAME, -6},
141 {'e', 'd', 't', DateParser::TIME_ZONE_NAME, -4},
142 {'e', 's', 't', DateParser::TIME_ZONE_NAME, -5},
143 {'m', 'd', 't', DateParser::TIME_ZONE_NAME, -6},
144 {'m', 's', 't', DateParser::TIME_ZONE_NAME, -7},
145 {'p', 'd', 't', DateParser::TIME_ZONE_NAME, -7},
146 {'p', 's', 't', DateParser::TIME_ZONE_NAME, -8},
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000147 {'t', '\0', '\0', DateParser::TIME_SEPARATOR, 0},
Steve Blocka7e24c12009-10-30 11:49:00 +0000148 {'\0', '\0', '\0', DateParser::INVALID, 0},
149};
150
151
152// We could use perfect hashing here, but this is not a bottleneck.
153int DateParser::KeywordTable::Lookup(const uint32_t* pre, int len) {
154 int i;
155 for (i = 0; array[i][kTypeOffset] != INVALID; i++) {
156 int j = 0;
157 while (j < kPrefixLength &&
158 pre[j] == static_cast<uint32_t>(array[i][j])) {
159 j++;
160 }
161 // Check if we have a match and the length is legal.
162 // Word longer than keyword is only allowed for month names.
163 if (j == kPrefixLength &&
164 (len <= kPrefixLength || array[i][kTypeOffset] == MONTH_NAME)) {
165 return i;
166 }
167 }
168 return i;
169}
170
171
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000172int DateParser::ReadMilliseconds(DateToken token) {
173 // Read first three significant digits of the original numeral,
174 // as inferred from the value and the number of digits.
175 // I.e., use the number of digits to see if there were
176 // leading zeros.
177 int number = token.number();
178 int length = token.length();
179 if (length < 3) {
180 // Less than three digits. Multiply to put most significant digit
181 // in hundreds position.
182 if (length == 1) {
183 number *= 100;
184 } else if (length == 2) {
185 number *= 10;
186 }
187 } else if (length > 3) {
188 if (length > kMaxSignificantDigits) length = kMaxSignificantDigits;
189 // More than three digits. Divide by 10^(length - 3) to get three
190 // most significant digits.
191 int factor = 1;
192 do {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000193 DCHECK(factor <= 100000000); // factor won't overflow.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000194 factor *= 10;
195 length--;
196 } while (length > 3);
197 number /= factor;
198 }
199 return number;
200}
201
202
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000203} // namespace internal
204} // namespace v8