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