Simplify date handling code
authorHojong Han <hojong.han@samsung.com>
Mon, 12 Aug 2013 23:49:18 +0000 (08:49 +0900)
committerHojong Han <hojong.han@samsung.com>
Tue, 13 Aug 2013 00:27:46 +0000 (09:27 +0900)
[Title] Simplify date handling code
[Issue#] VPSS-1105
[Problem] new Date(2010,10,1) with timezone set to +4 (MSK) returns "Sun Oct 31 2010 01:00:00 GMT+0400 (MSK)"
[Cause] Operating seperately on the UTC-standard and standard-DST offsets
[Solution] Generate a combined UTC-local offset
           This patch is based on commit-id ad805ed257b0997c5333bb8967e23cc1c24f4208 on Webkit-trunk

Change-Id: Ie96e028c5d8a9cbee01449074a03a8f82562f468

Source/JavaScriptCore/runtime/JSDateMath.cpp
Source/JavaScriptCore/runtime/JSGlobalData.cpp
Source/JavaScriptCore/runtime/JSGlobalData.h
Source/WTF/wtf/DateMath.cpp
Source/WTF/wtf/DateMath.h
Source/WTF/wtf/GregorianDateTime.cpp
Source/WTF/wtf/Platform.h
Source/WebCore/html/BaseDateAndTimeInputType.cpp
Source/WebCore/html/MonthInputType.cpp
Source/WebCore/html/TimeInputType.cpp

index fcf1c43..1f586e8 100644 (file)
@@ -126,14 +126,14 @@ 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 getLocalTimeOffset(ExecState* exec, double ms)
 {
-    DSTOffsetCache& cache = exec->globalData().dstOffsetCache;
+    LocalTimeOffsetCache& cache = exec->globalData().localTimeOffsetCache;
     double start = cache.start;
     double end = cache.end;
 
@@ -145,7 +145,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);
             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,34 +153,33 @@ static double getDSTOffset(ExecState* exec, double ms, double utcOffset)
                 cache.end = newEnd;
                 cache.increment = msPerMonth;
                 return endOffset;
+            } 
+            LocalTimeOffset offset = calculateLocalTimeOffset(ms); 
+            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);
     cache.offset = offset;
     cache.start = ms;
     cache.end = ms;
@@ -188,30 +187,15 @@ static double getDSTOffset(ExecState* exec, double ms, double utcOffset)
     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 day = dateToDaysFrom1970(t.year(), 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);
-    }
+    // convert to UTC
+    if (!inputIsUTC)
+        result -= getLocalTimeOffset(exec, result).offset;
 
     return result;
 }
@@ -219,12 +203,10 @@ double gregorianDateTimeToMS(ExecState* exec, const GregorianDateTime& t, double
 // input is UTC
 void msToGregorianDateTime(ExecState* exec, double ms, bool outputIsUTC, GregorianDateTime& tm)
 {
-    double dstOff = 0.0;
-    double utcOff = 0.0;
+    LocalTimeOffset localTimeOffset(false, 0);
     if (!outputIsUTC) {
-        utcOff = getUTCOffset(exec);
-        dstOff = getDSTOffset(exec, ms, utcOff);
-        ms += dstOff + utcOff;
+        localTimeOffset = getLocalTimeOffset(exec, ms);
+        ms += localTimeOffset.offset;
     }
 
     const int year = msToYear(ms);
@@ -236,8 +218,8 @@ void msToGregorianDateTime(ExecState* exec, double ms, bool outputIsUTC, Gregori
     tm.setMonthDay(dayInMonthFromDayInYear(tm.yearDay(), isLeapYear(year)));
     tm.setMonth(monthFromDayInYear(tm.yearDay(), isLeapYear(year)));
     tm.setYear(year);
-    tm.setIsDST(dstOff != 0.0);
-    tm.setUtcOffset(static_cast<long>((dstOff + utcOff) / WTF::msPerSecond));
+    tm.setIsDST(localTimeOffset.isDST);
+    tm.setUtcOffset(localTimeOffset.offset / WTF::msPerSecond);
 }
 
 double parseDateFromNullTerminatedCharacters(ExecState* exec, const char* dateString)
@@ -250,11 +232,8 @@ double parseDateFromNullTerminatedCharacters(ExecState* exec, const char* dateSt
         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);
-    }
+    if (!haveTZ)
+        offset = getLocalTimeOffset(exec, ms).offset / WTF::msPerMinute;
     return ms - (offset * WTF::msPerMinute);
 }
 
index c78cf5a..b093716 100644 (file)
@@ -157,7 +157,6 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread
     , sizeOfLastScratchBuffer(0)
 #endif
     , dynamicGlobalObject(0)
-    , cachedUTCOffset(std::numeric_limits<double>::quiet_NaN())
     , maxReentryDepth(threadStackType == ThreadStackTypeSmall ? MaxSmallThreadReentryDepth : MaxLargeThreadReentryDepth)
     , m_enabledProfiler(0)
     , m_regExpCache(new RegExpCache(this))
