DateMath.cpp should not depend on JavaScriptCore
https://bugs.webkit.org/show_bug.cgi?id=71747
Reviewed by Darin Adler.
This patch moves the JSC-specific parts of DateMath into JSDateMath in
JavaScriptCore. There shouldn't be any behavior change.
* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.gypi:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* runtime/DateConstructor.cpp:
* runtime/DateConversion.cpp:
* runtime/DateInstance.cpp:
* runtime/DateInstanceCache.h:
* runtime/DatePrototype.cpp:
* runtime/InitializeThreading.cpp:
* runtime/JSDateMath.cpp: Copied from Source/JavaScriptCore/wtf/DateMath.cpp.
(JSC::timeToMS):
(JSC::msToSeconds):
* runtime/JSDateMath.h: Copied from Source/JavaScriptCore/wtf/DateMath.h.
* wtf/DateMath.cpp:
(WTF::isLeapYear):
(WTF::msToDays):
(WTF::msToMinutes):
(WTF::msToHours):
(WTF::parseDateFromNullTerminatedCharacters):
(WTF::makeRFC2822DateString):
* wtf/DateMath.h:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@100205 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/runtime/DateConstructor.cpp b/Source/JavaScriptCore/runtime/DateConstructor.cpp
index 5c8d21a..931899e 100644
--- a/Source/JavaScriptCore/runtime/DateConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/DateConstructor.cpp
@@ -25,6 +25,7 @@
#include "DateConversion.h"
#include "DateInstance.h"
#include "DatePrototype.h"
+#include "JSDateMath.h"
#include "JSFunction.h"
#include "JSGlobalObject.h"
#include "JSString.h"
@@ -32,7 +33,6 @@
#include "ObjectPrototype.h"
#include <math.h>
#include <time.h>
-#include <wtf/DateMath.h>
#include <wtf/MathExtras.h>
#if OS(WINCE) && !PLATFORM(QT)
diff --git a/Source/JavaScriptCore/runtime/DateConversion.cpp b/Source/JavaScriptCore/runtime/DateConversion.cpp
index 1418876..7bc0cbc 100644
--- a/Source/JavaScriptCore/runtime/DateConversion.cpp
+++ b/Source/JavaScriptCore/runtime/DateConversion.cpp
@@ -44,10 +44,10 @@
#include "DateConversion.h"
#include "CallFrame.h"
+#include "JSDateMath.h"
#include "JSObject.h"
#include "ScopeChain.h"
#include "UString.h"
-#include <wtf/DateMath.h>
#include <wtf/StringExtras.h>
#include <wtf/text/CString.h>
diff --git a/Source/JavaScriptCore/runtime/DateInstance.cpp b/Source/JavaScriptCore/runtime/DateInstance.cpp
index e09a9e8..545757b 100644
--- a/Source/JavaScriptCore/runtime/DateInstance.cpp
+++ b/Source/JavaScriptCore/runtime/DateInstance.cpp
@@ -22,10 +22,10 @@
#include "config.h"
#include "DateInstance.h"
+#include "JSDateMath.h"
#include "JSGlobalObject.h"
#include <math.h>
-#include <wtf/DateMath.h>
#include <wtf/MathExtras.h>
using namespace WTF;
diff --git a/Source/JavaScriptCore/runtime/DateInstanceCache.h b/Source/JavaScriptCore/runtime/DateInstanceCache.h
index cdd12cf..153582f 100644
--- a/Source/JavaScriptCore/runtime/DateInstanceCache.h
+++ b/Source/JavaScriptCore/runtime/DateInstanceCache.h
@@ -26,7 +26,7 @@
#ifndef DateInstanceCache_h
#define DateInstanceCache_h
-#include <wtf/DateMath.h>
+#include "JSDateMath.h"
#include <wtf/FixedArray.h>
#include <wtf/HashFunctions.h>
#include <wtf/PassRefPtr.h>
diff --git a/Source/JavaScriptCore/runtime/DatePrototype.cpp b/Source/JavaScriptCore/runtime/DatePrototype.cpp
index 8a3e16d..319218c 100644
--- a/Source/JavaScriptCore/runtime/DatePrototype.cpp
+++ b/Source/JavaScriptCore/runtime/DatePrototype.cpp
@@ -27,6 +27,7 @@
#include "DateConversion.h"
#include "DateInstance.h"
#include "Error.h"
+#include "JSDateMath.h"
#include "JSGlobalObject.h"
#include "JSString.h"
#include "JSStringBuilder.h"
@@ -43,7 +44,6 @@
#include <stdlib.h>
#include <time.h>
#include <wtf/Assertions.h>
-#include <wtf/DateMath.h>
#include <wtf/MathExtras.h>
#include <wtf/StringExtras.h>
#include <wtf/UnusedParam.h>
diff --git a/Source/JavaScriptCore/runtime/InitializeThreading.cpp b/Source/JavaScriptCore/runtime/InitializeThreading.cpp
index 8028b3aee..3a371f9 100644
--- a/Source/JavaScriptCore/runtime/InitializeThreading.cpp
+++ b/Source/JavaScriptCore/runtime/InitializeThreading.cpp
@@ -33,11 +33,11 @@
#include "Heap.h"
#include "Heuristics.h"
#include "Identifier.h"
+#include "JSDateMath.h"
#include "JSGlobalObject.h"
#include "UString.h"
#include "WriteBarrier.h"
#include "dtoa.h"
-#include <wtf/DateMath.h>
#include <wtf/Threading.h>
#include <wtf/dtoa/cached-powers.h>
diff --git a/Source/JavaScriptCore/runtime/JSDateMath.cpp b/Source/JavaScriptCore/runtime/JSDateMath.cpp
new file mode 100644
index 0000000..8630733
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSDateMath.cpp
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2006, 2007 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)
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Alternatively, the contents of this file may be used under the terms
+ * of either the Mozilla Public License Version 1.1, found at
+ * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
+ * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
+ * (the "GPL"), in which case the provisions of the MPL or the GPL are
+ * applicable instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of one of those two
+ * licenses (the MPL or the GPL) and not to allow others to use your
+ * version of this file under the LGPL, indicate your decision by
+ * deletingthe provisions above and replace them with the notice and
+ * other provisions required by the MPL or the GPL, as the case may be.
+ * If you do not delete the provisions above, a recipient may use your
+ * version of this file under any of the LGPL, the MPL or the GPL.
+
+ * Copyright 2006-2008 the V8 project authors. All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSDateMath.h"
+
+#include "Assertions.h"
+#include "ASCIICType.h"
+#include "CurrentTime.h"
+#include "JSObject.h"
+#include "MathExtras.h"
+#include "ScopeChain.h"
+#include "StdLibExtras.h"
+#include "StringExtras.h"
+
+#include <algorithm>
+#include <limits.h>
+#include <limits>
+#include <stdint.h>
+#include <time.h>
+#include <wtf/text/StringBuilder.h>
+
+#if HAVE(ERRNO_H)
+#include <errno.h>
+#endif
+
+#if OS(WINCE)
+extern "C" size_t strftime(char * const s, const size_t maxsize, const char * const format, const struct tm * const t);
+extern "C" struct tm * localtime(const time_t *timer);
+#endif
+
+#if HAVE(SYS_TIME_H)
+#include <sys/time.h>
+#endif
+
+#if HAVE(SYS_TIMEB_H)
+#include <sys/timeb.h>
+#endif
+
+using namespace WTF;
+
+namespace JSC {
+
+static inline double timeToMS(double hour, double min, double sec, double ms)
+{
+ return (((hour * minutesPerHour + min) * secondsPerMinute + sec) * msPerSecond + ms);
+}
+
+static inline int msToSeconds(double ms)
+{
+ double result = fmod(floor(ms / msPerSecond), secondsPerMinute);
+ if (result < 0)
+ result += secondsPerMinute;
+ return static_cast<int>(result);
+}
+
+// 0: Sunday, 1: Monday, etc.
+static inline int msToWeekDay(double ms)
+{
+ int wd = (static_cast<int>(msToDays(ms)) + 4) % 7;
+ if (wd < 0)
+ wd += 7;
+ return wd;
+}
+
+// Get the 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)
+{
+ DSTOffsetCache& cache = exec->globalData().dstOffsetCache;
+ double start = cache.start;
+ double end = cache.end;
+
+ if (start <= ms) {
+ // If the time fits in the cached interval, return the cached offset.
+ if (ms <= end) return cache.offset;
+
+ // Compute a possible new interval end.
+ double newEnd = end + cache.increment;
+
+ if (ms <= newEnd) {
+ double endOffset = calculateDSTOffset(newEnd, utcOffset);
+ 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
+ // and return the offset.
+ cache.end = newEnd;
+ cache.increment = msPerMonth;
+ return endOffset;
+ } 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;
+ }
+ }
+ }
+
+ // 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);
+ cache.offset = offset;
+ cache.start = ms;
+ cache.end = ms;
+ cache.increment = msPerMonth;
+ 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);
+ }
+
+ return result;
+}
+
+// input is UTC
+void msToGregorianDateTime(ExecState* exec, double ms, bool outputIsUTC, GregorianDateTime& tm)
+{
+ double dstOff = 0.0;
+ double utcOff = 0.0;
+ if (!outputIsUTC) {
+ utcOff = getUTCOffset(exec);
+ dstOff = getDSTOffset(exec, ms, utcOff);
+ ms += dstOff + utcOff;
+ }
+
+ 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;
+}
+
+double parseDateFromNullTerminatedCharacters(ExecState* exec, const char* dateString)
+{
+ ASSERT(exec);
+ bool haveTZ;
+ int offset;
+ double ms = WTF::parseDateFromNullTerminatedCharacters(dateString, haveTZ, offset);
+ if (isnan(ms))
+ 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);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSDateMath.h b/Source/JavaScriptCore/runtime/JSDateMath.h
new file mode 100644
index 0000000..ba6d647
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSDateMath.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ * Copyright (C) 2010 Research In Motion Limited. All rights reserved.
+ *
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ */
+
+#ifndef JSDateMath_h
+#define JSDateMath_h
+
+#include <wtf/DateMath.h>
+
+namespace JSC {
+
+class ExecState;
+struct GregorianDateTime;
+
+void msToGregorianDateTime(ExecState*, double, bool outputIsUTC, GregorianDateTime&);
+double gregorianDateTimeToMS(ExecState*, const GregorianDateTime&, double, bool inputIsUTC);
+double getUTCOffset(ExecState*);
+double parseDateFromNullTerminatedCharacters(ExecState*, const char* dateString);
+
+// Intentionally overridding the default tm of the system.
+// The members of tm differ on various operating systems.
+struct GregorianDateTime {
+ WTF_MAKE_NONCOPYABLE(GregorianDateTime);
+public:
+ GregorianDateTime()
+ : second(0)
+ , minute(0)
+ , hour(0)
+ , weekDay(0)
+ , monthDay(0)
+ , yearDay(0)
+ , month(0)
+ , year(0)
+ , isDST(0)
+ , utcOffset(0)
+ {
+ }
+
+ 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;
+ memset(&ret, 0, sizeof(ret));
+
+ ret.tm_sec = second;
+ ret.tm_min = minute;
+ ret.tm_hour = hour;
+ ret.tm_wday = weekDay;
+ ret.tm_mday = monthDay;
+ ret.tm_yday = yearDay;
+ ret.tm_mon = month;
+ ret.tm_year = year;
+ ret.tm_isdst = isDST;
+
+#if HAVE(TM_GMTOFF)
+ ret.tm_gmtoff = static_cast<long>(utcOffset);
+#endif
+#if HAVE(TM_ZONE)
+ ret.tm_zone = timeZone.get();
+#endif
+
+ return ret;
+ }
+
+ void copyFrom(const GregorianDateTime& rhs)
+ {
+ second = rhs.second;
+ minute = rhs.minute;
+ hour = rhs.hour;
+ weekDay = rhs.weekDay;
+ monthDay = rhs.monthDay;
+ yearDay = rhs.yearDay;
+ month = rhs.month;
+ year = rhs.year;
+ isDST = rhs.isDST;
+ utcOffset = rhs.utcOffset;
+ if (rhs.timeZone) {
+ int inZoneSize = strlen(rhs.timeZone.get()) + 1;
+ timeZone = adoptArrayPtr(new char[inZoneSize]);
+ strncpy(timeZone.get(), rhs.timeZone.get(), inZoneSize);
+ } else
+ timeZone = nullptr;
+ }
+
+ int second;
+ int minute;
+ int hour;
+ int weekDay;
+ int monthDay;
+ int yearDay;
+ int month;
+ int year;
+ int isDST;
+ int utcOffset;
+ OwnArrayPtr<char> timeZone;
+};
+
+static inline int gmtoffset(const GregorianDateTime& t)
+{
+ return t.utcOffset;
+}
+
+} // namespace JSC
+
+#endif // JSDateMath_h