/*
* 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)
#include "JSDateMath.h"
#include "JSObject.h"
-#include "ScopeChain.h"
+#include "JSScope.h"
+#include "JSCInlines.h"
#include <algorithm>
#include <limits.h>
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;
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
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<long>((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<double>::quiet_NaN();
- // fall back to local timezone
- if (!haveTZ) {
- double utcOffset = getUTCOffset(exec);
- double dstOffset = getDSTOffset(exec, ms, utcOffset);
- offset = static_cast<int>((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