@@ -385,8 +384,7 @@ JSGlobalData::ClientData::~ClientData()
 
 void JSGlobalData::resetDateCache()
 {
-    cachedUTCOffset = std::numeric_limits<double>::quiet_NaN();
-    dstOffsetCache.reset();
+    localTimeOffsetCache.reset();
     cachedDateString = UString();
     cachedDateStringValue = std::numeric_limits<double>::quiet_NaN();
     dateInstanceCache.reset();
index d185e18..c3be3d5 100644 (file)
@@ -46,6 +46,7 @@
 #include "TimeoutChecker.h"
 #include "WeakRandom.h"
 #include <wtf/BumpPointerAllocator.h>
+#include <wtf/DateMath.h>
 #include <wtf/Forward.h>
 #include <wtf/HashMap.h>
 #include <wtf/SimpleStats.h>
@@ -84,21 +85,22 @@ namespace JSC {
     struct HashTable;
     struct Instruction;
 
-    struct DSTOffsetCache {
-        DSTOffsetCache()
+    struct LocalTimeOffsetCache {
+        LocalTimeOffsetCache()
+            : offset(false, 0)
         {
             reset();
         }
         
         void reset()
         {
-            offset = 0.0;
+            offset = LocalTimeOffset(false, 0);
             start = 0.0;
             end = -1.0;
             increment = 0.0;
         }
 
-        double offset;
+        LocalTimeOffset offset;
         double start;
         double end;
         double increment;
@@ -357,8 +359,7 @@ namespace JSC {
 
         HashSet<JSObject*> stringRecursionCheckVisitedObjects;
 
-        double cachedUTCOffset;
-        DSTOffsetCache dstOffsetCache;
+        LocalTimeOffsetCache localTimeOffsetCache;
         
         UString cachedDateString;
         double cachedDateStringValue;
index e3fc329..b964261 100644 (file)
@@ -356,7 +356,9 @@ int equivalentYearForDST(int year)
     return year;
 }
 
-int32_t calculateUTCOffset()
+#if !HAVE(TM_GMTOFF)
+
+static int32_t calculateUTCOffset()
 {
 #if OS(WINDOWS)
     TIME_ZONE_INFORMATION timeZoneInformation;
@@ -400,23 +402,15 @@ int32_t calculateUTCOffset()
 /*
  * Get the DST offset for the time passed in.
  */
-static double calculateDSTOffsetSimple(double localTimeSeconds, double utcOffset)
+static double calculateDSTOffset(time_t localTime, double utcOffset)
 {
-    if (localTimeSeconds > maxUnixTime)
-        localTimeSeconds = maxUnixTime;
-    else if (localTimeSeconds < 0) // Go ahead a day to make localtime work (does not work with 0)
-        localTimeSeconds += secondsPerDay;
-
     //input is UTC so we have to shift back to local time to determine DST thus the + getUTCOffset()
-    double offsetTime = (localTimeSeconds * msPerSecond) + utcOffset;
+    double offsetTime = (localTime * msPerSecond) + utcOffset;
 
     // Offset from UTC but doesn't include DST obviously
     int offsetHour =  msToHours(offsetTime);
     int offsetMinute =  msToMinutes(offsetTime);
 
-    // FIXME: time_t has a potential problem in 2038
-    time_t localTime = static_cast<time_t>(localTimeSeconds);
-
     tm localTM;
     getLocalTime(&localTime, &localTM);
 
@@ -428,10 +422,12 @@ static double calculateDSTOffsetSimple(double localTimeSeconds, double utcOffset
     return (diff * msPerSecond);
 }
 
-// Get the DST offset, given a time in UTC
-double calculateDSTOffset(double ms, double utcOffset)
+#endif
+
+// Returns combined offset in millisecond (UTC + DST).
+LocalTimeOffset calculateLocalTimeOffset(double ms)
 {
-    // On Mac OS X, the call to localtime (see calculateDSTOffsetSimple) will return historically accurate
+    // 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
@@ -447,7 +443,23 @@ double calculateDSTOffset(double ms, double utcOffset)
         ms = (day * msPerDay) + msToMilliseconds(ms);
     }
 
-    return calculateDSTOffsetSimple(ms / msPerSecond, utcOffset);
+    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 utcOffset = calculateUTCOffset();
+    double dstOffset = calculateDSTOffset(localTime, utcOffset);
+    return LocalTimeOffset(dstOffset, utcOffset + dstOffset);
+#endif
 }
 
 void initializeDates()
@@ -1026,11 +1038,8 @@ double parseDateFromNullTerminatedCharacters(const char* dateString)
         return std::numeric_limits<double>::quiet_NaN();
 
     // fall back to local timezone
-    if (!haveTZ) {
-        double utcOffset = calculateUTCOffset();
-        double dstOffset = calculateDSTOffset(ms, utcOffset);
-        offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute);
-    }
+    if (!haveTZ)
+        offset = calculateLocalTimeOffset(ms).offset / msPerMinute;
     return ms - (offset * msPerMinute);
 }
 
index 508fdc3..1ccb333 100644 (file)
@@ -101,8 +101,23 @@ WTF_EXPORT_PRIVATE int monthFromDayInYear(int dayInYear, bool leapYear);
 WTF_EXPORT_PRIVATE int dayInMonthFromDayInYear(int dayInYear, bool leapYear);
 
 // Returns offset milliseconds for UTC and DST.
-WTF_EXPORT_PRIVATE int32_t calculateUTCOffset();
-WTF_EXPORT_PRIVATE double calculateDSTOffset(double ms, double utcOffset);
+struct LocalTimeOffset {
+    LocalTimeOffset(bool isDST, int offset)
+        : isDST(isDST)
+        , offset(offset)
+    {
+    }
+
+    bool operator==(const LocalTimeOffset& other)
+    {
+        return isDST == other.isDST && offset == other.offset;
+    }
+
+    bool isDST;
+    int offset;
+};
+// Returns combined offset in millisecond (UTC + DST).
+WTF_EXPORT_PRIVATE LocalTimeOffset calculateLocalTimeOffset(double);
 
 } // namespace WTF
 
@@ -122,7 +137,7 @@ using WTF::msToHours;
 using WTF::secondsPerMinute;
 using WTF::parseDateFromNullTerminatedCharacters;
 using WTF::makeRFC2822DateString;
-using WTF::calculateUTCOffset;
-using WTF::calculateDSTOffset;
+using WTF::LocalTimeOffset;
+using WTF::calculateLocalTimeOffset;
 
 #endif // DateMath_h
index 61f73bf..5560984 100644 (file)
@@ -78,9 +78,7 @@ void GregorianDateTime::setToCurrentLocalTime()
 #if HAVE(TM_GMTOFF)
     m_utcOffset = localTM.tm_gmtoff;
 #else
-    int utcOffset = calculateUTCOffset();
-    utcOffset += calculateDSTOffset(localTime * msPerSecond, utcOffset);
-    m_utcOffset = utcOffset / msPerSecond;
+    m_utcOffset = calculateLocalTimeOffset(localTime * msPerSecond).offset / msPerSecond;
 #endif
 #endif
 }
index 5e46153..e87123a 100755 (executable)
@@ -781,6 +781,7 @@ com) : Patch to do not adjust cover rect as fixed pixel size*/
 #define ENABLE_TIZEN_JSC_CACHEFLUSH_PAGE_BY_PAGE 1 /* Hojong Han(hojong.han@samsung.com) : Fix YarrJIT crash */
 #define ENABLE_TIZEN_SET_PROPERTY_ATTRIBUTE_CORRECTLY 1 /* Hojong Han(hojong.han@samsung.com) : Fix overwritting Read-only property, set from WRT */
 #define ENABLE_TIZEN_JSC_SKIP_PROPERTY_TABLE_ERROR 1 /* Hojong Han(hojong.han@samsung.com) : Skip property table error */
