OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2009 Google Inc. All rights reserved. | |
3 * | |
4 * Redistribution and use in source and binary forms, with or without | |
5 * modification, are permitted provided that the following conditions are | |
6 * met: | |
7 * | |
8 * * Redistributions of source code must retain the above copyright | |
9 * notice, this list of conditions and the following disclaimer. | |
10 * * Redistributions in binary form must reproduce the above | |
11 * copyright notice, this list of conditions and the following disclaimer | |
12 * in the documentation and/or other materials provided with the | |
13 * distribution. | |
14 * * Neither the name of Google Inc. nor the names of its | |
15 * contributors may be used to endorse or promote products derived from | |
16 * this software without specific prior written permission. | |
17 * | |
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 */ | |
30 | |
31 #include "config.h" | |
32 #include "core/platform/DateComponents.h" | |
33 | |
34 #include <limits.h> | |
35 #include "wtf/ASCIICType.h" | |
36 #include "wtf/DateMath.h" | |
37 #include "wtf/MathExtras.h" | |
38 #include "wtf/text/WTFString.h" | |
39 | |
40 using namespace std; | |
41 | |
42 namespace WebCore { | |
43 | |
44 // HTML5 specification defines minimum week of year is one. | |
45 const int DateComponents::minimumWeekNumber = 1; | |
46 | |
47 // HTML5 specification defines maximum week of year is 53. | |
48 const int DateComponents::maximumWeekNumber = 53; | |
49 | |
50 static const int maximumMonthInMaximumYear = 8; // This is September, since mont
hs are 0 based. | |
51 static const int maximumDayInMaximumMonth = 13; | |
52 static const int maximumWeekInMaximumYear = 37; // The week of 275760-09-13 | |
53 | |
54 static const int daysInMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30,
31}; | |
55 | |
56 static bool isLeapYear(int year) | |
57 { | |
58 if (year % 4) | |
59 return false; | |
60 if (!(year % 400)) | |
61 return true; | |
62 if (!(year % 100)) | |
63 return false; | |
64 return true; | |
65 } | |
66 | |
67 // 'month' is 0-based. | |
68 static int maxDayOfMonth(int year, int month) | |
69 { | |
70 if (month != 1) // February? | |
71 return daysInMonth[month]; | |
72 return isLeapYear(year) ? 29 : 28; | |
73 } | |
74 | |
75 // 'month' is 0-based. | |
76 static int dayOfWeek(int year, int month, int day) | |
77 { | |
78 int shiftedMonth = month + 2; | |
79 // 2:January, 3:Feburuary, 4:March, ... | |
80 | |
81 // Zeller's congruence | |
82 if (shiftedMonth <= 3) { | |
83 shiftedMonth += 12; | |
84 year--; | |
85 } | |
86 // 4:March, ..., 14:January, 15:February | |
87 | |
88 int highYear = year / 100; | |
89 int lowYear = year % 100; | |
90 // We add 6 to make the result Sunday-origin. | |
91 int result = (day + 13 * shiftedMonth / 5 + lowYear + lowYear / 4 + highYear
/ 4 + 5 * highYear + 6) % 7; | |
92 return result; | |
93 } | |
94 | |
95 int DateComponents::maxWeekNumberInYear() const | |
96 { | |
97 int day = dayOfWeek(m_year, 0, 1); // January 1. | |
98 return day == Thursday || (day == Wednesday && isLeapYear(m_year)) ? maximum
WeekNumber : maximumWeekNumber - 1; | |
99 } | |
100 | |
101 static unsigned countDigits(const String& src, unsigned start) | |
102 { | |
103 unsigned index = start; | |
104 for (; index < src.length(); ++index) { | |
105 if (!isASCIIDigit(src[index])) | |
106 break; | |
107 } | |
108 return index - start; | |
109 } | |
110 | |
111 // Very strict integer parser. Do not allow leading or trailing whitespace unlik
e charactersToIntStrict(). | |
112 static bool toInt(const String& src, unsigned parseStart, unsigned parseLength,
int& out) | |
113 { | |
114 if (parseStart + parseLength > src.length() || parseLength <= 0) | |
115 return false; | |
116 int value = 0; | |
117 unsigned current = parseStart; | |
118 unsigned end = current + parseLength; | |
119 | |
120 // We don't need to handle negative numbers for ISO 8601. | |
121 for (; current < end; ++current) { | |
122 if (!isASCIIDigit(src[current])) | |
123 return false; | |
124 int digit = src[current] - '0'; | |
125 if (value > (INT_MAX - digit) / 10) // Check for overflow. | |
126 return false; | |
127 value = value * 10 + digit; | |
128 } | |
129 out = value; | |
130 return true; | |
131 } | |
132 | |
133 bool DateComponents::parseYear(const String& src, unsigned start, unsigned& end) | |
134 { | |
135 unsigned digitsLength = countDigits(src, start); | |
136 // Needs at least 4 digits according to the standard. | |
137 if (digitsLength < 4) | |
138 return false; | |
139 int year; | |
140 if (!toInt(src, start, digitsLength, year)) | |
141 return false; | |
142 if (year < minimumYear() || year > maximumYear()) | |
143 return false; | |
144 m_year = year; | |
145 end = start + digitsLength; | |
146 return true; | |
147 } | |
148 | |
149 static bool withinHTMLDateLimits(int year, int month) | |
150 { | |
151 if (year < DateComponents::minimumYear()) | |
152 return false; | |
153 if (year < DateComponents::maximumYear()) | |
154 return true; | |
155 return month <= maximumMonthInMaximumYear; | |
156 } | |
157 | |
158 static bool withinHTMLDateLimits(int year, int month, int monthDay) | |
159 { | |
160 if (year < DateComponents::minimumYear()) | |
161 return false; | |
162 if (year < DateComponents::maximumYear()) | |
163 return true; | |
164 if (month < maximumMonthInMaximumYear) | |
165 return true; | |
166 return monthDay <= maximumDayInMaximumMonth; | |
167 } | |
168 | |
169 static bool withinHTMLDateLimits(int year, int month, int monthDay, int hour, in
t minute, int second, int millisecond) | |
170 { | |
171 if (year < DateComponents::minimumYear()) | |
172 return false; | |
173 if (year < DateComponents::maximumYear()) | |
174 return true; | |
175 if (month < maximumMonthInMaximumYear) | |
176 return true; | |
177 if (monthDay < maximumDayInMaximumMonth) | |
178 return true; | |
179 if (monthDay > maximumDayInMaximumMonth) | |
180 return false; | |
181 // (year, month, monthDay) = (maximumYear, maximumMonthInMaximumYear, maximu
mDayInMaximumMonth) | |
182 return !hour && !minute && !second && !millisecond; | |
183 } | |
184 | |
185 bool DateComponents::addDay(int dayDiff) | |
186 { | |
187 ASSERT(m_monthDay); | |
188 | |
189 int day = m_monthDay + dayDiff; | |
190 if (day > maxDayOfMonth(m_year, m_month)) { | |
191 day = m_monthDay; | |
192 int year = m_year; | |
193 int month = m_month; | |
194 int maxDay = maxDayOfMonth(year, month); | |
195 for (; dayDiff > 0; --dayDiff) { | |
196 ++day; | |
197 if (day > maxDay) { | |
198 day = 1; | |
199 ++month; | |
200 if (month >= 12) { // month is 0-origin. | |
201 month = 0; | |
202 ++year; | |
203 } | |
204 maxDay = maxDayOfMonth(year, month); | |
205 } | |
206 } | |
207 if (!withinHTMLDateLimits(year, month, day)) | |
208 return false; | |
209 m_year = year; | |
210 m_month = month; | |
211 } else if (day < 1) { | |
212 int month = m_month; | |
213 int year = m_year; | |
214 day = m_monthDay; | |
215 for (; dayDiff < 0; ++dayDiff) { | |
216 --day; | |
217 if (day < 1) { | |
218 --month; | |
219 if (month < 0) { | |
220 month = 11; | |
221 --year; | |
222 } | |
223 day = maxDayOfMonth(year, month); | |
224 } | |
225 } | |
226 if (!withinHTMLDateLimits(year, month, day)) | |
227 return false; | |
228 m_year = year; | |
229 m_month = month; | |
230 } else { | |
231 if (!withinHTMLDateLimits(m_year, m_month, day)) | |
232 return false; | |
233 } | |
234 m_monthDay = day; | |
235 return true; | |
236 } | |
237 | |
238 bool DateComponents::addMinute(int minute) | |
239 { | |
240 // This function is used to adjust timezone offset. So m_year, m_month, | |
241 // m_monthDay have values between the lower and higher limits. | |
242 ASSERT(withinHTMLDateLimits(m_year, m_month, m_monthDay)); | |
243 | |
244 int carry; | |
245 // minute can be negative or greater than 59. | |
246 minute += m_minute; | |
247 if (minute > 59) { | |
248 carry = minute / 60; | |
249 minute = minute % 60; | |
250 } else if (minute < 0) { | |
251 carry = (59 - minute) / 60; | |
252 minute += carry * 60; | |
253 carry = -carry; | |
254 ASSERT(minute >= 0 && minute <= 59); | |
255 } else { | |
256 if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, m_hour, minute, m
_second, m_millisecond)) | |
257 return false; | |
258 m_minute = minute; | |
259 return true; | |
260 } | |
261 | |
262 int hour = m_hour + carry; | |
263 if (hour > 23) { | |
264 carry = hour / 24; | |
265 hour = hour % 24; | |
266 } else if (hour < 0) { | |
267 carry = (23 - hour) / 24; | |
268 hour += carry * 24; | |
269 carry = -carry; | |
270 ASSERT(hour >= 0 && hour <= 23); | |
271 } else { | |
272 if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, hour, minute, m_s
econd, m_millisecond)) | |
273 return false; | |
274 m_minute = minute; | |
275 m_hour = hour; | |
276 return true; | |
277 } | |
278 if (!addDay(carry)) | |
279 return false; | |
280 if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, hour, minute, m_secon
d, m_millisecond)) | |
281 return false; | |
282 m_minute = minute; | |
283 m_hour = hour; | |
284 return true; | |
285 } | |
286 | |
287 // Parses a timezone part, and adjust year, month, monthDay, hour, minute, secon
d, millisecond. | |
288 bool DateComponents::parseTimeZone(const String& src, unsigned start, unsigned&
end) | |
289 { | |
290 if (start >= src.length()) | |
291 return false; | |
292 unsigned index = start; | |
293 if (src[index] == 'Z') { | |
294 end = index + 1; | |
295 return true; | |
296 } | |
297 | |
298 bool minus; | |
299 if (src[index] == '+') | |
300 minus = false; | |
301 else if (src[index] == '-') | |
302 minus = true; | |
303 else | |
304 return false; | |
305 ++index; | |
306 | |
307 int hour; | |
308 int minute; | |
309 if (!toInt(src, index, 2, hour) || hour < 0 || hour > 23) | |
310 return false; | |
311 index += 2; | |
312 | |
313 if (index >= src.length() || src[index] != ':') | |
314 return false; | |
315 ++index; | |
316 | |
317 if (!toInt(src, index, 2, minute) || minute < 0 || minute > 59) | |
318 return false; | |
319 index += 2; | |
320 | |
321 if (minus) { | |
322 hour = -hour; | |
323 minute = -minute; | |
324 } | |
325 | |
326 // Subtract the timezone offset. | |
327 if (!addMinute(-(hour * 60 + minute))) | |
328 return false; | |
329 end = index; | |
330 return true; | |
331 } | |
332 | |
333 bool DateComponents::parseMonth(const String& src, unsigned start, unsigned& end
) | |
334 { | |
335 unsigned index; | |
336 if (!parseYear(src, start, index)) | |
337 return false; | |
338 if (index >= src.length() || src[index] != '-') | |
339 return false; | |
340 ++index; | |
341 | |
342 int month; | |
343 if (!toInt(src, index, 2, month) || month < 1 || month > 12) | |
344 return false; | |
345 --month; | |
346 if (!withinHTMLDateLimits(m_year, month)) | |
347 return false; | |
348 m_month = month; | |
349 end = index + 2; | |
350 m_type = Month; | |
351 return true; | |
352 } | |
353 | |
354 bool DateComponents::parseDate(const String& src, unsigned start, unsigned& end) | |
355 { | |
356 unsigned index; | |
357 if (!parseMonth(src, start, index)) | |
358 return false; | |
359 // '-' and 2-digits are needed. | |
360 if (index + 2 >= src.length()) | |
361 return false; | |
362 if (src[index] != '-') | |
363 return false; | |
364 ++index; | |
365 | |
366 int day; | |
367 if (!toInt(src, index, 2, day) || day < 1 || day > maxDayOfMonth(m_year, m_m
onth)) | |
368 return false; | |
369 if (!withinHTMLDateLimits(m_year, m_month, day)) | |
370 return false; | |
371 m_monthDay = day; | |
372 end = index + 2; | |
373 m_type = Date; | |
374 return true; | |
375 } | |
376 | |
377 bool DateComponents::parseWeek(const String& src, unsigned start, unsigned& end) | |
378 { | |
379 unsigned index; | |
380 if (!parseYear(src, start, index)) | |
381 return false; | |
382 | |
383 // 4 characters ('-' 'W' digit digit) are needed. | |
384 if (index + 3 >= src.length()) | |
385 return false; | |
386 if (src[index] != '-') | |
387 return false; | |
388 ++index; | |
389 if (src[index] != 'W') | |
390 return false; | |
391 ++index; | |
392 | |
393 int week; | |
394 if (!toInt(src, index, 2, week) || week < minimumWeekNumber || week > maxWee
kNumberInYear()) | |
395 return false; | |
396 if (m_year == maximumYear() && week > maximumWeekInMaximumYear) | |
397 return false; | |
398 m_week = week; | |
399 end = index + 2; | |
400 m_type = Week; | |
401 return true; | |
402 } | |
403 | |
404 bool DateComponents::parseTime(const String& src, unsigned start, unsigned& end) | |
405 { | |
406 int hour; | |
407 if (!toInt(src, start, 2, hour) || hour < 0 || hour > 23) | |
408 return false; | |
409 unsigned index = start + 2; | |
410 if (index >= src.length()) | |
411 return false; | |
412 if (src[index] != ':') | |
413 return false; | |
414 ++index; | |
415 | |
416 int minute; | |
417 if (!toInt(src, index, 2, minute) || minute < 0 || minute > 59) | |
418 return false; | |
419 index += 2; | |
420 | |
421 int second = 0; | |
422 int millisecond = 0; | |
423 // Optional second part. | |
424 // Do not return with false because the part is optional. | |
425 if (index + 2 < src.length() && src[index] == ':') { | |
426 if (toInt(src, index + 1, 2, second) && second >= 0 && second <= 59) { | |
427 index += 3; | |
428 | |
429 // Optional fractional second part. | |
430 if (index < src.length() && src[index] == '.') { | |
431 unsigned digitsLength = countDigits(src, index + 1); | |
432 if (digitsLength > 0) { | |
433 ++index; | |
434 bool ok; | |
435 if (digitsLength == 1) { | |
436 ok = toInt(src, index, 1, millisecond); | |
437 millisecond *= 100; | |
438 } else if (digitsLength == 2) { | |
439 ok = toInt(src, index, 2, millisecond); | |
440 millisecond *= 10; | |
441 } else { // digitsLength >= 3 | |
442 ok = toInt(src, index, 3, millisecond); | |
443 } | |
444 ASSERT_UNUSED(ok, ok); | |
445 index += digitsLength; | |
446 } | |
447 } | |
448 } | |
449 } | |
450 m_hour = hour; | |
451 m_minute = minute; | |
452 m_second = second; | |
453 m_millisecond = millisecond; | |
454 end = index; | |
455 m_type = Time; | |
456 return true; | |
457 } | |
458 | |
459 bool DateComponents::parseDateTimeLocal(const String& src, unsigned start, unsig
ned& end) | |
460 { | |
461 unsigned index; | |
462 if (!parseDate(src, start, index)) | |
463 return false; | |
464 if (index >= src.length()) | |
465 return false; | |
466 if (src[index] != 'T') | |
467 return false; | |
468 ++index; | |
469 if (!parseTime(src, index, end)) | |
470 return false; | |
471 if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, m_hour, m_minute, m_s
econd, m_millisecond)) | |
472 return false; | |
473 m_type = DateTimeLocal; | |
474 return true; | |
475 } | |
476 | |
477 bool DateComponents::parseDateTime(const String& src, unsigned start, unsigned&
end) | |
478 { | |
479 unsigned index; | |
480 if (!parseDate(src, start, index)) | |
481 return false; | |
482 if (index >= src.length()) | |
483 return false; | |
484 if (src[index] != 'T') | |
485 return false; | |
486 ++index; | |
487 if (!parseTime(src, index, index)) | |
488 return false; | |
489 if (!parseTimeZone(src, index, end)) | |
490 return false; | |
491 if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, m_hour, m_minute, m_s
econd, m_millisecond)) | |
492 return false; | |
493 m_type = DateTime; | |
494 return true; | |
495 } | |
496 | |
497 static inline double positiveFmod(double value, double divider) | |
498 { | |
499 double remainder = fmod(value, divider); | |
500 return remainder < 0 ? remainder + divider : remainder; | |
501 } | |
502 | |
503 void DateComponents::setMillisecondsSinceMidnightInternal(double msInDay) | |
504 { | |
505 ASSERT(msInDay >= 0 && msInDay < msPerDay); | |
506 m_millisecond = static_cast<int>(fmod(msInDay, msPerSecond)); | |
507 double value = floor(msInDay / msPerSecond); | |
508 m_second = static_cast<int>(fmod(value, secondsPerMinute)); | |
509 value = floor(value / secondsPerMinute); | |
510 m_minute = static_cast<int>(fmod(value, minutesPerHour)); | |
511 m_hour = static_cast<int>(value / minutesPerHour); | |
512 } | |
513 | |
514 bool DateComponents::setMillisecondsSinceEpochForDateInternal(double ms) | |
515 { | |
516 m_year = msToYear(ms); | |
517 int yearDay = dayInYear(ms, m_year); | |
518 m_month = monthFromDayInYear(yearDay, isLeapYear(m_year)); | |
519 m_monthDay = dayInMonthFromDayInYear(yearDay, isLeapYear(m_year)); | |
520 return true; | |
521 } | |
522 | |
523 bool DateComponents::setMillisecondsSinceEpochForDate(double ms) | |
524 { | |
525 m_type = Invalid; | |
526 if (!std::isfinite(ms)) | |
527 return false; | |
528 if (!setMillisecondsSinceEpochForDateInternal(round(ms))) | |
529 return false; | |
530 if (!withinHTMLDateLimits(m_year, m_month, m_monthDay)) | |
531 return false; | |
532 m_type = Date; | |
533 return true; | |
534 } | |
535 | |
536 bool DateComponents::setMillisecondsSinceEpochForDateTime(double ms) | |
537 { | |
538 m_type = Invalid; | |
539 if (!std::isfinite(ms)) | |
540 return false; | |
541 ms = round(ms); | |
542 setMillisecondsSinceMidnightInternal(positiveFmod(ms, msPerDay)); | |
543 if (!setMillisecondsSinceEpochForDateInternal(ms)) | |
544 return false; | |
545 if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, m_hour, m_minute, m_s
econd, m_millisecond)) | |
546 return false; | |
547 m_type = DateTime; | |
548 return true; | |
549 } | |
550 | |
551 bool DateComponents::setMillisecondsSinceEpochForDateTimeLocal(double ms) | |
552 { | |
553 // Internal representation of DateTimeLocal is the same as DateTime except m
_type. | |
554 if (!setMillisecondsSinceEpochForDateTime(ms)) | |
555 return false; | |
556 m_type = DateTimeLocal; | |
557 return true; | |
558 } | |
559 | |
560 bool DateComponents::setMillisecondsSinceEpochForMonth(double ms) | |
561 { | |
562 m_type = Invalid; | |
563 if (!std::isfinite(ms)) | |
564 return false; | |
565 if (!setMillisecondsSinceEpochForDateInternal(round(ms))) | |
566 return false; | |
567 if (!withinHTMLDateLimits(m_year, m_month)) | |
568 return false; | |
569 m_type = Month; | |
570 return true; | |
571 } | |
572 | |
573 bool DateComponents::setMillisecondsSinceMidnight(double ms) | |
574 { | |
575 m_type = Invalid; | |
576 if (!std::isfinite(ms)) | |
577 return false; | |
578 setMillisecondsSinceMidnightInternal(positiveFmod(round(ms), msPerDay)); | |
579 m_type = Time; | |
580 return true; | |
581 } | |
582 | |
583 bool DateComponents::setMonthsSinceEpoch(double months) | |
584 { | |
585 if (!std::isfinite(months)) | |
586 return false; | |
587 months = round(months); | |
588 double doubleMonth = positiveFmod(months, 12); | |
589 double doubleYear = 1970 + (months - doubleMonth) / 12; | |
590 if (doubleYear < minimumYear() || maximumYear() < doubleYear) | |
591 return false; | |
592 int year = static_cast<int>(doubleYear); | |
593 int month = static_cast<int>(doubleMonth); | |
594 if (!withinHTMLDateLimits(year, month)) | |
595 return false; | |
596 m_year = year; | |
597 m_month = month; | |
598 m_type = Month; | |
599 return true; | |
600 } | |
601 | |
602 // Offset from January 1st to Monday of the ISO 8601's first week. | |
603 // ex. If January 1st is Friday, such Monday is 3 days later. Returns 3. | |
604 static int offsetTo1stWeekStart(int year) | |
605 { | |
606 int offsetTo1stWeekStart = 1 - dayOfWeek(year, 0, 1); | |
607 if (offsetTo1stWeekStart <= -4) | |
608 offsetTo1stWeekStart += 7; | |
609 return offsetTo1stWeekStart; | |
610 } | |
611 | |
612 bool DateComponents::setMillisecondsSinceEpochForWeek(double ms) | |
613 { | |
614 m_type = Invalid; | |
615 if (!std::isfinite(ms)) | |
616 return false; | |
617 ms = round(ms); | |
618 | |
619 m_year = msToYear(ms); | |
620 if (m_year < minimumYear() || m_year > maximumYear()) | |
621 return false; | |
622 | |
623 int yearDay = dayInYear(ms, m_year); | |
624 int offset = offsetTo1stWeekStart(m_year); | |
625 if (yearDay < offset) { | |
626 // The day belongs to the last week of the previous year. | |
627 m_year--; | |
628 if (m_year <= minimumYear()) | |
629 return false; | |
630 m_week = maxWeekNumberInYear(); | |
631 } else { | |
632 m_week = ((yearDay - offset) / 7) + 1; | |
633 if (m_week > maxWeekNumberInYear()) { | |
634 m_year++; | |
635 m_week = 1; | |
636 } | |
637 if (m_year > maximumYear() || (m_year == maximumYear() && m_week > maxim
umWeekInMaximumYear)) | |
638 return false; | |
639 } | |
640 m_type = Week; | |
641 return true; | |
642 } | |
643 | |
644 double DateComponents::millisecondsSinceEpochForTime() const | |
645 { | |
646 ASSERT(m_type == Time || m_type == DateTime || m_type == DateTimeLocal); | |
647 return ((m_hour * minutesPerHour + m_minute) * secondsPerMinute + m_second)
* msPerSecond + m_millisecond; | |
648 } | |
649 | |
650 double DateComponents::millisecondsSinceEpoch() const | |
651 { | |
652 switch (m_type) { | |
653 case Date: | |
654 return dateToDaysFrom1970(m_year, m_month, m_monthDay) * msPerDay; | |
655 case DateTime: | |
656 case DateTimeLocal: | |
657 return dateToDaysFrom1970(m_year, m_month, m_monthDay) * msPerDay + mill
isecondsSinceEpochForTime(); | |
658 case Month: | |
659 return dateToDaysFrom1970(m_year, m_month, 1) * msPerDay; | |
660 case Time: | |
661 return millisecondsSinceEpochForTime(); | |
662 case Week: | |
663 return (dateToDaysFrom1970(m_year, 0, 1) + offsetTo1stWeekStart(m_year)
+ (m_week - 1) * 7) * msPerDay; | |
664 case Invalid: | |
665 break; | |
666 } | |
667 ASSERT_NOT_REACHED(); | |
668 return invalidMilliseconds(); | |
669 } | |
670 | |
671 double DateComponents::monthsSinceEpoch() const | |
672 { | |
673 ASSERT(m_type == Month); | |
674 return (m_year - 1970) * 12 + m_month; | |
675 } | |
676 | |
677 String DateComponents::toStringForTime(SecondFormat format) const | |
678 { | |
679 ASSERT(m_type == DateTime || m_type == DateTimeLocal || m_type == Time); | |
680 SecondFormat effectiveFormat = format; | |
681 if (m_millisecond) | |
682 effectiveFormat = Millisecond; | |
683 else if (format == None && m_second) | |
684 effectiveFormat = Second; | |
685 | |
686 switch (effectiveFormat) { | |
687 default: | |
688 ASSERT_NOT_REACHED(); | |
689 // Fallback to None. | |
690 case None: | |
691 return String::format("%02d:%02d", m_hour, m_minute); | |
692 case Second: | |
693 return String::format("%02d:%02d:%02d", m_hour, m_minute, m_second); | |
694 case Millisecond: | |
695 return String::format("%02d:%02d:%02d.%03d", m_hour, m_minute, m_second,
m_millisecond); | |
696 } | |
697 } | |
698 | |
699 String DateComponents::toString(SecondFormat format) const | |
700 { | |
701 switch (m_type) { | |
702 case Date: | |
703 return String::format("%04d-%02d-%02d", m_year, m_month + 1, m_monthDay)
; | |
704 case DateTime: | |
705 return String::format("%04d-%02d-%02dT", m_year, m_month + 1, m_monthDay
) | |
706 + toStringForTime(format) + String("Z"); | |
707 case DateTimeLocal: | |
708 return String::format("%04d-%02d-%02dT", m_year, m_month + 1, m_monthDay
) | |
709 + toStringForTime(format); | |
710 case Month: | |
711 return String::format("%04d-%02d", m_year, m_month + 1); | |
712 case Time: | |
713 return toStringForTime(format); | |
714 case Week: | |
715 return String::format("%04d-W%02d", m_year, m_week); | |
716 case Invalid: | |
717 break; | |
718 } | |
719 ASSERT_NOT_REACHED(); | |
720 return String("(Invalid DateComponents)"); | |
721 } | |
722 | |
723 } // namespace WebCore | |
OLD | NEW |