Home | History | Annotate | Download | only in html
      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
    682