From: Carlos Garcia Campos <carlosgc@webkit.org>
Subject: String(new Date(Mar 30 2014 01:00:00)) is wrong in CET
Bug: https://bugs.webkit.org/show_bug.cgi?id=130967
Origin: http://trac.webkit.org/changeset/175904
Index: webkitgtk/Source/JavaScriptCore/runtime/DateConstructor.cpp
===================================================================
--- webkitgtk.orig/Source/JavaScriptCore/runtime/DateConstructor.cpp
+++ webkitgtk/Source/JavaScriptCore/runtime/DateConstructor.cpp
@@ -166,7 +166,7 @@ JSObject* constructDate(ExecState* exec,
             t.setSecond(JSC::toInt32(doubleArguments[5]));
             t.setIsDST(-1);
             double ms = (numArgs >= 7) ? doubleArguments[6] : 0;
-            value = gregorianDateTimeToMS(vm, t, ms, false);
+            value = gregorianDateTimeToMS(vm, t, ms, WTF::LocalTime);
         }
     }
 
@@ -190,7 +190,7 @@ static EncodedJSValue JSC_HOST_CALL call
 {
     VM& vm = exec->vm();
     GregorianDateTime ts;
-    msToGregorianDateTime(vm, currentTimeMS(), false, ts);
+    msToGregorianDateTime(vm, currentTimeMS(), WTF::LocalTime, ts);
     return JSValue::encode(jsNontrivialString(&vm, formatDateTime(ts, DateTimeFormatDateAndTime, false)));
 }
 
@@ -244,7 +244,7 @@ EncodedJSValue JSC_HOST_CALL dateUTC(Exe
     t.setMinute(JSC::toInt32(doubleArguments[4]));
     t.setSecond(JSC::toInt32(doubleArguments[5]));
     double ms = (n >= 7) ? doubleArguments[6] : 0;
-    return JSValue::encode(jsNumber(timeClip(gregorianDateTimeToMS(exec->vm(), t, ms, true))));
+    return JSValue::encode(jsNumber(timeClip(gregorianDateTimeToMS(exec->vm(), t, ms, WTF::UTCTime))));
 }
 
 } // namespace JSC
Index: webkitgtk/Source/JavaScriptCore/runtime/DateInstance.cpp
===================================================================
--- webkitgtk.orig/Source/JavaScriptCore/runtime/DateInstance.cpp
+++ webkitgtk/Source/JavaScriptCore/runtime/DateInstance.cpp
@@ -69,7 +69,7 @@ const GregorianDateTime* DateInstance::c
         m_data = vm.dateInstanceCache.add(milli);
 
     if (m_data->m_gregorianDateTimeCachedForMS != milli) {
-        msToGregorianDateTime(vm, milli, false, m_data->m_cachedGregorianDateTime);
+        msToGregorianDateTime(vm, milli, WTF::LocalTime, m_data->m_cachedGregorianDateTime);
         m_data->m_gregorianDateTimeCachedForMS = milli;
     }
     return &m_data->m_cachedGregorianDateTime;
@@ -86,7 +86,7 @@ const GregorianDateTime* DateInstance::c
         m_data = vm.dateInstanceCache.add(milli);
 
     if (m_data->m_gregorianDateTimeUTCCachedForMS != milli) {
-        msToGregorianDateTime(vm, milli, true, m_data->m_cachedGregorianDateTimeUTC);
+        msToGregorianDateTime(vm, milli, WTF::UTCTime, m_data->m_cachedGregorianDateTimeUTC);
         m_data->m_gregorianDateTimeUTCCachedForMS = milli;
     }
     return &m_data->m_cachedGregorianDateTimeUTC;
Index: webkitgtk/Source/JavaScriptCore/runtime/DatePrototype.cpp
===================================================================
--- webkitgtk.orig/Source/JavaScriptCore/runtime/DatePrototype.cpp
+++ webkitgtk/Source/JavaScriptCore/runtime/DatePrototype.cpp
@@ -859,7 +859,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFu
     return JSValue::encode(result);
 }
 