+#define ENABLE_TIZEN_GENERATE_COMBINED_UTC_LOCAL 1 /* Hojong Han(hojong.han@samsung.com) : Simplify date handling code */
 
 #define ENABLE_TIZEN_WRT_LAUNCHING_PERFORMANCE 1 /* Byungwoo Lee(bw80.lee@samsung.com) : Local patches to enhance web app launching performance */
 
index 921fcdb..d0d4f26 100644 (file)
@@ -84,9 +84,13 @@ bool BaseDateAndTimeInputType::typeMismatch() const
 Decimal BaseDateAndTimeInputType::defaultValueForStepUp() const
 {
     double ms = currentTimeMS();
+#if ENABLE(TIZEN_GENERATE_COMBINED_UTC_LOCAL)
+    int offset = calculateLocalTimeOffset(ms).offset / msPerMinute;
+#else
     double utcOffset = calculateUTCOffset();
     double dstOffset = calculateDSTOffset(ms, utcOffset);
     int offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute);
+#endif
     return Decimal::fromDouble(ms + (offset * msPerMinute));
 }
 
index 70afa69..9deb4bc 100644 (file)
@@ -85,9 +85,13 @@ String MonthInputType::serializeWithMilliseconds(double value) const
 Decimal MonthInputType::defaultValueForStepUp() const
 {
     double current = currentTimeMS();
+#if ENABLE(TIZEN_GENERATE_COMBINED_UTC_LOCAL)
+    int offset = calculateLocalTimeOffset(current).offset / msPerMinute;
+#else
     double utcOffset = calculateUTCOffset();
     double dstOffset = calculateDSTOffset(current, utcOffset);
     int offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute);
+#endif
     current += offset * msPerMinute;
 
     DateComponents date;
index 052b887..7197412 100644 (file)
@@ -67,9 +67,13 @@ DateComponents::Type TimeInputType::dateType() const
 Decimal TimeInputType::defaultValueForStepUp() const
 {
     double current = currentTimeMS();
+#if ENABLE(TIZEN_GENERATE_COMBINED_UTC_LOCAL)
+    int offset = calculateLocalTimeOffset(current).offset / msPerMinute;
+#else
     double utcOffset = calculateUTCOffset();
     double dstOffset = calculateDSTOffset(current, utcOffset);
     int offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute);
+#endif
     current += offset * msPerMinute;
 
     DateComponents date;