X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/6fe7ccc865dc7d7541b93c5bcaf6368d2c98a174..refs/heads/master:/runtime/JSDateMath.cpp diff --git a/runtime/JSDateMath.cpp b/runtime/JSDateMath.cpp index dbe7488..1482e31 100644 --- a/runtime/JSDateMath.cpp +++ b/runtime/JSDateMath.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2012 Apple Inc. All rights reserved. * Copyright (C) 2009 Google Inc. All rights reserved. * Copyright (C) 2007-2009 Torch Mobile, Inc. * Copyright (C) 2010 &yet, LLC. (nate@andyet.net) @@ -73,7 +73,8 @@ #include "JSDateMath.h" #include "JSObject.h" -#include "ScopeChain.h" +#include "JSScope.h" +#include "JSCInlines.h" #include #include @@ -126,18 +127,19 @@ static inline int msToWeekDay(double ms) return wd; } -// Get the DST offset for the time passed in. +// Get the combined UTC + DST offset for the time passed in. // // NOTE: The implementation relies on the fact that no time zones have // more than one daylight savings offset change per month. // If this function is called with NaN it returns NaN. -static double getDSTOffset(ExecState* exec, double ms, double utcOffset) +static LocalTimeOffset localTimeOffset(VM& vm, double ms, WTF::TimeType inputTimeType = WTF::UTCTime) { - DSTOffsetCache& cache = exec->globalData().dstOffsetCache; + LocalTimeOffsetCache& cache = vm.localTimeOffsetCache; double start = cache.start; double end = cache.end; + WTF::TimeType cachedTimeType = cache.timeType; - if (start <= ms) { + if (cachedTimeType == inputTimeType && start <= ms) { // If the time fits in the cached interval, return the cached offset. if (ms <= end) return cache.offset; @@ -145,7 +147,7 @@ static double getDSTOffset(ExecState* exec, double ms, double utcOffset) double newEnd = end + cache.increment; if (ms <= newEnd) { - double endOffset = calculateDSTOffset(newEnd, utcOffset); + LocalTimeOffset endOffset = calculateLocalTimeOffset(newEnd, inputTimeType); if (cache.offset == endOffset) { // If the offset at the end of the new interval still matches // the offset in the cache, we grow the cached time interval @@ -153,110 +155,99 @@ static double getDSTOffset(ExecState* exec, double ms, double utcOffset) cache.end = newEnd; cache.increment = msPerMonth; return endOffset; + } + LocalTimeOffset offset = calculateLocalTimeOffset(ms, inputTimeType); + if (offset == endOffset) { + // The offset at the given time is equal to the offset at the + // new end of the interval, so that means that we've just skipped + // the point in time where the DST offset change occurred. Updated + // the interval to reflect this and reset the increment. + cache.start = ms; + cache.end = newEnd; + cache.increment = msPerMonth; } else { - double offset = calculateDSTOffset(ms, utcOffset); - if (offset == endOffset) { - // The offset at the given time is equal to the offset at the - // new end of the interval, so that means that we've just skipped - // the point in time where the DST offset change occurred. Updated - // the interval to reflect this and reset the increment. - cache.start = ms; - cache.end = newEnd; - cache.increment = msPerMonth; - } else { - // The interval contains a DST offset change and the given time is - // before it. Adjust the increment to avoid a linear search for - // the offset change point and change the end of the interval. - cache.increment /= 3; - cache.end = ms; - } - // Update the offset in the cache and return it. - cache.offset = offset; - return offset; + // The interval contains a DST offset change and the given time is + // before it. Adjust the increment to avoid a linear search for + // the offset change point and change the end of the interval. + cache.increment /= 3; + cache.end = ms; } + // Update the offset in the cache and return it. + cache.offset = offset; + return offset; } } // Compute the DST offset for the time and shrink the cache interval // to only contain the time. This allows fast repeated DST offset // computations for the same time. - double offset = calculateDSTOffset(ms, utcOffset); + LocalTimeOffset offset = calculateLocalTimeOffset(ms, inputTimeType); cache.offset = offset; cache.start = ms; cache.end = ms; cache.increment = msPerMonth; + cache.timeType = inputTimeType; return offset; } -/* - * Get the difference in milliseconds between this time zone and UTC (GMT) - * NOT including DST. - */ -double getUTCOffset(ExecState* exec) -{ - double utcOffset = exec->globalData().cachedUTCOffset; - if (!isnan(utcOffset)) - return utcOffset; - exec->globalData().cachedUTCOffset = calculateUTCOffset(); - return exec->globalData().cachedUTCOffset; -} - -double gregorianDateTimeToMS(ExecState* exec, const GregorianDateTime& t, double milliSeconds, bool inputIsUTC) +double gregorianDateTimeToMS(VM& vm, const GregorianDateTime& t, double milliSeconds, WTF::TimeType inputTimeType) { - 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; + 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; - if (!inputIsUTC) { // convert to UTC - double utcOffset = getUTCOffset(exec); - result -= utcOffset; - result -= getDSTOffset(exec, result, utcOffset); - } - - return result; + return localTimeResult - localToUTCTimeOffset; } // input is UTC -void msToGregorianDateTime(ExecState* exec, double ms, bool outputIsUTC, GregorianDateTime& tm) +void msToGregorianDateTime(VM& vm, double ms, WTF::TimeType outputTimeType, GregorianDateTime& tm) { - double dstOff = 0.0; - double utcOff = 0.0; - if (!outputIsUTC) { - utcOff = getUTCOffset(exec); - dstOff = getDSTOffset(exec, ms, utcOff); - ms += dstOff + utcOff; + LocalTimeOffset localTime; + if (outputTimeType == WTF::LocalTime) { + localTime = localTimeOffset(vm, ms); + ms += localTime.offset; } const int year = msToYear(ms); - tm.second = msToSeconds(ms); - tm.minute = msToMinutes(ms); - tm.hour = msToHours(ms); - tm.weekDay = msToWeekDay(ms); - tm.yearDay = dayInYear(ms, year); - tm.monthDay = dayInMonthFromDayInYear(tm.yearDay, isLeapYear(year)); - tm.month = monthFromDayInYear(tm.yearDay, isLeapYear(year)); - tm.year = year - 1900; - tm.isDST = dstOff != 0.0; - tm.utcOffset = static_cast((dstOff + utcOff) / WTF::msPerSecond); - tm.timeZone = nullptr; + tm.setSecond(msToSeconds(ms)); + tm.setMinute(msToMinutes(ms)); + tm.setHour(msToHours(ms)); + tm.setWeekDay(msToWeekDay(ms)); + tm.setYearDay(dayInYear(ms, year)); + tm.setMonthDay(dayInMonthFromDayInYear(tm.yearDay(), isLeapYear(year))); + tm.setMonth(monthFromDayInYear(tm.yearDay(), isLeapYear(year))); + tm.setYear(year); + tm.setIsDST(localTime.isDST); + tm.setUtcOffset(localTime.offset / WTF::msPerSecond); } -double parseDateFromNullTerminatedCharacters(ExecState* exec, const char* dateString) +double parseDateFromNullTerminatedCharacters(VM& vm, const char* dateString) { - ASSERT(exec); bool haveTZ; int offset; - double ms = WTF::parseDateFromNullTerminatedCharacters(dateString, haveTZ, offset); - if (isnan(ms)) + double localTimeMS = WTF::parseDateFromNullTerminatedCharacters(dateString, haveTZ, offset); + if (std::isnan(localTimeMS)) return std::numeric_limits::quiet_NaN(); - // fall back to local timezone - if (!haveTZ) { - double utcOffset = getUTCOffset(exec); - double dstOffset = getDSTOffset(exec, ms, utcOffset); - offset = static_cast((utcOffset + dstOffset) / WTF::msPerMinute); - } - return ms - (offset * WTF::msPerMinute); + // fall back to local timezone. + if (!haveTZ) + offset = localTimeOffset(vm, localTimeMS, WTF::LocalTime).offset / WTF::msPerMinute; + + return localTimeMS - (offset * WTF::msPerMinute); +} + +double parseDate(VM& vm, const String& date) +{ + if (date == vm.cachedDateString) + return vm.cachedDateStringValue; + double value = parseES5DateFromNullTerminatedCharacters(date.utf8().data()); + if (std::isnan(value)) + value = parseDateFromNullTerminatedCharacters(vm, date.utf8().data()); + vm.cachedDateString = date; + vm.cachedDateStringValue = value; + return value; } } // namespace JSC