-static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC)
+static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, WTF::TimeType inputTimeType)
 {
     JSValue thisValue = exec->thisValue();
     if (!thisValue.inherits(DateInstance::info()))
@@ -878,7 +878,7 @@ static EncodedJSValue setNewValueFromTim
     double secs = floor(milli / msPerSecond);
     double ms = milli - secs * msPerSecond;
 
-    const GregorianDateTime* other = inputIsUTC 
+    const GregorianDateTime* other = inputTimeType == WTF::UTCTime
         ? thisDateObj->gregorianDateTimeUTC(exec)
         : thisDateObj->gregorianDateTime(exec);
     if (!other)
@@ -892,12 +892,12 @@ static EncodedJSValue setNewValueFromTim
         return JSValue::encode(result);
     } 
     
-    JSValue result = jsNumber(gregorianDateTimeToMS(vm, gregorianDateTime, ms, inputIsUTC));
+    JSValue result = jsNumber(gregorianDateTimeToMS(vm, gregorianDateTime, ms, inputTimeType));
     thisDateObj->setInternalValue(vm, result);
     return JSValue::encode(result);
 }
 
-static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC)
+static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, WTF::TimeType inputTimeType)
 {
     JSValue thisValue = exec->thisValue();
     if (!thisValue.inherits(DateInstance::info()))
@@ -916,10 +916,10 @@ static EncodedJSValue setNewValueFromDat
 
     GregorianDateTime gregorianDateTime; 
     if (numArgsToUse == 3 && std::isnan(milli)) 
-        msToGregorianDateTime(vm, 0, true, gregorianDateTime);
+        msToGregorianDateTime(vm, 0, WTF::UTCTime, gregorianDateTime);
     else { 
         ms = milli - floor(milli / msPerSecond) * msPerSecond; 
-        const GregorianDateTime* other = inputIsUTC 
+        const GregorianDateTime* other = inputTimeType == WTF::UTCTime
             ? thisDateObj->gregorianDateTimeUTC(exec)
             : thisDateObj->gregorianDateTime(exec);
         if (!other)
@@ -933,93 +933,93 @@ static EncodedJSValue setNewValueFromDat
         return JSValue::encode(result);
     } 
            
-    JSValue result = jsNumber(gregorianDateTimeToMS(vm, gregorianDateTime, ms, inputIsUTC));
+    JSValue result = jsNumber(gregorianDateTimeToMS(vm, gregorianDateTime, ms, inputTimeType));
     thisDateObj->setInternalValue(vm, result);
     return JSValue::encode(result);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState* exec)
 {
-    const bool inputIsUTC = false;
-    return setNewValueFromTimeArgs(exec, 1, inputIsUTC);
+    const WTF::TimeType inputTimeType = WTF::LocalTime;
+    return setNewValueFromTimeArgs(exec, 1, inputTimeType);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState* exec)
 {
-    const bool inputIsUTC = true;
-    return setNewValueFromTimeArgs(exec, 1, inputIsUTC);
+    const WTF::TimeType inputTimeType = WTF::UTCTime;
+    return setNewValueFromTimeArgs(exec, 1, inputTimeType);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState* exec)
 {
-    const bool inputIsUTC = false;
-    return setNewValueFromTimeArgs(exec, 2, inputIsUTC);
+    const WTF::TimeType inputTimeType = WTF::LocalTime;
+    return setNewValueFromTimeArgs(exec, 2, inputTimeType);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState* exec)
 {
-    const bool inputIsUTC = true;
-    return setNewValueFromTimeArgs(exec, 2, inputIsUTC);
+    const WTF::TimeType inputTimeType = WTF::UTCTime;
+    return setNewValueFromTimeArgs(exec, 2, inputTimeType);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState* exec)
 {
-    const bool inputIsUTC = false;
-    return setNewValueFromTimeArgs(exec, 3, inputIsUTC);
+    const WTF::TimeType inputTimeType = WTF::LocalTime;
+    return setNewValueFromTimeArgs(exec, 3, inputTimeType);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState* exec)
 {
-    const bool inputIsUTC = true;
-    return setNewValueFromTimeArgs(exec, 3, inputIsUTC);
+    const WTF::TimeType inputTimeType = WTF::UTCTime;
+    return setNewValueFromTimeArgs(exec, 3, inputTimeType);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState* exec)
 {
-    const bool inputIsUTC = false;
-    return setNewValueFromTimeArgs(exec, 4, inputIsUTC);
+    const WTF::TimeType inputTimeType = WTF::LocalTime;
+    return setNewValueFromTimeArgs(exec, 4, inputTimeType);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState* exec)
 {
-    const bool inputIsUTC = true;
-    return setNewValueFromTimeArgs(exec, 4, inputIsUTC);
+    const WTF::TimeType inputTimeType = WTF::UTCTime;
+    return setNewValueFromTimeArgs(exec, 4, inputTimeType);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState* exec)
 {
-    const bool inputIsUTC = false;
-    return setNewValueFromDateArgs(exec, 1, inputIsUTC);
+    const WTF::TimeType inputTimeType = WTF::LocalTime;
+    return setNewValueFromDateArgs(exec, 1, inputTimeType);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState* exec)
 {
-    const bool inputIsUTC = true;
-    return setNewValueFromDateArgs(exec, 1, inputIsUTC);
+    const WTF::TimeType inputTimeType = WTF::UTCTime;
+    return setNewValueFromDateArgs(exec, 1, inputTimeType);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState* exec)
 {
-    const bool inputIsUTC = false;
-    return setNewValueFromDateArgs(exec, 2, inputIsUTC);
+    const WTF::TimeType inputTimeType = WTF::LocalTime;
+    return setNewValueFromDateArgs(exec, 2, inputTimeType);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState* exec)
 {
-    const bool inputIsUTC = true;
-    return setNewValueFromDateArgs(exec, 2, inputIsUTC);
+    const WTF::TimeType inputTimeType = WTF::UTCTime;
+    return setNewValueFromDateArgs(exec, 2, inputTimeType);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState* exec)
 {
-    const bool inputIsUTC = false;
-    return setNewValueFromDateArgs(exec, 3, inputIsUTC);
+    const WTF::TimeType inputTimeType = WTF::LocalTime;
+    return setNewValueFromDateArgs(exec, 3, inputTimeType);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState* exec)
 {
-    const bool inputIsUTC = true;
-    return setNewValueFromDateArgs(exec, 3, inputIsUTC);
+    const WTF::TimeType inputTimeType = WTF::UTCTime;
+    return setNewValueFromDateArgs(exec, 3, inputTimeType);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec)
@@ -1043,7 +1043,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFu
     if (std::isnan(milli))
         // Based on ECMA 262 B.2.5 (setYear)
         // the time must be reset to +0 if it is NaN.
