]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/JSDateMath.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / runtime / JSDateMath.cpp
index dbe748835de3ed04212ec8f238c817f403ffc6ab..1482e312f377082e37c71554f8fcd7a2debfe1e6 100644 (file)
@@ -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 <algorithm>
 #include <limits.h>
@@ -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<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