From 6a7f06d70e1267d3d995a3c863ba8f748d45e531 Mon Sep 17 00:00:00 2001
From: Allan Sandfeld Jensen <allan.jensen@digia.com>
Date: Fri, 19 Sep 2014 16:24:44 +0400
Subject: [PATCH] Fix DateTime with recent versions of tzdata

An backport of http://trac.webkit.org/changeset/150833 needed for
correct time KRAT, YAKT and MOS timezones.

Task-number: QTBUG-41422
Change-Id: I6e9d1db690fee8d77faa1d76c836bd7b345ce854
Reviewed-by: Jocelyn Turcotte <jocelyn.turcotte@digia.com>
---
 .../JavaScriptCore/runtime/DateConstructor.cpp     |   6 +-
 .../JavaScriptCore/runtime/JSGlobalData.cpp        |   4 +-
 .../JavaScriptCore/runtime/JSGlobalData.h          |  18 +--
 .../javascriptcore/JavaScriptCore/wtf/DateMath.cpp | 135 ++++++++++-----------
 .../javascriptcore/JavaScriptCore/wtf/DateMath.h   |  60 ++++-----
 .../JavaScriptCore/runtime/DateConstructor.cpp     |   6 +-
 .../Source/JavaScriptCore/runtime/JSGlobalData.cpp |   4 +-
 .../Source/JavaScriptCore/runtime/JSGlobalData.h   |  18 +--
 .../webkit/Source/JavaScriptCore/wtf/DateMath.cpp  | 135 ++++++++++-----------
 .../webkit/Source/JavaScriptCore/wtf/DateMath.h    |  64 +++++-----
 .../WebCore/html/BaseDateAndTimeInputType.cpp      |   4 +-
 .../webkit/Source/WebCore/html/MonthInputType.cpp  |   4 +-
 .../webkit/Source/WebCore/html/TimeInputType.cpp   |   4 +-
 13 files changed, 218 insertions(+), 244 deletions(-)

diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConstructor.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConstructor.cpp
index e9a5c29..532eedb 100644
--- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConstructor.cpp
+++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/DateConstructor.cpp
@@ -129,10 +129,8 @@ ConstructType DateConstructor::getConstructData(ConstructData& constructData)
 // ECMA 15.9.2
 static JSValue JSC_HOST_CALL callDate(ExecState* exec, JSObject*, JSValue, const ArgList&)
 {
-    time_t localTime = time(0);
-    tm localTM;
-    getLocalTime(&localTime, &localTM);
-    GregorianDateTime ts(exec, localTM);
+    GregorianDateTime ts;
+    msToGregorianDateTime(exec, currentTimeMS(), false, ts);
     DateConversionBuffer date;
     DateConversionBuffer time;
     formatDate(ts, date);
diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalData.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalData.cpp
index 1c25c16..f90d495 100644
--- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalData.cpp
+++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalData.cpp
@@ -143,7 +143,6 @@ JSGlobalData::JSGlobalData(bool isShared)
     , functionCodeBlockBeingReparsed(0)
     , firstStringifierToMark(0)
     , markStack(jsArrayVPtr)
-    , cachedUTCOffset(NaN)
 #ifndef NDEBUG
     , mainThreadOnly(false)
 #endif
@@ -259,8 +258,7 @@ JSGlobalData::ClientData::~ClientData()
 
 void JSGlobalData::resetDateCache()
 {
-    cachedUTCOffset = NaN;
-    dstOffsetCache.reset();
+    localTimeOffsetCache.reset();
     cachedDateString = UString();
     dateInstanceCache.reset();
 }
diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalData.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalData.h
index dcd3289..fc60b84 100644
--- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalData.h
+++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSGlobalData.h
@@ -39,6 +39,7 @@
 #include "SmallStrings.h"
 #include "TimeoutChecker.h"
 #include "WeakRandom.h"
+#include <wtf/DateMath.h>
 #include <wtf/Forward.h>
 #include <wtf/HashMap.h>
 #include <wtf/RefCounted.h>
@@ -63,21 +64,23 @@ namespace JSC {
     struct HashTable;
     struct Instruction;    
 
-    struct DSTOffsetCache {
-        DSTOffsetCache()
+    struct LocalTimeOffsetCache {
+        LocalTimeOffsetCache()
+            : start(0.0)
+            , end(-1.0)
+            , increment(0.0)
         {
-            reset();
         }
-        
+
         void reset()
         {
-            offset = 0.0;
+            offset = LocalTimeOffset();
             start = 0.0;
             end = -1.0;
             increment = 0.0;
         }
 
-        double offset;
+        LocalTimeOffset offset;
         double start;
         double end;
         double increment;
@@ -179,8 +182,7 @@ namespace JSC {
 
         MarkStack markStack;
 
-        double cachedUTCOffset;
-        DSTOffsetCache dstOffsetCache;
+        LocalTimeOffsetCache localTimeOffsetCache;
         
         UString cachedDateString;
         double cachedDateStringValue;
diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/wtf/DateMath.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/wtf/DateMath.cpp
index b9a0207..e72f94b 100644
--- a/src/3rdparty/javascriptcore/JavaScriptCore/wtf/DateMath.cpp
+++ b/src/3rdparty/javascriptcore/JavaScriptCore/wtf/DateMath.cpp
@@ -377,6 +377,8 @@ int equivalentYearForDST(int year)
     return year;
 }
 
+#if !HAVE(TM_GMTOFF)
+
 static int32_t calculateUTCOffset()
 {
 #if PLATFORM(BREWMP)
@@ -418,23 +420,15 @@ static 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);
 
@@ -446,10 +440,12 @@ static double calculateDSTOffsetSimple(double localTimeSeconds, double utcOffset
     return (diff * msPerSecond);
 }
 
-// Get the DST offset, given a time in UTC
-static 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
@@ -465,7 +461,23 @@ static 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()
@@ -838,11 +850,9 @@ double parseDateFromNullTerminatedCharacters(const char* dateString)
         return 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);
 }
 
@@ -859,14 +869,14 @@ double timeClip(double t)
 #if USE(JSC)
 namespace JSC {
 
-// 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(ExecState* exec, double ms)
 {
-    DSTOffsetCache& cache = exec->globalData().dstOffsetCache;
+    LocalTimeOffsetCache& cache = exec->globalData().localTimeOffsetCache;
     double start = cache.start;
     double end = cache.end;
 
@@ -878,7 +888,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
@@ -886,34 +896,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;
@@ -921,30 +930,14 @@ 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 + 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);
-    }
+    if (!inputIsUTC)
+        result -= localTimeOffset(exec, result).offset;
 
     return result;
 }
@@ -952,12 +945,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 localTime(false, 0);
     if (!outputIsUTC) {
-        utcOff = getUTCOffset(exec);
-        dstOff = getDSTOffset(exec, ms, utcOff);
-        ms += dstOff + utcOff;
+        localTime = localTimeOffset(exec, ms);
+        ms += localTime.offset;
     }
 
     const int year = msToYear(ms);
@@ -969,8 +960,8 @@ void msToGregorianDateTime(ExecState* exec, double ms, bool outputIsUTC, Gregori
     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.isDST    =  localTime.isDST;
+    tm.utcOffset = localTime.offset / WTF::msPerSecond;
     tm.timeZone = NULL;
 }
 
@@ -984,11 +975,9 @@ double parseDateFromNullTerminatedCharacters(ExecState* exec, const char* dateSt
         return 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 = calculateLocalTimeOffset(ms).offset / msPerMinute;
+
     return ms - (offset * WTF::msPerMinute);
 }
 
diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/wtf/DateMath.h b/src/3rdparty/javascriptcore/JavaScriptCore/wtf/DateMath.h
index 033d25e..15a19bd 100644
--- a/src/3rdparty/javascriptcore/JavaScriptCore/wtf/DateMath.h
+++ b/src/3rdparty/javascriptcore/JavaScriptCore/wtf/DateMath.h
@@ -50,6 +50,34 @@
 #include <wtf/UnusedParam.h>
 
 namespace WTF {
+
+struct LocalTimeOffset {
+    LocalTimeOffset()
+        : isDST(false)
+        , offset(0)
+    {
+    }
+
+    LocalTimeOffset(bool isDST, int offset)
+        : isDST(isDST)
+        , offset(offset)
+    {
+    }
+
+    bool operator==(const LocalTimeOffset& other)
+    {
+        return isDST == other.isDST && offset == other.offset;
+    }
+
+    bool operator!=(const LocalTimeOffset& other)
+    {
+        return isDST != other.isDST || offset != other.offset;
+    }
+
+    bool isDST;
+    int offset;
+};
+
 void initializeDates();
 int equivalentYearForDST(int year);
 
@@ -83,6 +111,9 @@ int dayInYear(double ms, int year);
 int monthFromDayInYear(int dayInYear, bool leapYear);
 int dayInMonthFromDayInYear(int dayInYear, bool leapYear);
 
+// Returns combined offset in millisecond (UTC + DST).
+LocalTimeOffset calculateLocalTimeOffset(double utcInMilliseconds);
+
 } // namespace WTF
 
 using WTF::dateToDaysFrom1970;
@@ -94,6 +125,8 @@ using WTF::msPerDay;
 using WTF::msPerSecond;
 using WTF::msToYear;
 using WTF::secondsPerMinute;
+using WTF::LocalTimeOffset;
+using WTF::calculateLocalTimeOffset;
 
 #if USE(JSC)
 namespace JSC {
@@ -128,33 +161,6 @@ struct GregorianDateTime : Noncopyable {
         delete [] timeZone;
     }
 
-    GregorianDateTime(ExecState* exec, const tm& inTm)
-        : second(inTm.tm_sec)
-        , minute(inTm.tm_min)
-        , hour(inTm.tm_hour)
-        , weekDay(inTm.tm_wday)
-        , monthDay(inTm.tm_mday)
-        , yearDay(inTm.tm_yday)
-        , month(inTm.tm_mon)
-        , year(inTm.tm_year)
-        , isDST(inTm.tm_isdst)
-    {
-        UNUSED_PARAM(exec);
-#if HAVE(TM_GMTOFF)
-        utcOffset = static_cast<int>(inTm.tm_gmtoff);
-#else
-        utcOffset = static_cast<int>(getUTCOffset(exec) / WTF::msPerSecond + (isDST ? WTF::secondsPerHour : 0));
-#endif
-
-#if HAVE(TM_ZONE)
-        int inZoneSize = strlen(inTm.tm_zone) + 1;
-        timeZone = new char[inZoneSize];
-        strncpy(timeZone, inTm.tm_zone, inZoneSize);
-#else
-        timeZone = 0;
-#endif
-    }
-
     operator tm() const
     {
         tm ret;
diff --git a/src/3rdparty/webkit/Source/JavaScriptCore/runtime/DateConstructor.cpp b/src/3rdparty/webkit/Source/JavaScriptCore/runtime/DateConstructor.cpp
index 9bbb688..5f44d2c 100644
--- a/src/3rdparty/webkit/Source/JavaScriptCore/runtime/DateConstructor.cpp
+++ b/src/3rdparty/webkit/Source/JavaScriptCore/runtime/DateConstructor.cpp
@@ -139,10 +139,8 @@ ConstructType DateConstructor::getConstructData(ConstructData& constructData)
 // ECMA 15.9.2
 static EncodedJSValue JSC_HOST_CALL callDate(ExecState* exec)
 {
-    time_t localTime = time(0);
-    tm localTM;
-    getLocalTime(&localTime, &localTM);
-    GregorianDateTime ts(exec, localTM);
+    GregorianDateTime ts;
+    msToGregorianDateTime(exec, currentTimeMS(), false, ts);
     DateConversionBuffer date;
     DateConversionBuffer time;
     formatDate(ts, date);
diff --git a/src/3rdparty/webkit/Source/JavaScriptCore/runtime/JSGlobalData.cpp b/src/3rdparty/webkit/Source/JavaScriptCore/runtime/JSGlobalData.cpp
index 61bbea0..8ddb7d2 100644
--- a/src/3rdparty/webkit/Source/JavaScriptCore/runtime/JSGlobalData.cpp
+++ b/src/3rdparty/webkit/Source/JavaScriptCore/runtime/JSGlobalData.cpp
@@ -165,7 +165,6 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread
     , heap(this)
     , globalObjectCount(0)
     , dynamicGlobalObject(0)
-    , cachedUTCOffset(NaN)
     , maxReentryDepth(threadStackType == ThreadStackTypeSmall ? MaxSmallThreadReentryDepth : MaxLargeThreadReentryDepth)
     , m_regExpCache(new RegExpCache(this))
 #if ENABLE(REGEXP_TRACING)
@@ -377,8 +376,7 @@ JSGlobalData::ClientData::~ClientData()
 
 void JSGlobalData::resetDateCache()
 {
-    cachedUTCOffset = NaN;
-    dstOffsetCache.reset();
+    localTimeOffsetCache.reset();
     cachedDateString = UString();
     cachedDateStringValue = NaN;
     dateInstanceCache.reset();
diff --git a/src/3rdparty/webkit/Source/JavaScriptCore/runtime/JSGlobalData.h b/src/3rdparty/webkit/Source/JavaScriptCore/runtime/JSGlobalData.h
index df36016..6df6390 100644
--- a/src/3rdparty/webkit/Source/JavaScriptCore/runtime/JSGlobalData.h
+++ b/src/3rdparty/webkit/Source/JavaScriptCore/runtime/JSGlobalData.h
@@ -42,6 +42,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/RefCounted.h>
@@ -77,21 +78,23 @@ namespace JSC {
     struct HashTable;
     struct Instruction;
 
-    struct DSTOffsetCache {
-        DSTOffsetCache()
+    struct LocalTimeOffsetCache {
+        LocalTimeOffsetCache()
+            : start(0.0)
+            , end(-1.0)
+            , increment(0.0)
         {
-            reset();
         }
-        
+
         void reset()
         {
-            offset = 0.0;
+            offset = LocalTimeOffset();
             start = 0.0;
             end = -1.0;
             increment = 0.0;
         }
 
-        double offset;
+        LocalTimeOffset offset;
         double start;
         double end;
         double increment;
@@ -233,8 +236,7 @@ namespace JSC {
 
         HashSet<JSObject*> stringRecursionCheckVisitedObjects;
 
-        double cachedUTCOffset;
-        DSTOffsetCache dstOffsetCache;
+        LocalTimeOffsetCache localTimeOffsetCache;
         
         UString cachedDateString;
         double cachedDateStringValue;
diff --git a/src/3rdparty/webkit/Source/JavaScriptCore/wtf/DateMath.cpp b/src/3rdparty/webkit/Source/JavaScriptCore/wtf/DateMath.cpp
index b181ee2..d13042b 100644
--- a/src/3rdparty/webkit/Source/JavaScriptCore/wtf/DateMath.cpp
+++ b/src/3rdparty/webkit/Source/JavaScriptCore/wtf/DateMath.cpp
@@ -385,6 +385,8 @@ int equivalentYearForDST(int year)
     return year;
 }
 
+#if !HAVE(TM_GMTOFF)
+
 int32_t calculateUTCOffset()
 {
 #if PLATFORM(BREWMP)
@@ -426,23 +428,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);
 
@@ -454,10 +448,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
@@ -473,7 +469,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()
@@ -1002,11 +1014,9 @@ double parseDateFromNullTerminatedCharacters(const char* dateString)
         return 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);
 }
 
@@ -1023,14 +1033,14 @@ double timeClip(double t)
 #if USE(JSC)
 namespace JSC {
 
-// 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(ExecState* exec, double ms)
 {
-    DSTOffsetCache& cache = exec->globalData().dstOffsetCache;
+    LocalTimeOffsetCache& cache = exec->globalData().localTimeOffsetCache;
     double start = cache.start;
     double end = cache.end;
 
@@ -1042,7 +1052,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
@@ -1050,34 +1060,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;
@@ -1085,30 +1094,14 @@ 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 + 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);
-    }
+    if (!inputIsUTC)
+        result -= localTimeOffset(exec, result).offset;
 
     return result;
 }
@@ -1116,12 +1109,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 localTime(false, 0);
     if (!outputIsUTC) {
-        utcOff = getUTCOffset(exec);
-        dstOff = getDSTOffset(exec, ms, utcOff);
-        ms += dstOff + utcOff;
+        localTime = localTimeOffset(exec, ms);
+        ms += localTime.offset;
     }
 
     const int year = msToYear(ms);
@@ -1133,8 +1124,8 @@ void msToGregorianDateTime(ExecState* exec, double ms, bool outputIsUTC, Gregori
     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.isDST    =  localTime.isDST;
+    tm.utcOffset = localTime.offset / WTF::msPerSecond;
     tm.timeZone = nullptr;
 }
 
@@ -1148,11 +1139,9 @@ double parseDateFromNullTerminatedCharacters(ExecState* exec, const char* dateSt
         return 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 = calculateLocalTimeOffset(ms).offset / msPerMinute;
+
     return ms - (offset * WTF::msPerMinute);
 }
 
diff --git a/src/3rdparty/webkit/Source/JavaScriptCore/wtf/DateMath.h b/src/3rdparty/webkit/Source/JavaScriptCore/wtf/DateMath.h
index 2ac284e..bb59c8d 100644
--- a/src/3rdparty/webkit/Source/JavaScriptCore/wtf/DateMath.h
+++ b/src/3rdparty/webkit/Source/JavaScriptCore/wtf/DateMath.h
@@ -54,6 +54,34 @@
 #include <wtf/UnusedParam.h>
 
 namespace WTF {
+
+struct LocalTimeOffset {
+    LocalTimeOffset()
+        : isDST(false)
+        , offset(0)
+    {
+    }
+
+    LocalTimeOffset(bool isDST, int offset)
+        : isDST(isDST)
+        , offset(offset)
+    {
+    }
+
+    bool operator==(const LocalTimeOffset& other)
+    {
+        return isDST == other.isDST && offset == other.offset;
+    }
+
+    bool operator!=(const LocalTimeOffset& other)
+    {
+        return isDST != other.isDST || offset != other.offset;
+    }
+
+    bool isDST;
+    int offset;
+};
+
 void initializeDates();
 int equivalentYearForDST(int year);
 
@@ -88,9 +116,8 @@ int dayInYear(double ms, int year);
 int monthFromDayInYear(int dayInYear, bool leapYear);
 int dayInMonthFromDayInYear(int dayInYear, bool leapYear);
 
-// Returns offset milliseconds for UTC and DST.
-int32_t calculateUTCOffset();
-double calculateDSTOffset(double ms, double utcOffset);
+// Returns combined offset in millisecond (UTC + DST).
+LocalTimeOffset calculateLocalTimeOffset(double utcInMilliseconds);
 
 } // namespace WTF
 
@@ -106,8 +133,8 @@ using WTF::msPerSecond;
 using WTF::msToYear;
 using WTF::secondsPerMinute;
 using WTF::parseDateFromNullTerminatedCharacters;
-using WTF::calculateUTCOffset;
-using WTF::calculateDSTOffset;
+using WTF::LocalTimeOffset;
+using WTF::calculateLocalTimeOffset;
 
 #if USE(JSC)
 namespace JSC {
@@ -138,33 +165,6 @@ public:
     {
     }
 
-    GregorianDateTime(ExecState* exec, const tm& inTm)
-        : second(inTm.tm_sec)
-        , minute(inTm.tm_min)
-        , hour(inTm.tm_hour)
-        , weekDay(inTm.tm_wday)
-        , monthDay(inTm.tm_mday)
-        , yearDay(inTm.tm_yday)
-        , month(inTm.tm_mon)
-        , year(inTm.tm_year)
-        , isDST(inTm.tm_isdst)
-    {
-        UNUSED_PARAM(exec);
-#if HAVE(TM_GMTOFF)
-        utcOffset = static_cast<int>(inTm.tm_gmtoff);
-#else
-        utcOffset = static_cast<int>(getUTCOffset(exec) / WTF::msPerSecond + (isDST ? WTF::secondsPerHour : 0));
-#endif
-
-#if HAVE(TM_ZONE)
-        int inZoneSize = strlen(inTm.tm_zone) + 1;
-        timeZone = adoptArrayPtr(new char[inZoneSize]);
-        strncpy(timeZone.get(), inTm.tm_zone, inZoneSize);
-#else
-        timeZone = nullptr;
-#endif
-    }
-
     operator tm() const
     {
         tm ret;
diff --git a/src/3rdparty/webkit/Source/WebCore/html/BaseDateAndTimeInputType.cpp b/src/3rdparty/webkit/Source/WebCore/html/BaseDateAndTimeInputType.cpp
index e52c103..e24379a 100644
--- a/src/3rdparty/webkit/Source/WebCore/html/BaseDateAndTimeInputType.cpp
+++ b/src/3rdparty/webkit/Source/WebCore/html/BaseDateAndTimeInputType.cpp
@@ -102,9 +102,7 @@ bool BaseDateAndTimeInputType::supportsRangeLimitation() const
 double BaseDateAndTimeInputType::defaultValueForStepUp() const
 {
     double ms = currentTimeMS();
-    double utcOffset = calculateUTCOffset();
-    double dstOffset = calculateDSTOffset(ms, utcOffset);
-    int offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute);
+    int offset = calculateLocalTimeOffset(ms).offset / msPerMinute;
     return ms + (offset * msPerMinute);
 }
 
diff --git a/src/3rdparty/webkit/Source/WebCore/html/MonthInputType.cpp b/src/3rdparty/webkit/Source/WebCore/html/MonthInputType.cpp
index 06e3726..9390a07 100644
--- a/src/3rdparty/webkit/Source/WebCore/html/MonthInputType.cpp
+++ b/src/3rdparty/webkit/Source/WebCore/html/MonthInputType.cpp
@@ -82,9 +82,7 @@ String MonthInputType::serializeWithMilliseconds(double value) const
 double MonthInputType::defaultValueForStepUp() const
 {
     double current = currentTimeMS();
-    double utcOffset = calculateUTCOffset();
-    double dstOffset = calculateDSTOffset(current, utcOffset);
-    int offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute);
+    int offset = calculateLocalTimeOffset(current).offset / msPerMinute;
     current += offset * msPerMinute;
 
     DateComponents date;
diff --git a/src/3rdparty/webkit/Source/WebCore/html/TimeInputType.cpp b/src/3rdparty/webkit/Source/WebCore/html/TimeInputType.cpp
index f89ec33..bbfc86d 100644
--- a/src/3rdparty/webkit/Source/WebCore/html/TimeInputType.cpp
+++ b/src/3rdparty/webkit/Source/WebCore/html/TimeInputType.cpp
@@ -64,9 +64,7 @@ DateComponents::Type TimeInputType::dateType() const
 double TimeInputType::defaultValueForStepUp() const
 {
     double current = currentTimeMS();
-    double utcOffset = calculateUTCOffset();
-    double dstOffset = calculateDSTOffset(current, utcOffset);
-    int offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute);
+    int offset = calculateLocalTimeOffset(current).offset / msPerMinute;
     current += offset * msPerMinute;
 
     DateComponents date;
-- 
2.0.4