-        msToGregorianDateTime(vm, 0, true, gregorianDateTime);
+        msToGregorianDateTime(vm, 0, WTF::UTCTime, gregorianDateTime);
     else {
         double secs = floor(milli / msPerSecond);
         ms = milli - secs * msPerSecond;
@@ -1059,7 +1059,7 @@ EncodedJSValue JSC_HOST_CALL dateProtoFu
     }
 
     gregorianDateTime.setYear(toInt32((year >= 0 && year <= 99) ? (year + 1900) : year));
-    JSValue result = jsNumber(gregorianDateTimeToMS(vm, gregorianDateTime, ms, false));
+    JSValue result = jsNumber(gregorianDateTimeToMS(vm, gregorianDateTime, ms, WTF::LocalTime));
     thisDateObj->setInternalValue(vm, result);
     return JSValue::encode(result);
 }
Index: webkitgtk/Source/JavaScriptCore/runtime/JSDateMath.cpp
===================================================================
--- webkitgtk.orig/Source/JavaScriptCore/runtime/JSDateMath.cpp
+++ webkitgtk/Source/JavaScriptCore/runtime/JSDateMath.cpp
@@ -132,13 +132,14 @@ static inline int msToWeekDay(double ms)
 // 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 LocalTimeOffset localTimeOffset(VM& vm, double ms)
