double gregorianDateTimeToMS(VM& vm, const GregorianDateTime& t, double milliSeconds, WTF::TimeType inputTimeType) { double day = dateToDaysFrom1970(t.year(), t.month(), t.monthDay()); double ms = timeToMS(t.hour(), t.minute(), t.second(), milliSeconds); double localTimeResult = (day * WTF::msPerDay) + ms; double localToUTCTimeOffset = inputTimeType == LocalTime ? localTimeOffset(vm, localTimeResult, inputTimeType).offset : 0; return localTimeResult - localToUTCTimeOffset; }
double DateComponents::millisecondsSinceEpoch() const { switch (m_type) { case Date: return dateToDaysFrom1970(m_year, m_month, m_monthDay) * msPerDay; case DateTime: case DateTimeLocal: return dateToDaysFrom1970(m_year, m_month, m_monthDay) * msPerDay + millisecondsSinceEpochForTime(); case Month: return dateToDaysFrom1970(m_year, m_month, 1) * msPerDay; case Time: return millisecondsSinceEpochForTime(); case Week: return (dateToDaysFrom1970(m_year, 0, 1) + offsetTo1stWeekStart(m_year) + (m_week - 1) * 7) * msPerDay; case Invalid: break; } ASSERT_NOT_REACHED(); return invalidMilliseconds(); }
double gregorianDateTimeToMS(ExecState* exec, const GregorianDateTime& t, double milliSeconds, bool inputIsUTC) { double day = dateToDaysFrom1970(t.year + 1900, t.month, t.monthDay); double ms = timeToMS(t.hour, t.minute, t.second, milliSeconds); double result = (day * WTF::msPerDay) + ms; if (!inputIsUTC) result -= localTimeOffset(exec, result).offset; return result; }
double gregorianDateTimeToMS(ExecState* exec, const GregorianDateTime& t, double milliSeconds, bool inputIsUTC) { double day = dateToDaysFrom1970(t.year + 1900, t.month, t.monthDay); double ms = timeToMS(t.hour, t.minute, t.second, milliSeconds); double result = (day * WTF::msPerDay) + ms; if (!inputIsUTC) { // convert to UTC double utcOffset = getUTCOffset(exec); result -= utcOffset; result -= getDSTOffset(exec, result, utcOffset); } return result; }
// Returns combined offset in millisecond (UTC + DST). LocalTimeOffset calculateLocalTimeOffset(double ms, TimeType inputTimeType) { #if HAVE(TM_GMTOFF) double localToUTCTimeOffset = inputTimeType == LocalTime ? calculateUTCOffset() : 0; #else double localToUTCTimeOffset = calculateUTCOffset(); #endif if (inputTimeType == LocalTime) ms -= localToUTCTimeOffset; // On Mac OS X, the call to localtime (see calculateDSTOffset) will return historically accurate // DST information (e.g. New Zealand did not have DST from 1946 to 1974) however the JavaScript // standard explicitly dictates that historical information should not be considered when // determining DST. For this reason we shift away from years that localtime can handle but would // return historically accurate information. int year = msToYear(ms); int equivalentYear = equivalentYearForDST(year); if (year != equivalentYear) { bool leapYear = isLeapYear(year); int dayInYearLocal = dayInYear(ms, year); int dayInMonth = dayInMonthFromDayInYear(dayInYearLocal, leapYear); int month = monthFromDayInYear(dayInYearLocal, leapYear); double day = dateToDaysFrom1970(equivalentYear, month, dayInMonth); ms = (day * msPerDay) + msToMilliseconds(ms); } double localTimeSeconds = ms / msPerSecond; if (localTimeSeconds > maxUnixTime) localTimeSeconds = maxUnixTime; else if (localTimeSeconds < 0) // Go ahead a day to make localtime work (does not work with 0). localTimeSeconds += secondsPerDay; // FIXME: time_t has a potential problem in 2038. time_t localTime = static_cast<time_t>(localTimeSeconds); #if HAVE(TM_GMTOFF) tm localTM; getLocalTime(&localTime, &localTM); return LocalTimeOffset(localTM.tm_isdst, localTM.tm_gmtoff * msPerSecond); #else double dstOffset = calculateDSTOffset(localTime, localToUTCTimeOffset); return LocalTimeOffset(dstOffset, localToUTCTimeOffset + dstOffset); #endif }
// Get the DST offset, given a time in UTC static double calculateDSTOffset(double ms, double utcOffset) { // On Mac OS X, the call to localtime (see calculateDSTOffsetSimple) will return historically accurate // DST information (e.g. New Zealand did not have DST from 1946 to 1974) however the JavaScript // standard explicitly dictates that historical information should not be considered when // determining DST. For this reason we shift away from years that localtime can handle but would // return historically accurate information. int year = msToYear(ms); int equivalentYear = equivalentYearForDST(year); if (year != equivalentYear) { bool leapYear = isLeapYear(year); int dayInYearLocal = dayInYear(ms, year); int dayInMonth = dayInMonthFromDayInYear(dayInYearLocal, leapYear); int month = monthFromDayInYear(dayInYearLocal, leapYear); double day = dateToDaysFrom1970(equivalentYear, month, dayInMonth); ms = (day * msPerDay) + msToMilliseconds(ms); } return calculateDSTOffsetSimple(ms / msPerSecond, utcOffset); }
double msForDate(int year, int month, int day) { return dateToDaysFrom1970(year, month, day) * msPerDay; }
double LocaleWin::parseDate(const Vector<DateFormatToken>& tokens, int baseYear, const String& input) { ensureShortMonthLabels(); ensureMonthLabels(); const double NaN = numeric_limits<double>::quiet_NaN(); unsigned inputIndex = 0; int day = -1, month = -1, year = -1; for (unsigned i = 0; i < tokens.size(); ++i) { switch (tokens[i].type) { case DateFormatToken::Literal: { String data = tokens[i].data; unsigned literalLength = data.length(); if (input.substring(inputIndex, literalLength) == data) inputIndex += literalLength; // Go ahead even if the input doesn't have this string. break; } case DateFormatToken::Day1: case DateFormatToken::Day2: day = parseNumber(input, inputIndex); if (day < 1 || day > 31) return NaN; break; case DateFormatToken::Month1: case DateFormatToken::Month2: case DateFormatToken::Month3: case DateFormatToken::Month4: month = parseNumberOrMonth(input, inputIndex); if (month < 0 || month > 11) return NaN; break; case DateFormatToken::Year1: { unsigned oldIndex = inputIndex; year = parseNumber(input, inputIndex); if (year <= 0) return NaN; if (inputIndex - oldIndex == 1) { int shortYear = baseYear % 10; int decade = baseYear - shortYear; if (shortYear >= 5) year += shortYear - 4 <= year ? decade : decade + 10; else year += shortYear + 5 >= year ? decade : decade - 10; } break; } case DateFormatToken::Year2: { unsigned oldIndex = inputIndex; year = parseNumber(input, inputIndex); if (year <= 0) return NaN; if (inputIndex - oldIndex == 2) { int shortYear = baseYear % 100; int century = baseYear - shortYear; if (shortYear >= 50) year += shortYear - 49 <= year ? century : century + 100; else year += shortYear + 50 >= year ? century : century - 100; } break; } case DateFormatToken::Year4: year = parseNumber(input, inputIndex); if (year <= 0) return NaN; break; } } if (year <= 0 || month < 0 || day <= 0) return NaN; return dateToDaysFrom1970(year, month, day) * msPerDay; }