Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / DateComponents.cpp
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 "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 blink {
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 months 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 // 'month' is 0-based.
57 static int maxDayOfMonth(int year, int month)
58 {
59     if (month != 1) // February?
60         return daysInMonth[month];
61     return isLeapYear(year) ? 29 : 28;
62 }
63
64 // 'month' is 0-based.
65 static int dayOfWeek(int year, int month, int day)
66 {
67     int shiftedMonth = month + 2;
68     // 2:January, 3:Feburuary, 4:March, ...
69
70     // Zeller's congruence
71     if (shiftedMonth <= 3) {
72         shiftedMonth += 12;
73         year--;
74     }
75     // 4:March, ..., 14:January, 15:February
76
77     int highYear = year / 100;
78     int lowYear = year % 100;
79     // We add 6 to make the result Sunday-origin.
80     int result = (day + 13 * shiftedMonth / 5 + lowYear + lowYear / 4 + highYear / 4 + 5 * highYear + 6) % 7;
81     return result;
82 }
83
84 int DateComponents::weekDay() const
85 {
86     return dayOfWeek(m_year, m_month, m_monthDay);
87 }
88
89 int DateComponents::maxWeekNumberInYear() const
90 {
91     int day = dayOfWeek(m_year, 0, 1); // January 1.
92     return day == Thursday || (day == Wednesday && isLeapYear(m_year)) ? maximumWeekNumber : maximumWeekNumber - 1;
93 }
94
95 static unsigned countDigits(const String& src, unsigned start)
96 {
97     unsigned index = start;
98     for (; index < src.length(); ++index) {
99         if (!isASCIIDigit(src[index]))
100             break;
101     }
102     return index - start;
103 }
104
105 // Very strict integer parser. Do not allow leading or trailing whitespace unlike charactersToIntStrict().
106 static bool toInt(const String& src, unsigned parseStart, unsigned parseLength, int& out)
107 {
108     if (parseStart + parseLength > src.length() || !parseLength)
109         return false;
110     int value = 0;
111     unsigned current = parseStart;
112     unsigned end = current + parseLength;
113
114     // We don't need to handle negative numbers for ISO 8601.
115     for (; current < end; ++current) {
116         if (!isASCIIDigit(src[current]))
117             return false;
118         int digit = src[current] - '0';
119         if (value > (INT_MAX - digit) / 10) // Check for overflow.
120             return false;
121         value = value * 10 + digit;
122     }
123     out = value;
124     return true;
125 }
126
127 bool DateComponents::parseYear(const String& src, unsigned start, unsigned& end)
128 {
129     unsigned digitsLength = countDigits(src, start);
130     // Needs at least 4 digits according to the standard.
131     if (digitsLength < 4)
132         return false;
133     int year;
134     if (!toInt(src, start, digitsLength, year))
135         return false;
136     if (year < minimumYear() || year > maximumYear())
137         return false;
138     m_year = year;
139     end = start + digitsLength;
140     return true;
141 }
142
143 static bool withinHTMLDateLimits(int year, int month)
144 {
145     if (year < DateComponents::minimumYear())
146         return false;
147     if (year < DateComponents::maximumYear())
148         return true;
149     return month <= maximumMonthInMaximumYear;
150 }
151
152 static bool withinHTMLDateLimits(int year, int month, int monthDay)
153 {
154     if (year < DateComponents::minimumYear())
155         return false;
156     if (year < DateComponents::maximumYear())
157         return true;
158     if (month < maximumMonthInMaximumYear)
159         return true;
160     return monthDay <= maximumDayInMaximumMonth;
161 }
162
163 static bool withinHTMLDateLimits(int year, int month, int monthDay, int hour, int minute, int second, int millisecond)
164 {
165     if (year < DateComponents::minimumYear())
166         return false;
167     if (year < DateComponents::maximumYear())
168         return true;
169     if (month < maximumMonthInMaximumYear)
170         return true;
171     if (monthDay < maximumDayInMaximumMonth)
172         return true;
173     if (monthDay > maximumDayInMaximumMonth)
174         return false;
175     // (year, month, monthDay) = (maximumYear, maximumMonthInMaximumYear, maximumDayInMaximumMonth)
176     return !hour && !minute && !second && !millisecond;
177 }
178
179 bool DateComponents::addDay(int dayDiff)
180 {
181     ASSERT(m_monthDay);
182
183     int day = m_monthDay + dayDiff;
184     if (day > maxDayOfMonth(m_year, m_month)) {
185         day = m_monthDay;
186         int year = m_year;
187         int month = m_month;
188         int maxDay = maxDayOfMonth(year, month);
189         for (; dayDiff > 0; --dayDiff) {
190             ++day;
191             if (day > maxDay) {
192                 day = 1;
193                 ++month;
194                 if (month >= 12) { // month is 0-origin.
195                     month = 0;
196                     ++year;
197                 }
198                 maxDay = maxDayOfMonth(year, month);
199             }
200         }
201         if (!withinHTMLDateLimits(year, month, day))
202             return false;
203         m_year = year;
204         m_month = month;
205     } else if (day < 1) {
206         int month = m_month;
207         int year = m_year;
208         day = m_monthDay;
209         for (; dayDiff < 0; ++dayDiff) {
210             --day;
211             if (day < 1) {
212                 --month;
213                 if (month < 0) {
214                     month = 11;
215                     --year;
216                 }
217                 day = maxDayOfMonth(year, month);
218             }
219         }
220         if (!withinHTMLDateLimits(year, month, day))
221             return false;
222         m_year = year;
223         m_month = month;
224     } else {
225         if (!withinHTMLDateLimits(m_year, m_month, day))
226             return false;
227     }
228     m_monthDay = day;
229     return true;
230 }
231
232 bool DateComponents::addMinute(int minute)
233 {
234     // This function is used to adjust timezone offset. So m_year, m_month,
235     // m_monthDay have values between the lower and higher limits.
236     ASSERT(withinHTMLDateLimits(m_year, m_month, m_monthDay));
237
238     int carry;
239     // minute can be negative or greater than 59.
240     minute += m_minute;
241     if (minute > 59) {
242         carry = minute / 60;
243         minute = minute % 60;
244     } else if (minute < 0) {
245         carry = (59 - minute) / 60;
246         minute += carry * 60;
247         carry = -carry;
248         ASSERT(minute >= 0 && minute <= 59);
249     } else {
250         if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, m_hour, minute, m_second, m_millisecond))
251             return false;
252         m_minute = minute;
253         return true;
254     }
255
256     int hour = m_hour + carry;
257     if (hour > 23) {
258         carry = hour / 24;
259         hour = hour % 24;
260     } else if (hour < 0) {
261         carry = (23 - hour) / 24;
262         hour += carry * 24;
263         carry = -carry;
264         ASSERT(hour >= 0 && hour <= 23);
265     } else {
266         if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, hour, minute, m_second, m_millisecond))
267             return false;
268         m_minute = minute;
269         m_hour = hour;
270         return true;
271     }
272     if (!addDay(carry))
273         return false;
274     if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, hour, minute, m_second, m_millisecond))
275         return false;
276     m_minute = minute;
277     m_hour = hour;
278     return true;
279 }
280
281 // Parses a timezone part, and adjust year, month, monthDay, hour, minute, second, millisecond.
282 bool DateComponents::parseTimeZone(const String& src, unsigned start, unsigned& end)
283 {
284     if (start >= src.length())
285         return false;
286     unsigned index = start;
287     if (src[index] == 'Z') {
288         end = index + 1;
289         return true;
290     }
291
292     bool minus;
293     if (src[index] == '+')
294         minus = false;
295     else if (src[index] == '-')
296         minus = true;
297     else
298         return false;
299     ++index;
300
301     int hour;
302     int minute;
303     if (!toInt(src, index, 2, hour) || hour < 0 || hour > 23)
304         return false;
305     index += 2;
306
307     if (index >= src.length() || src[index] != ':')
308         return false;
309     ++index;
310
311     if (!toInt(src, index, 2, minute) || minute < 0 || minute > 59)
312         return false;
313     index += 2;
314
315     if (minus) {
316         hour = -hour;
317         minute = -minute;
318     }
319
320     // Subtract the timezone offset.
321     if (!addMinute(-(hour * 60 + minute)))
322         return false;
323     end = index;
324     return true;
325 }
326
327 bool DateComponents::parseMonth(const String& src, unsigned start, unsigned& end)
328 {
329     unsigned index;
330     if (!parseYear(src, start, index))
331         return false;
332     if (index >= src.length() || src[index] != '-')
333         return false;
334     ++index;
335
336     int month;
337     if (!toInt(src, index, 2, month) || month < 1 || month > 12)
338         return false;
339     --month;
340     if (!withinHTMLDateLimits(m_year, month))
341         return false;
342     m_month = month;
343     end = index + 2;
344     m_type = Month;
345     return true;
346 }
347
348 bool DateComponents::parseDate(const String& src, unsigned start, unsigned& end)
349 {
350     unsigned index;
351     if (!parseMonth(src, start, index))
352         return false;
353     // '-' and 2-digits are needed.
354     if (index + 2 >= src.length())
355         return false;
356     if (src[index] != '-')
357         return false;
358     ++index;
359
360     int day;
361     if (!toInt(src, index, 2, day) || day < 1 || day > maxDayOfMonth(m_year, m_month))
362         return false;
363     if (!withinHTMLDateLimits(m_year, m_month, day))
364         return false;
365     m_monthDay = day;
366     end = index + 2;
367     m_type = Date;
368     return true;
369 }
370
371 bool DateComponents::parseWeek(const String& src, unsigned start, unsigned& end)
372 {
373     unsigned index;
374     if (!parseYear(src, start, index))
375         return false;
376
377     // 4 characters ('-' 'W' digit digit) are needed.
378     if (index + 3 >= src.length())
379         return false;
380     if (src[index] != '-')
381         return false;
382     ++index;
383     if (src[index] != 'W')
384         return false;
385     ++index;
386
387     int week;
388     if (!toInt(src, index, 2, week) || week < minimumWeekNumber || week > maxWeekNumberInYear())
389         return false;
390     if (m_year == maximumYear() && week > maximumWeekInMaximumYear)
391         return false;
392     m_week = week;
393     end = index + 2;
394     m_type = Week;
395     return true;
396 }
397
398 bool DateComponents::parseTime(const String& src, unsigned start, unsigned& end)
399 {
400     int hour;
401     if (!toInt(src, start, 2, hour) || hour < 0 || hour > 23)
402         return false;
403     unsigned index = start + 2;
404     if (index >= src.length())
405         return false;
406     if (src[index] != ':')
407         return false;
408     ++index;
409
410     int minute;
411     if (!toInt(src, index, 2, minute) || minute < 0 || minute > 59)
412         return false;
413     index += 2;
414
415     int second = 0;
416     int millisecond = 0;
417     // Optional second part.
418     // Do not return with false because the part is optional.
419     if (index + 2 < src.length() && src[index] == ':') {
420         if (toInt(src, index + 1, 2, second) && second >= 0 && second <= 59) {
421             index += 3;
422
423             // Optional fractional second part.
424             if (index < src.length() && src[index] == '.') {
425                 unsigned digitsLength = countDigits(src, index + 1);
426                 if (digitsLength >  0) {
427                     ++index;
428                     bool ok;
429                     if (digitsLength == 1) {
430                         ok = toInt(src, index, 1, millisecond);
431                         millisecond *= 100;
432                     } else if (digitsLength == 2) {
433                         ok = toInt(src, index, 2, millisecond);
434                         millisecond *= 10;
435                     } else { // digitsLength >= 3
436                         ok = toInt(src, index, 3, millisecond);
437                     }
438                     ASSERT_UNUSED(ok, ok);
439                     index += digitsLength;
440                 }
441             }
442         }
443     }
444     m_hour = hour;
445     m_minute = minute;
446     m_second = second;
447     m_millisecond = millisecond;
448     end = index;
449     m_type = Time;
450     return true;
451 }
452
453 bool DateComponents::parseDateTimeLocal(const String& src, unsigned start, unsigned& end)
454 {
455     unsigned index;
456     if (!parseDate(src, start, index))
457         return false;
458     if (index >= src.length())
459         return false;
460     if (src[index] != 'T')
461         return false;
462     ++index;
463     if (!parseTime(src, index, end))
464         return false;
465     if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, m_hour, m_minute, m_second, m_millisecond))
466         return false;
467     m_type = DateTimeLocal;
468     return true;
469 }
470
471 bool DateComponents::parseDateTime(const String& src, unsigned start, unsigned& end)
472 {
473     unsigned index;
474     if (!parseDate(src, start, index))
475         return false;
476     if (index >= src.length())
477         return false;
478     if (src[index] != 'T')
479         return false;
480     ++index;
481     if (!parseTime(src, index, index))
482         return false;
483     if (!parseTimeZone(src, index, end))
484         return false;
485     if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, m_hour, m_minute, m_second, m_millisecond))
486         return false;
487     m_type = DateTime;
488     return true;
489 }
490
491 static inline double positiveFmod(double value, double divider)
492 {
493     double remainder = fmod(value, divider);
494     return remainder < 0 ? remainder + divider : remainder;
495 }
496
497 void DateComponents::setMillisecondsSinceMidnightInternal(double msInDay)
498 {
499     ASSERT(msInDay >= 0 && msInDay < msPerDay);
500     m_millisecond = static_cast<int>(fmod(msInDay, msPerSecond));
501     double value = floor(msInDay / msPerSecond);
502     m_second = static_cast<int>(fmod(value, secondsPerMinute));
503     value = floor(value / secondsPerMinute);
504     m_minute = static_cast<int>(fmod(value, minutesPerHour));
505     m_hour = static_cast<int>(value / minutesPerHour);
506 }
507
508 bool DateComponents::setMillisecondsSinceEpochForDateInternal(double ms)
509 {
510     m_year = msToYear(ms);
511     int yearDay = dayInYear(ms, m_year);
512     m_month = monthFromDayInYear(yearDay, isLeapYear(m_year));
513     m_monthDay = dayInMonthFromDayInYear(yearDay, isLeapYear(m_year));
514     return true;
515 }
516
517 bool DateComponents::setMillisecondsSinceEpochForDate(double ms)
518 {
519     m_type = Invalid;
520     if (!std::isfinite(ms))
521         return false;
522     if (!setMillisecondsSinceEpochForDateInternal(round(ms)))
523         return false;
524     if (!withinHTMLDateLimits(m_year, m_month, m_monthDay))
525         return false;
526     m_type = Date;
527     return true;
528 }
529
530 bool DateComponents::setMillisecondsSinceEpochForDateTime(double ms)
531 {
532     m_type = Invalid;
533     if (!std::isfinite(ms))
534         return false;
535     ms = round(ms);
536     setMillisecondsSinceMidnightInternal(positiveFmod(ms, msPerDay));
537     if (!setMillisecondsSinceEpochForDateInternal(ms))
538         return false;
539     if (!withinHTMLDateLimits(m_year, m_month, m_monthDay, m_hour, m_minute, m_second, m_millisecond))
540         return false;
541     m_type = DateTime;
542     return true;
543 }
544
545 bool DateComponents::setMillisecondsSinceEpochForDateTimeLocal(double ms)
546 {
547     // Internal representation of DateTimeLocal is the same as DateTime except m_type.
548     if (!setMillisecondsSinceEpochForDateTime(ms))
549         return false;
550     m_type = DateTimeLocal;
551     return true;
552 }
553
554 bool DateComponents::setMillisecondsSinceEpochForMonth(double ms)
555 {
556     m_type = Invalid;
557     if (!std::isfinite(ms))
558         return false;
559     if (!setMillisecondsSinceEpochForDateInternal(round(ms)))
560         return false;
561     if (!withinHTMLDateLimits(m_year, m_month))
562         return false;
563     m_type = Month;
564     return true;
565 }
566
567 bool DateComponents::setMillisecondsSinceMidnight(double ms)
568 {
569     m_type = Invalid;
570     if (!std::isfinite(ms))
571         return false;
572     setMillisecondsSinceMidnightInternal(positiveFmod(round(ms), msPerDay));
573     m_type = Time;
574     return true;
575 }
576
577 bool DateComponents::setMonthsSinceEpoch(double months)
578 {
579     if (!std::isfinite(months))
580         return false;
581     months = round(months);
582     double doubleMonth = positiveFmod(months, 12);
583     double doubleYear = 1970 + (months - doubleMonth) / 12;
584     if (doubleYear < minimumYear() || maximumYear() < doubleYear)
585         return false;
586     int year = static_cast<int>(doubleYear);
587     int month = static_cast<int>(doubleMonth);
588     if (!withinHTMLDateLimits(year, month))
589         return false;
590     m_year = year;
591     m_month = month;
592     m_type = Month;
593     return true;
594 }
595
596 // Offset from January 1st to Monday of the ISO 8601's first week.
597 //   ex. If January 1st is Friday, such Monday is 3 days later. Returns 3.
598 static int offsetTo1stWeekStart(int year)
599 {
600     int offsetTo1stWeekStart = 1 - dayOfWeek(year, 0, 1);
601     if (offsetTo1stWeekStart <= -4)
602         offsetTo1stWeekStart += 7;
603     return offsetTo1stWeekStart;
604 }
605
606 bool DateComponents::setMillisecondsSinceEpochForWeek(double ms)
607 {
608     m_type = Invalid;
609     if (!std::isfinite(ms))
610         return false;
611     ms = round(ms);
612
613     m_year = msToYear(ms);
614     if (m_year < minimumYear() || m_year > maximumYear())
615         return false;
616
617     int yearDay = dayInYear(ms, m_year);
618     int offset = offsetTo1stWeekStart(m_year);
619     if (yearDay < offset) {
620         // The day belongs to the last week of the previous year.
621         m_year--;
622         if (m_year <= minimumYear())
623             return false;
624         m_week = maxWeekNumberInYear();
625     } else {
626         m_week = ((yearDay - offset) / 7) + 1;
627         if (m_week > maxWeekNumberInYear()) {
628             m_year++;
629             m_week = 1;
630         }
631         if (m_year > maximumYear() || (m_year == maximumYear() && m_week > maximumWeekInMaximumYear))
632             return false;
633     }
634     m_type = Week;
635     return true;
636 }
637
638 double DateComponents::millisecondsSinceEpochForTime() const
639 {
640     ASSERT(m_type == Time || m_type == DateTime || m_type == DateTimeLocal);
641     return ((m_hour * minutesPerHour + m_minute) * secondsPerMinute + m_second) * msPerSecond + m_millisecond;
642 }
643
644 double DateComponents::millisecondsSinceEpoch() const
645 {
646     switch (m_type) {
647     case Date:
648         return dateToDaysFrom1970(m_year, m_month, m_monthDay) * msPerDay;
649     case DateTime:
650     case DateTimeLocal:
651         return dateToDaysFrom1970(m_year, m_month, m_monthDay) * msPerDay + millisecondsSinceEpochForTime();
652     case Month:
653         return dateToDaysFrom1970(m_year, m_month, 1) * msPerDay;
654     case Time:
655         return millisecondsSinceEpochForTime();
656     case Week:
657         return (dateToDaysFrom1970(m_year, 0, 1) + offsetTo1stWeekStart(m_year) + (m_week - 1) * 7) * msPerDay;
658     case Invalid:
659         break;
660     }
661     ASSERT_NOT_REACHED();
662     return invalidMilliseconds();
663 }
664
665 double DateComponents::monthsSinceEpoch() const
666 {
667     ASSERT(m_type == Month);
668     return (m_year - 1970) * 12 + m_month;
669 }
670
671 String DateComponents::toStringForTime(SecondFormat format) const
672 {
673     ASSERT(m_type == DateTime || m_type == DateTimeLocal || m_type == Time);
674     SecondFormat effectiveFormat = format;
675     if (m_millisecond)
676         effectiveFormat = Millisecond;
677     else if (format == None && m_second)
678         effectiveFormat = Second;
679
680     switch (effectiveFormat) {
681     default:
682         ASSERT_NOT_REACHED();
683         // Fallback to None.
684     case None:
685         return String::format("%02d:%02d", m_hour, m_minute);
686     case Second:
687         return String::format("%02d:%02d:%02d", m_hour, m_minute, m_second);
688     case Millisecond:
689         return String::format("%02d:%02d:%02d.%03d", m_hour, m_minute, m_second, m_millisecond);
690     }
691 }
692
693 String DateComponents::toString(SecondFormat format) const
694 {
695     switch (m_type) {
696     case Date:
697         return String::format("%04d-%02d-%02d", m_year, m_month + 1, m_monthDay);
698     case DateTime:
699         return String::format("%04d-%02d-%02dT", m_year, m_month + 1, m_monthDay)
700             + toStringForTime(format) + String("Z");
701     case DateTimeLocal:
702         return String::format("%04d-%02d-%02dT", m_year, m_month + 1, m_monthDay)
703             + toStringForTime(format);
704     case Month:
705         return String::format("%04d-%02d", m_year, m_month + 1);
706     case Time:
707         return toStringForTime(format);
708     case Week:
709         return String::format("%04d-W%02d", m_year, m_week);
710     case Invalid:
711         break;
712     }
713     ASSERT_NOT_REACHED();
714     return String("(Invalid DateComponents)");
715 }
716
717 } // namespace blink