Line data Source code
1 : // Copyright 2011 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/dateparser.h"
6 :
7 : #include "src/char-predicates-inl.h"
8 : #include "src/objects-inl.h"
9 :
10 : namespace v8 {
11 : namespace internal {
12 :
13 96258 : bool DateParser::DayComposer::Write(FixedArray* output) {
14 96258 : if (index_ < 1) return false;
15 : // Day and month defaults to 1.
16 188626 : while (index_ < kSize) {
17 92442 : comp_[index_++] = 1;
18 : }
19 :
20 : int year = 0; // Default year is 0 (=> 2000) for KJS compatibility.
21 : int month = kNone;
22 : int day = kNone;
23 :
24 96184 : if (named_month_ == kNone) {
25 5675 : if (is_iso_date_ || (index_ == 3 && !IsDay(comp_[0]))) {
26 : // YMD
27 5031 : year = comp_[0];
28 5031 : month = comp_[1];
29 5031 : day = comp_[2];
30 : } else {
31 : // MD(Y)
32 86 : month = comp_[0];
33 86 : day = comp_[1];
34 86 : if (index_ == 3) year = comp_[2];
35 : }
36 : } else {
37 : month = named_month_;
38 91067 : if (index_ == 1) {
39 : // MD or DM
40 0 : day = comp_[0];
41 182134 : } else if (!IsDay(comp_[0])) {
42 : // YMD, MYD, or YDM
43 : year = comp_[0];
44 0 : day = comp_[1];
45 : } else {
46 : // DMY, MDY, or DYM
47 : day = comp_[0];
48 91067 : year = comp_[1];
49 : }
50 : }
51 :
52 96184 : if (!is_iso_date_) {
53 91625 : if (Between(year, 0, 49)) year += 2000;
54 90999 : else if (Between(year, 50, 99)) year += 1900;
55 : }
56 :
57 192326 : if (!Smi::IsValid(year) || !IsMonth(month) || !IsDay(day)) return false;
58 :
59 : output->set(YEAR, Smi::FromInt(year));
60 96142 : output->set(MONTH, Smi::FromInt(month - 1)); // 0-based
61 : output->set(DAY, Smi::FromInt(day));
62 96142 : return true;
63 : }
64 :
65 :
66 96142 : bool DateParser::TimeComposer::Write(FixedArray* output) {
67 : // All time slots default to 0
68 196721 : while (index_ < kSize) {
69 4437 : comp_[index_++] = 0;
70 : }
71 :
72 : int& hour = comp_[0];
73 : int& minute = comp_[1];
74 : int& second = comp_[2];
75 : int& millisecond = comp_[3];
76 :
77 96142 : if (hour_offset_ != kNone) {
78 1536 : if (!IsHour12(hour)) return false;
79 768 : hour %= 12;
80 768 : hour += hour_offset_;
81 : }
82 :
83 480485 : if (!IsHour(hour) || !IsMinute(minute) ||
84 384343 : !IsSecond(second) || !IsMillisecond(millisecond)) {
85 : // A 24th hour is allowed if minutes, seconds, and milliseconds are 0
86 75 : if (hour != 24 || minute != 0 || second != 0 || millisecond != 0) {
87 : return false;
88 : }
89 : }
90 :
91 : output->set(HOUR, Smi::FromInt(hour));
92 96127 : output->set(MINUTE, Smi::FromInt(minute));
93 96127 : output->set(SECOND, Smi::FromInt(second));
94 96127 : output->set(MILLISECOND, Smi::FromInt(millisecond));
95 96127 : return true;
96 : }
97 :
98 :
99 96127 : bool DateParser::TimeZoneComposer::Write(FixedArray* output) {
100 96127 : if (sign_ != kNone) {
101 95306 : if (hour_ == kNone) hour_ = 0;
102 95306 : if (minute_ == kNone) minute_ = 0;
103 : // Avoid signed integer overflow (undefined behavior) by doing unsigned
104 : // arithmetic.
105 95306 : unsigned total_seconds_unsigned = hour_ * 3600U + minute_ * 60U;
106 95306 : if (total_seconds_unsigned > Smi::kMaxValue) return false;
107 : int total_seconds = static_cast<int>(total_seconds_unsigned);
108 95306 : if (sign_ < 0) {
109 90086 : total_seconds = -total_seconds;
110 : }
111 : DCHECK(Smi::IsValid(total_seconds));
112 : output->set(UTC_OFFSET, Smi::FromInt(total_seconds));
113 : } else {
114 821 : output->set_null(UTC_OFFSET);
115 : }
116 : return true;
117 : }
118 :
119 : const 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},
137 : {'z', '\0', '\0', DateParser::TIME_ZONE_NAME, 0},
138 : {'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},
147 : {'t', '\0', '\0', DateParser::TIME_SEPARATOR, 0},
148 : {'\0', '\0', '\0', DateParser::INVALID, 0},
149 : };
150 :
151 :
152 : // We could use perfect hashing here, but this is not a bottleneck.
153 278762 : int DateParser::KeywordTable::Lookup(const uint32_t* pre, int len) {
154 : int i;
155 4906650 : for (i = 0; array[i][kTypeOffset] != INVALID; i++) {
156 : int j = 0;
157 10913886 : while (j < kPrefixLength &&
158 5362650 : pre[j] == static_cast<uint32_t>(array[i][j])) {
159 734762 : 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 4816474 : if (j == kPrefixLength &&
164 189 : (len <= kPrefixLength || array[i][kTypeOffset] == MONTH_NAME)) {
165 : return i;
166 : }
167 : }
168 : return i;
169 : }
170 :
171 :
172 3876 : int 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 3876 : int number = token.number();
178 3876 : int length = token.length();
179 3876 : if (length < 3) {
180 : // Less than three digits. Multiply to put most significant digit
181 : // in hundreds position.
182 75 : if (length == 1) {
183 60 : number *= 100;
184 15 : } else if (length == 2) {
185 15 : number *= 10;
186 : }
187 3801 : } else if (length > 3) {
188 30 : 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 105 : do {
193 : DCHECK(factor <= 100000000); // factor won't overflow.
194 105 : factor *= 10;
195 105 : length--;
196 : } while (length > 3);
197 30 : number /= factor;
198 : }
199 3876 : return number;
200 : }
201 :
202 :
203 : } // namespace internal
204 : } // namespace v8
|