+static LocalTimeOffset localTimeOffset(VM& vm, double ms, WTF::TimeType inputTimeType = WTF::UTCTime)
 {
     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;
 
@@ -146,7 +147,7 @@ static LocalTimeOffset localTimeOffset(V
         double newEnd = end + cache.increment;
 
         if (ms <= newEnd) {
-            LocalTimeOffset endOffset = calculateLocalTimeOffset(newEnd);
+            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
@@ -155,7 +156,7 @@ static LocalTimeOffset localTimeOffset(V
                 cache.increment = msPerMonth;
                 return endOffset;
             }
-            LocalTimeOffset offset = calculateLocalTimeOffset(ms);
+            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
@@ -180,31 +181,31 @@ static LocalTimeOffset localTimeOffset(V
     // 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.
-    LocalTimeOffset offset = calculateLocalTimeOffset(ms);
+    LocalTimeOffset offset = calculateLocalTimeOffset(ms, inputTimeType);
     cache.offset = offset;
     cache.start = ms;
     cache.end = ms;
     cache.increment = msPerMonth;
+    cache.timeType = inputTimeType;
     return offset;
 }
 
-double gregorianDateTimeToMS(VM& vm, const GregorianDateTime& t, double milliSeconds, bool inputIsUTC)
+double gregorianDateTimeToMS(VM& vm, const GregorianDateTime& t, double milliSeconds, WTF::TimeType inputTimeType)
 {
     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;
+    double localTimeResult = (day * WTF::msPerDay) + ms;
+    double localToUTCTimeOffset = inputTimeType == LocalTime
+        ? localTimeOffset(vm, localTimeResult, inputTimeType).offset : 0;
 
-    if (!inputIsUTC)
-        result -= localTimeOffset(vm, result).offset;
-
-    return result;
+    return localTimeResult - localToUTCTimeOffset;
 }
 
 // input is UTC
-void msToGregorianDateTime(VM& vm, double ms, bool outputIsUTC, GregorianDateTime& tm)
+void msToGregorianDateTime(VM& vm, double ms, WTF::TimeType outputTimeType, GregorianDateTime& tm)
 {
     LocalTimeOffset localTime;
-    if (!outputIsUTC) {
+    if (outputTimeType == WTF::LocalTime) {
         localTime = localTimeOffset(vm, ms);
         ms += localTime.offset;
     }
@@ -226,15 +227,15 @@ double parseDateFromNullTerminatedCharac
 {
     bool haveTZ;
     int offset;
-    double ms = WTF::parseDateFromNullTerminatedCharacters(dateString, haveTZ, offset);
-    if (std::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
+    // fall back to local timezone.
     if (!haveTZ)
-        offset = localTimeOffset(vm, ms).offset / WTF::msPerMinute;
+        offset = localTimeOffset(vm, localTimeMS, WTF::LocalTime).offset / WTF::msPerMinute;
 
-    return ms - (offset * WTF::msPerMinute);
+    return localTimeMS - (offset * WTF::msPerMinute);
 }
 
 double parseDate(VM& vm, const String& date)
Index: webkitgtk/Source/JavaScriptCore/runtime/JSDateMath.h
===================================================================
--- webkitgtk.orig/Source/JavaScriptCore/runtime/JSDateMath.h
+++ webkitgtk/Source/JavaScriptCore/runtime/JSDateMath.h
@@ -50,8 +50,8 @@ namespace JSC {
 
 class VM;
 
-JS_EXPORT_PRIVATE void msToGregorianDateTime(VM&, double, bool outputIsUTC, GregorianDateTime&);
-JS_EXPORT_PRIVATE double gregorianDateTimeToMS(VM&, const GregorianDateTime&, double, bool inputIsUTC);
+JS_EXPORT_PRIVATE void msToGregorianDateTime(VM&, double, WTF::TimeType outputTimeType, GregorianDateTime&);
+JS_EXPORT_PRIVATE double gregorianDateTimeToMS(VM&, const GregorianDateTime&, double, WTF::TimeType inputTimeType);
 JS_EXPORT_PRIVATE double getUTCOffset(VM&);
 JS_EXPORT_PRIVATE double parseDateFromNullTerminatedCharacters(VM&, const char* dateString);
 JS_EXPORT_PRIVATE double parseDate(VM&, const WTF::String&);
Index: webkitgtk/Source/JavaScriptCore/runtime/VM.h
===================================================================
--- webkitgtk.orig/Source/JavaScriptCore/runtime/VM.h
+++ webkitgtk/Source/JavaScriptCore/runtime/VM.h
@@ -133,6 +133,7 @@ struct LocalTimeOffsetCache {
         : start(0.0)
         , end(-1.0)
         , increment(0.0)
+        , timeType(WTF::UTCTime)
     {
     }
 
@@ -142,12 +143,14 @@ struct LocalTimeOffsetCache {
         start = 0.0;
         end = -1.0;
         increment = 0.0;
+        timeType = WTF::UTCTime;
     }
 
     LocalTimeOffset offset;
     double start;
     double end;
     double increment;
+    WTF::TimeType timeType;
 };
 
 class ConservativeRoots;
Index: webkitgtk/Source/WTF/wtf/DateMath.cpp
===================================================================
--- webkitgtk.orig/Source/WTF/wtf/DateMath.cpp
+++ webkitgtk/Source/WTF/wtf/DateMath.cpp
@@ -363,8 +363,6 @@ int equivalentYearForDST(int year)
     return year;
 }
 
-#if !HAVE(TM_GMTOFF)
-
 static int32_t calculateUTCOffset()
 {
 #if OS(WINDOWS)
@@ -406,6 +404,8 @@ static int32_t calculateUTCOffset()
 #endif
 }
 
+#if !HAVE(TM_GMTOFF)
+
 #if OS(WINDOWS)
 // Code taken from http://support.microsoft.com/kb/167296
 static void UnixTimeToFileTime(time_t t, LPFILETIME pft)
@@ -467,8 +467,16 @@ static double calculateDSTOffset(time_t
 #endif
 
 // Returns combined offset in millisecond (UTC + DST).
-LocalTimeOffset calculateLocalTimeOffset(double ms)
+LocalTimeOffset calculateLocalTimeOffset(double ms, TimeType inputTimeType)
 {
+#if HAVE(TM_GMTOFF)
+    double localToUTCTimeOffset = inputTimeType == LocalTime ? calculateUTCOffset() : 0;
+#else
+    double localToUTCTimeOffset = calculateUTCOffset();
+#endif
+    if (inputTimeType == LocalTime)
+        ms -= localToUTCTimeOffset;
+
     // 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
@@ -498,9 +506,8 @@ LocalTimeOffset calculateLocalTimeOffset
     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);
+    double dstOffset = calculateDSTOffset(localTime, localToUTCTimeOffset);
+    return LocalTimeOffset(dstOffset, localToUTCTimeOffset + dstOffset);
 #endif
 }
 
@@ -1091,7 +1098,7 @@ double parseDateFromNullTerminatedCharac
 
     // fall back to local timezone
     if (!haveTZ)
-        offset = calculateLocalTimeOffset(ms).offset / msPerMinute;
+        offset = calculateLocalTimeOffset(ms, LocalTime).offset / msPerMinute; // ms value is in local time milliseconds.
 
     return ms - (offset * msPerMinute);
 }
Index: webkitgtk/Source/WTF/wtf/DateMath.h
===================================================================
--- webkitgtk.orig/Source/WTF/wtf/DateMath.h
+++ webkitgtk/Source/WTF/wtf/DateMath.h
@@ -53,6 +53,11 @@
 
 namespace WTF {
 
+enum TimeType {
+    UTCTime = 0,
+    LocalTime
+};
+
 struct LocalTimeOffset {
     LocalTimeOffset()
         : isDST(false)
@@ -126,7 +131,7 @@ WTF_EXPORT_PRIVATE int monthFromDayInYea
 WTF_EXPORT_PRIVATE int dayInMonthFromDayInYear(int dayInYear, bool leapYear);
 
 // Returns combined offset in millisecond (UTC + DST).
-WTF_EXPORT_PRIVATE LocalTimeOffset calculateLocalTimeOffset(double utcInMilliseconds);
+WTF_EXPORT_PRIVATE LocalTimeOffset calculateLocalTimeOffset(double utcInMilliseconds, TimeType = UTCTime);
 
 } // namespace WTF
 
