Reviewed by GGaren
authorkmccullo <kmccullo@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 4 Oct 2006 18:36:29 +0000 (18:36 +0000)
committerkmccullo <kmccullo@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 4 Oct 2006 18:36:29 +0000 (18:36 +0000)
        - This is a big makeover for our Date implemenetation.  This solves many platform specific issues, specifically dates before 1970, and simplifies some ugly code.  The purpose of this was to get us to pass many of the JavaScriptCore tests on windows.

        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
        * JavaScriptCore.xcodeproj/project.pbxproj:
        * kjs/DateMath.cpp: Added.
        (KJS::):
        (KJS::daysInYear):
        (KJS::daysFrom1970ToYear):
        (KJS::msFrom1970ToYear):
        (KJS::msToDays):
        (KJS::msToYear):
        (KJS::isLeapYear):
        (KJS::isInLeapYear):
        (KJS::dayInYear):
        (KJS::msToMilliseconds):
        (KJS::msToWeekDay):
        (KJS::msToSeconds):
        (KJS::msToMinutes):
        (KJS::msToHours):
        (KJS::msToMonth):
        (KJS::msToDayInMonth):
        (KJS::monthToDayInYear):
        (KJS::timeToMseconds):
        (KJS::dateToDayInYear):
        (KJS::equivalentYearForDST):
        (KJS::getUTCOffset):
        (KJS::getDSTOffsetSimple):
        (KJS::getDSTOffset):
        (KJS::localTimeToUTC):
        (KJS::UTCToLocalTime):
        (KJS::dateToMseconds):
        (KJS::msToTM):
        (KJS::isDST):
        * kjs/DateMath.h: Added.
        (KJS::):
        * kjs/date_object.cpp:
        (KJS::gmtoffset):
        (KJS::formatTime):
        (KJS::DateInstance::getTime):
        (KJS::DateInstance::getUTCTime):
        (KJS::DateProtoFunc::callAsFunction):
        (KJS::DateObjectImp::construct):
        (KJS::DateObjectFuncImp::callAsFunction):
        (KJS::parseDate):
        * kjs/testkjs.cpp:
        * os-win32/stdint.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@16780 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JavaScriptCore/ChangeLog
JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
JavaScriptCore/kjs/DateMath.cpp [new file with mode: 0644]
JavaScriptCore/kjs/DateMath.h [new file with mode: 0644]
JavaScriptCore/kjs/date_object.cpp
JavaScriptCore/kjs/testkjs.cpp
JavaScriptCore/os-win32/stdint.h

index d68d21ce77b48e9a11098f577ed92cf3213ce584..819c0263deb1a37ad2193fbba3e42486c9aa5d0f 100644 (file)
@@ -1,3 +1,54 @@
+2006-10-04  Kevin McCullough  <KMcCullough@apple.com>
+
+        Reviewed by GGaren
+
+        - This is a big makeover for our Date implemenetation.  This solves many platform specific issues, specifically dates before 1970, and simplifies some ugly code.  The purpose of this was to get us to pass many of the JavaScriptCore tests on windows.
+
+        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * kjs/DateMath.cpp: Added.
+        (KJS::):
+        (KJS::daysInYear):
+        (KJS::daysFrom1970ToYear):
+        (KJS::msFrom1970ToYear):
+        (KJS::msToDays):
+        (KJS::msToYear):
+        (KJS::isLeapYear):
+        (KJS::isInLeapYear):
+        (KJS::dayInYear):
+        (KJS::msToMilliseconds):
+        (KJS::msToWeekDay):
+        (KJS::msToSeconds):
+        (KJS::msToMinutes):
+        (KJS::msToHours):
+        (KJS::msToMonth):
+        (KJS::msToDayInMonth):
+        (KJS::monthToDayInYear):
+        (KJS::timeToMseconds):
+        (KJS::dateToDayInYear):
+        (KJS::equivalentYearForDST):
+        (KJS::getUTCOffset):
+        (KJS::getDSTOffsetSimple):
+        (KJS::getDSTOffset):
+        (KJS::localTimeToUTC):
+        (KJS::UTCToLocalTime):
+        (KJS::dateToMseconds):
+        (KJS::msToTM):
+        (KJS::isDST):
+        * kjs/DateMath.h: Added.
+        (KJS::):
+        * kjs/date_object.cpp:
+        (KJS::gmtoffset):
+        (KJS::formatTime):
+        (KJS::DateInstance::getTime):
+        (KJS::DateInstance::getUTCTime):
+        (KJS::DateProtoFunc::callAsFunction):
+        (KJS::DateObjectImp::construct):
+        (KJS::DateObjectFuncImp::callAsFunction):
+        (KJS::parseDate):
+        * kjs/testkjs.cpp:
+        * os-win32/stdint.h:
+
 2006-10-02  Nikolas Zimmermann  <zimmermann@kde.org>
 
         Reviewed/landed by Adam.
index 3a76023b89f5e7693d122169b3d842a6c18c48cb..f4adff8d4b59c425b5c8ec6651934b95b4f18c4a 100644 (file)
                                RelativePath="..\..\kjs\date_object.h"
                                >
                        </File>
+                       <File
+                               RelativePath="..\..\kjs\DateMath.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\kjs\DateMath.h"
+                               >
+                       </File>
                        <File
                                RelativePath="..\..\kjs\debugger.cpp"
                                >
index d49f85060422bdde5d330907c002b34982eeb857..50d062721122549b545776a1cacd1330cea70580 100644 (file)
                93F0B3AB09BB4DC00068FCE3 /* Parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93F0B3A909BB4DC00068FCE3 /* Parser.cpp */; };
                93F0B3AC09BB4DC00068FCE3 /* Parser.h in Headers */ = {isa = PBXBuildFile; fileRef = 93F0B3AA09BB4DC00068FCE3 /* Parser.h */; };
                BCF655590A2049710038A194 /* MathExtras.h in Headers */ = {isa = PBXBuildFile; fileRef = BCF6553B0A2048DE0038A194 /* MathExtras.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               D212022A0AD4310D00ED79B6 /* DateMath.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D21202280AD4310C00ED79B6 /* DateMath.cpp */; };
+               D212022B0AD4310D00ED79B6 /* DateMath.h in Headers */ = {isa = PBXBuildFile; fileRef = D21202290AD4310C00ED79B6 /* DateMath.h */; };
                E195679609E7CF1200B89D13 /* UnicodeIcu.h in Headers */ = {isa = PBXBuildFile; fileRef = E195678F09E7CF1200B89D13 /* UnicodeIcu.h */; };
                E195679809E7CF1200B89D13 /* Unicode.h in Headers */ = {isa = PBXBuildFile; fileRef = E195679409E7CF1200B89D13 /* Unicode.h */; };
                E195679909E7CF1200B89D13 /* UnicodeCategory.h in Headers */ = {isa = PBXBuildFile; fileRef = E195679509E7CF1200B89D13 /* UnicodeCategory.h */; };
                93F0B3AA09BB4DC00068FCE3 /* Parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Parser.h; sourceTree = "<group>"; };
                93F1981A08245AAE001E9ABC /* keywords.table */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = text; path = keywords.table; sourceTree = "<group>"; tabWidth = 8; };
                BCF6553B0A2048DE0038A194 /* MathExtras.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MathExtras.h; sourceTree = "<group>"; };
+               D21202280AD4310C00ED79B6 /* DateMath.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DateMath.cpp; sourceTree = "<group>"; };
+               D21202290AD4310C00ED79B6 /* DateMath.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DateMath.h; sourceTree = "<group>"; };
                E195678F09E7CF1200B89D13 /* UnicodeIcu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnicodeIcu.h; sourceTree = "<group>"; };
                E195679409E7CF1200B89D13 /* Unicode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Unicode.h; sourceTree = "<group>"; };
                E195679509E7CF1200B89D13 /* UnicodeCategory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnicodeCategory.h; sourceTree = "<group>"; };
                                F692A8540255597D01FF60F7 /* create_hash_table */,
                                F692A8550255597D01FF60F7 /* date_object.cpp */,
                                F692A8560255597D01FF60F7 /* date_object.h */,
+                               D21202280AD4310C00ED79B6 /* DateMath.cpp */,
+                               D21202290AD4310C00ED79B6 /* DateMath.h */,
                                F692A8580255597D01FF60F7 /* debugger.cpp */,
                                F692A8590255597D01FF60F7 /* debugger.h */,
                                651F6412039D5B5F0078395C /* dtoa.cpp */,
                                1CAF34890A6C421700ABE06E /* WebScriptObject.h in Headers */,
                                65C7A1740A8EAACB00FA37EA /* JSWrapperObject.h in Headers */,
                                93B6A0DF0AA64DA40076DE27 /* GetPtr.h in Headers */,
+                               D212022B0AD4310D00ED79B6 /* DateMath.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                0867D690FE84028FC02AAC07 /* Project object */ = {
                        isa = PBXProject;
                        buildConfigurationList = 149C277108902AFE008A9EFC /* Build configuration list for PBXProject "JavaScriptCore" */;
-                       compatibilityVersion = "Xcode 2.4";
                        hasScannedForEncodings = 1;
                        mainGroup = 0867D691FE84028FC02AAC07 /* JavaScriptCore */;
                        productRefGroup = 034768DFFF38A50411DB9C8B /* Products */;
                        projectDirPath = "";
                        projectRoot = "";
-                       shouldCheckCompatibility = 1;
                        targets = (
                                932F5B3E0822A1C700736975 /* JavaScriptCore */,
                                935F69F508244FEA003D1A45 /* dftables */,
                                1421359B0A677F4F00A8195E /* JSBase.cpp in Sources */,
                                65400C110A69BAF200509887 /* PropertyNameArray.cpp in Sources */,
                                65C7A1730A8EAACB00FA37EA /* JSWrapperObject.cpp in Sources */,
+                               D212022A0AD4310D00ED79B6 /* DateMath.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
diff --git a/JavaScriptCore/kjs/DateMath.cpp b/JavaScriptCore/kjs/DateMath.cpp
new file mode 100644 (file)
index 0000000..eb01835
--- /dev/null
@@ -0,0 +1,461 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2006 Apple Computer
+ *
+ * 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.
+ *
+ */
+
+#include <DateMath.h>
+
+#include <math.h>
+#include <stdint.h>
+#include <wtf/OwnPtr.h>
+
+namespace KJS {
+
+/* Constants */
+
+static const double secondsPerHour = 60.0 * 60.0;
+static const double minutesPerDay = 24.0 * 60.0;
+static const double secondsPerDay = 24.0 * 60.0 * 60.0;
+static const double secondsPerYear = 24.0 * 60.0 * 60.0 * 365.0;
+
+
+static const double usecPerMsec = 1000.0;
+static const double usecPerSec = 1000000.0;
+
+static const double maxUnixTime = 2145859200.0; /*equivalent to 12/31/2037 */
+
+/*
+ * The following array contains the day of year for the first day of
+ * each month, where index 0 is January, and day 0 is January 1.
+ */
+static double firstDayOfMonth[2][12] = {
+    {0.0, 31.0, 59.0, 90.0, 120.0, 151.0, 181.0, 212.0, 243.0, 273.0, 304.0, 334.0},
+    {0.0, 31.0, 60.0, 91.0, 121.0, 152.0, 182.0, 213.0, 244.0, 274.0, 305.0, 335.0}
+};
+
+
+/*
+ * Years and leap years on which Jan 1 is a Sunday, Monday, etc.
+ *
+ * yearStartingWith[0][i] is an example non-leap year where
+ * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
+ *
+ * yearStartingWith[1][i] is an example leap year where
+ * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
+ */
+static int yearStartingWith[2][7] = {
+    {1978, 1973, 1974, 1975, 1981, 1971, 1977},
+    {1984, 1996, 1980, 1992, 1976, 1988, 1972}
+};
+
+
+static inline int daysInYear(int year)
+{
+    if (year % 4 != 0)
+        return 365;
+    if (year % 400 == 0)
+        return 366;
+    if (year % 100 == 0)
+        return 365;
+    return 366;
+}
+
+static inline double daysFrom1970ToYear(int year)
+{
+    return 365.0 * (year - 1970)
+        + floor((year - 1969) / 4.0)
+        - floor((year - 1901) / 100.0)
+        + floor((year - 1601) / 400.0);
+}
+
+static inline double msFrom1970ToYear(int year)
+{
+    return msPerDay * daysFrom1970ToYear(year);
+}
+
+static inline int msToDays(double ms)
+{
+    return floor(ms / msPerDay);
+}
+
+static inline int msToYear(double ms)
+{
+    int y = floor(ms /(msPerDay*365.2425)) + 1970;
+    double t2 = msFrom1970ToYear(y);
+
+    if (t2 > ms) {
+        y--;
+    } else {
+        if (t2 + msPerDay * daysInYear(y) <= ms)
+            y++;
+    }
+    return y;
+}
+
+static inline bool isLeapYear(int year)
+{
+    if (year % 4 != 0)
+        return false;
+    if (year % 400 == 0)
+        return true;
+    if (year % 100 == 0)
+        return false;
+    return true;
+}
+
+static inline bool isInLeapYear(double ms)
+{
+    return isLeapYear(msToYear(ms));
+}
+
+static inline int dayInYear(double ms, int year)
+{
+    return msToDays(ms) - daysFrom1970ToYear(year);
+}
+
+static inline double msToMilliseconds(double ms)
+{
+    double result;
+    result = fmod(ms, msPerDay);
+    if (result < 0)
+        result += msPerDay;
+    return result;
+}
+
+// 0: Sunday, 1: Monday, etc.
+static inline int msToWeekDay(double ms)
+{
+    int wd = ((int)msToDays(ms) + 4) % 7;
+    if (wd < 0)
+        wd += 7;
+    return wd;
+}
+
+static inline int msToSeconds(double ms)
+{
+    int result = (int) fmod(floor(ms / msPerSecond), secondsPerMinute);
+    if (result < 0)
+        result += (int)secondsPerMinute;
+    return result;
+}
+
+static inline int msToMinutes(double ms)
+{
+    int result = (int) fmod(floor(ms / msPerMinute), minutesPerHour);
+    if (result < 0)
+        result += (int)minutesPerHour;
+    return result;
+}
+
+static inline int msToHours(double ms)
+{
+    int result = (int) fmod(floor(ms/msPerHour), hoursPerDay);
+    if (result < 0)
+        result += (int)hoursPerDay;
+    return result;
+}
+
+static inline int msToMonth(double ms)
+{
+    int d, step;
+    int year = msToYear(ms);
+    d = dayInYear(ms, year);
+
+    if (d < (step = 31))
+        return 0;
+    step += (isInLeapYear(ms) ? 29 : 28);
+    if (d < step)
+        return 1;
+    if (d < (step += 31))
+        return 2;
+    if (d < (step += 30))
+        return 3;
+    if (d < (step += 31))
+        return 4;
+    if (d < (step += 30))
+        return 5;
+    if (d < (step += 31))
+        return 6;
+    if (d < (step += 31))
+        return 7;
+    if (d < (step += 30))
+        return 8;
+    if (d < (step += 31))
+        return 9;
+    if (d < (step += 30))
+        return 10;
+    return 11;
+}
+
+static inline int msToDayInMonth(double ms)
+{
+    int d, step, next;
+    int year = msToYear(ms);
+    d = dayInYear(ms, year);
+
+    if (d <= (next = 30))
+        return d + 1;
+    step = next;
+    next += (isInLeapYear(ms) ? 29 : 28);
+    if (d <= next)
+        return d - step;
+    step = next;
+    if (d <= (next += 31))
+        return d - step;
+    step = next;
+    if (d <= (next += 30))
+        return d - step;
+    step = next;
+    if (d <= (next += 31))
+        return d - step;
+    step = next;
+    if (d <= (next += 30))
+        return d - step;
+    step = next;
+    if (d <= (next += 31))
+        return d - step;
+    step = next;
+    if (d <= (next += 31))
+        return d - step;
+    step = next;
+    if (d <= (next += 30))
+        return d - step;
+    step = next;
+    if (d <= (next += 31))
+        return d - step;
+    step = next;
+    if (d <= (next += 30))
+        return d - step;
+    step = next;
+    return d - step;
+}
+
+static inline double monthToDayInYear(int month, bool isLeapYear)
+{
+    return firstDayOfMonth[isLeapYear][month];
+}
+
+static inline double timeToMseconds(double hour, double min, double sec, double ms)
+{
+    return (((hour * minutesPerHour + min) * secondsPerMinute + sec) * msPerSecond + ms);
+}
+
+static double dateToDayInYear(double year, double month, double day)
+{
+    year += floor(month / 12);
+
+    month = fmod(month, 12.0);
+    if (month < 0)
+        month += 12;
+
+    double yearday = floor(msFrom1970ToYear(year) / msPerDay);
+    double monthday = monthToDayInYear(month, isLeapYear(year));
+
+    return yearday + monthday + day - 1;
+}
+
+/*
+ * Find a year for which any given date will fall on the same weekday.
+ *
+ * This function should be used with caution when used other than
+ * for determining DST; it hasn't been proven not to produce an
+ * incorrect year for times near year boundaries.
+ */
+static inline int equivalentYearForDST(int year)
+{
+    int day;
+
+    day = (int) daysFrom1970ToYear(year) + 4;
+    day = day % 7;
+
+    if (day < 0)
+        day += 7;
+
+    return yearStartingWith[isLeapYear(year)][day];
+}
+
+/*
+ * Get the difference in milliseconds between this time zone and UTC (GMT)
+ * NOT including DST.
+ */
+double getUTCOffset() {
+    static double utcOffset;
+    static bool utcOffsetInitialized = false;
+    if (!utcOffsetInitialized) {
+        struct tm ltime;
+
+        ltime.tm_sec = 0;
+        ltime.tm_min = 0;
+        ltime.tm_hour = 0;
+        ltime.tm_mon = 0;
+        ltime.tm_wday = 0;
+        ltime.tm_yday = 0;
+        ltime.tm_isdst = 0;
+
+        /* get the difference between this time zone and GMT */
+        ltime.tm_mday = 2;
+        ltime.tm_year = 70;
+
+        #if !PLATFORM(WIN_OS)
+        ltime.tm_zone = 0;
+        ltime.tm_gmtoff = 0;
+        #endif
+
+        utcOffset = mktime(&ltime) - (hoursPerDay * secondsPerHour);
+        utcOffset *= -msPerSecond;
+
+        utcOffsetInitialized = true;
+    }
+    return utcOffset;
+}
+
+/*
+ * Get the DST offset for the time passed in.  Takes
+ * seconds (not milliseconds) and cannot handle dates before 1970
+ * on some OS'
+ */
+static double getDSTOffsetSimple(double localTimeSeconds)
+{
+    if(localTimeSeconds > maxUnixTime)
+        localTimeSeconds = maxUnixTime;
+    else if(localTimeSeconds < 0) /*go ahead a day to make localtime work (does not work with 0) */
+        localTimeSeconds = secondsPerDay;
+
+    double offsetTime = (localTimeSeconds * usecPerMsec) + getUTCOffset() ;
+
+    struct tm prtm;
+    prtm.tm_min   =  msToMinutes(offsetTime);
+    prtm.tm_hour  =  msToHours(offsetTime);
+
+
+    time_t localTime = localTimeSeconds;
+
+    struct tm tm;
+    #if PLATFORM(WIN_OS)
+    localtime_s(&tm, &localTime);
+    #else
+    localtime_r(&localTime, &tm);
+    #endif
+
+    double diff = ((tm.tm_hour - prtm.tm_hour) * secondsPerHour) + ((tm.tm_min - prtm.tm_min) * 60);
+
+    if(diff < 0)
+        diff += secondsPerDay;
+
+    return (diff * usecPerMsec);
+}
+
+// get the DST offset the time passed in
+static double getDSTOffset(double ms)
+{
+    /*
+     * If earlier than 1970 or after 2038, potentially beyond the ken of
+     * many OSes, map it to an equivalent year before asking.
+     */
+    if (ms < 0.0 || ms > 2145916800000.0) {
+        int year;
+        double day;
+
+        year = equivalentYearForDST(msToYear(ms));
+        day = dateToDayInYear(year, msToMonth(ms), msToDayInMonth(ms));
+        ms = (day * msPerDay) + msToMilliseconds(ms);
+    }
+
+    /* put our ms in an LL, and map it to usec for prtime */
+    return getDSTOffsetSimple(ms / usecPerMsec);
+}
+
+static inline double localTimeToUTC(double ms)
+{
+    ms -= getUTCOffset();
+    ms -= getDSTOffset(ms);
+    return ms;
+}
+
+static inline double UTCToLocalTime(double ms)
+{
+    ms += getUTCOffset();
+    ms += getDSTOffset(ms);
+    return ms;
+}
+
+double dateToMseconds(tm* t, double ms, bool inputIsUTC)
+{
+    double day = dateToDayInYear(t->tm_year + 1900, t->tm_mon, t->tm_mday);
+    double msec_time = timeToMseconds(t->tm_hour, t->tm_min, t->tm_sec, ms);
+    double result = (day * msPerDay) + msec_time;
+
+    if(!inputIsUTC)
+        result = localTimeToUTC(result);
+
+    return result;
+}
+
+void msToTM(double ms, bool outputIsUTC, struct tm& tm)
+{
+    //input is UTC
+    if(!outputIsUTC)
+        ms = UTCToLocalTime(ms);
+
+    tm.tm_sec   =  msToSeconds(ms);
+    tm.tm_min   =  msToMinutes(ms);
+    tm.tm_hour  =  msToHours(ms);
+    tm.tm_wday  =  msToWeekDay(ms);
+    tm.tm_mday  =  msToDayInMonth(ms);
+    tm.tm_yday  =  dayInYear(ms, msToYear(ms));
+    tm.tm_mon   =  msToMonth(ms);
+    tm.tm_year  =  msToYear(ms) - 1900;
+    tm.tm_isdst =  isDST(ms);
+
+    //everyone else seems to have these fields
+    #if !PLATFORM(WIN_OS)
+    struct tm xtm;
+    time_t seconds = ms/usecPerMsec;
+    localtime_r(&seconds, &xtm);
+    tm.tm_gmtoff = xtm.tm_gmtoff;
+    tm.tm_zone = xtm.tm_zone;
+    #endif
+}
+
+bool isDST(const double& ms)
+{
+    return getDSTOffset(ms) != 0;
+}
+
+}   //namespace KJS
+
diff --git a/JavaScriptCore/kjs/DateMath.h b/JavaScriptCore/kjs/DateMath.h
new file mode 100644 (file)
index 0000000..b977d5d
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2006 Apple Computer
+ *
+ * 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 DateMath_h
+#define DateMath_h
+
+#include <time.h>
+
+namespace KJS {
+
+// Constants //
+
+const char * const weekdayName[7] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
+const char * const monthName[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+const double hoursPerDay = 24.0;
+const double msPerDay = 24.0 * 60.0 * 60.0 * 1000.0;
+const double minutesPerHour = 60.0;
+const double secondsPerMinute = 60.0;
+const double msPerSecond = 1000.0;
+const double msPerMinute = 60.0 * 1000.0;
+const double msPerHour = 60.0 * 60.0 * 1000.0;
+
+// Exported Functions //
+void msToTM(double, bool outputIsUTC, struct tm& );
+double dateToMseconds(tm*, double, bool inputIsUTC);
+bool isDST(const double&);
+double getUTCOffset();
+
+}   //namespace KJS
+
+#endif // DateMath_h
index 8890ae9d133d66e7eac35a9f3a2820894c1c4d35..1539173cad0bb9a7d0060f959d65fe690b4a9bbd 100644 (file)
 
 #include "error_object.h"
 #include "operations.h"
+#include <DateMath.h>
 
 #include <wtf/MathExtras.h>
 #include <wtf/StringExtras.h>
 
 #if PLATFORM(MAC)
-#include <CoreFoundation/CoreFoundation.h>
+    #include <CoreFoundation/CoreFoundation.h>
 #endif
 
+namespace KJS {
+
+static double parseDate(const UString&);
+static double timeClip(double);
+
 inline int gmtoffset(const tm& t)
 {
 #if PLATFORM(WIN_OS)
     // Time is supposed to be in the current timezone.
-    // FIXME: Use undocumented _dstbias?
-    return -(_timezone / 60 - (t.tm_isdst > 0 ? 60 : 0 )) * 60;
+    return static_cast<int>(getUTCOffset()/1000.0);
 #else
     return t.tm_gmtoff;
 #endif
 }
 
-namespace KJS {
 
 /**
  * @internal
@@ -90,23 +94,6 @@ private:
     int id;
 };
 
-// some constants
-const double hoursPerDay = 24;
-const double minutesPerHour = 60;
-const double secondsPerMinute = 60;
-const double msPerSecond = 1000;
-const double msPerMinute = 60 * 1000;
-const double msPerHour = 60 * 60 * 1000;
-const double msPerDay = 24 * 60 * 60 * 1000;
-
-static const char * const weekdayName[7] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
-static const char * const monthName[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
-
-static double makeTime(tm *, double ms, bool utc);
-static double parseDate(const UString &);
-static double timeClip(double);
-static void millisecondsToTM(double milli, bool utc, tm *t);
-
 #if PLATFORM(MAC)
 
 static CFDateFormatterStyle styleFromArgString(const UString& string, CFDateFormatterStyle defaultStyle)
@@ -196,8 +183,7 @@ static UString formatTime(const tm &t, bool utc)
 {
     char buffer[100];
     if (utc) {
-        // FIXME: why not on windows?
-#if !PLATFORM(WIN_OS)
+#if !PLATFORM(WIN_OS)   //win doesn't have the tm_gtoff member
         ASSERT(t.tm_gmtoff == 0);
 #endif
         snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT", t.tm_hour, t.tm_min, t.tm_sec);
@@ -222,67 +208,6 @@ static UString formatTime(const tm &t, bool utc)
     return UString(buffer);
 }
 
-static int day(double t)
-{
-    return int(floor(t / msPerDay));
-}
-
-static double dayFromYear(int year)
-{
-    return 365.0 * (year - 1970)
-        + floor((year - 1969) / 4.0)
-        - floor((year - 1901) / 100.0)
-        + floor((year - 1601) / 400.0);
-}
-
-// based on the rule for whether it's a leap year or not
-static int daysInYear(int year)
-{
-    if (year % 4 != 0)
-        return 365;
-    if (year % 400 == 0)
-        return 366;
-    if (year % 100 == 0)
-        return 365;
-    return 366;
-}
-
-// time value of the start of a year
-static double timeFromYear(int year)
-{
-    return msPerDay * dayFromYear(year);
-}
-
-// year determined by time value
-static int yearFromTime(double t)
-{
-    // ### there must be an easier way
-
-    // initial guess
-    int y = 1970 + int(t / (365.25 * msPerDay));
-
-    // adjustment
-    if (timeFromYear(y) > t) {
-        do
-            --y;
-        while (timeFromYear(y) > t);
-    } else {
-        while (timeFromYear(y + 1) < t)
-            ++y;
-    }
-
-    return y;
-}
-
-// 0: Sunday, 1: Monday, etc.
-static int weekDay(double t)
-{
-    int wd = (day(t) + 4) % 7;
-    if (wd < 0)
-        wd += 7;
-    return wd;
-}
-
 // Converts a list of arguments sent to a Date member function into milliseconds, updating
 // ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
 //
@@ -368,7 +293,7 @@ bool DateInstance::getTime(tm &t, int &offset) const
     if (isNaN(milli))
         return false;
     
-    millisecondsToTM(milli, false, &t);
+    msToTM(milli, false, t);
     offset = gmtoffset(t);
     return true;
 }
@@ -379,7 +304,7 @@ bool DateInstance::getUTCTime(tm &t) const
     if (isNaN(milli))
         return false;
     
-    millisecondsToTM(milli, true, &t);
+    msToTM(milli, true, t);
     return true;
 }
 
@@ -390,7 +315,7 @@ bool DateInstance::getTime(double &milli, int &offset) const
         return false;
     
     tm t;
-    millisecondsToTM(milli, false, &t);
+    msToTM(milli, false, t);
     offset = gmtoffset(t);
     return true;
 }
@@ -410,43 +335,6 @@ static inline bool isTime_tSigned()
     return minusOne < 0;
 }
 
-static void millisecondsToTM(double milli, bool utc, tm *t)
-{
-  // check whether time value is outside time_t's usual range
-  // make the necessary transformations if necessary
-  static bool time_tIsSigned = isTime_tSigned();
-  static double time_tMin = (time_tIsSigned ? - (double)(1ULL << (8 * sizeof(time_t) - 1)) : 0);
-  static double time_tMax = (time_tIsSigned ? (1ULL << 8 * sizeof(time_t) - 1) - 1 : 2 * (double)(1ULL << 8 * sizeof(time_t) - 1) - 1);
-  int realYearOffset = 0;
-  double milliOffset = 0.0;
-  double secs = floor(milli / msPerSecond);
-
-  if (secs < time_tMin || secs > time_tMax) {
-    // ### ugly and probably not very precise
-    int realYear = yearFromTime(milli);
-    int base = daysInYear(realYear) == 365 ? 2001 : 2000;
-    milliOffset = timeFromYear(base) - timeFromYear(realYear);
-    milli += milliOffset;
-    realYearOffset = realYear - base;
-  }
-
-  time_t tv = (time_t) floor(milli / msPerSecond);
-
-  *t = *(utc ? gmtime(&tv) : localtime(&tv));
-  // We had an out of range year. Restore the year (plus/minus offset
-  // found by calculating tm_year) and fix the week day calculation.
-  if (realYearOffset != 0) {
-    t->tm_year += realYearOffset;
-    milli -= milliOffset;
-    // Do our own weekday calculation. Use time zone offset to handle local time.
-    double m = milli;
-    if (!utc)
-      m += gmtoffset(*t) * msPerSecond;
-    t->tm_wday = weekDay(m);
-  }
-}    
-
-
 // ------------------------------ DatePrototype -----------------------------
 
 const ClassInfo DatePrototype::info = {"Date", &DateInstance::info, &dateTable, 0};
@@ -575,7 +463,7 @@ JSValue *DateProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const
   double ms = milli - secs * msPerSecond;
 
   tm t;
-  millisecondsToTM(milli, utc, &t);
+  msToTM(milli, utc, t);
 
   switch (id) {
   case ToString:
@@ -674,7 +562,7 @@ JSValue *DateProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const
   if (id == SetYear || id == SetMilliSeconds || id == SetSeconds ||
       id == SetMinutes || id == SetHours || id == SetDate ||
       id == SetMonth || id == SetFullYear ) {
-    result = jsNumber(makeTime(&t, ms, utc));
+    result = jsNumber(dateToMseconds(&t, ms, utc));
     thisDateObj->setInternalValue(result);
   }
   
@@ -761,7 +649,7 @@ JSObject *DateObjectImp::construct(ExecState *exec, const List &args)
       t.tm_sec = (numArgs >= 6) ? args[5]->toInt32(exec) : 0;
       t.tm_isdst = -1;
       double ms = (numArgs >= 7) ? roundValue(exec, args[6]) : 0;
-      value = makeTime(&t, ms, false);
+      value = dateToMseconds(&t, ms, false);
     }
   }
   
@@ -814,7 +702,7 @@ JSValue *DateObjectFuncImp::callAsFunction(ExecState* exec, JSObject*, const Lis
     t.tm_min = (n >= 5) ? args[4]->toInt32(exec) : 0;
     t.tm_sec = (n >= 6) ? args[5]->toInt32(exec) : 0;
     double ms = (n >= 7) ? roundValue(exec, args[6]) : 0;
-    return jsNumber(makeTime(&t, ms, true));
+    return jsNumber(dateToMseconds(&t, ms, true));
   }
 }
 
@@ -853,58 +741,6 @@ static const struct KnownZone {
     { "PDT", -420 }
 };
 
-static double makeTime(tm *t, double ms, bool utc)
-{
-    int utcOffset;
-    if (utc) {
-        time_t zero = 0;
-#if PLATFORM(WIN_OS)
-        // FIXME: not thread safe
-        (void)localtime(&zero);
-#if COMPILER(BORLAND) || COMPILER(CYGWIN)
-        utcOffset = - _timezone;
-#else
-        utcOffset = - timezone;
-#endif
-        t->tm_isdst = 0;
-#else
-        tm t3;
-        localtime_r(&zero, &t3);
-        utcOffset = t3.tm_gmtoff;
-        t->tm_isdst = t3.tm_isdst;
-#endif
-    } else {
-        utcOffset = 0;
-        t->tm_isdst = -1;
-    }
-
-    double yearOffset = 0.0;
-    if (t->tm_year < (1970 - 1900) || t->tm_year > (2038 - 1900)) {
-        // we'll fool mktime() into believing that this year is within
-        // its normal, portable range (1970-2038) by setting tm_year to
-        // 2000 or 2001 and adding the difference in milliseconds later.
-        // choice between offset will depend on whether the year is a
-        // leap year or not.
-        int y = t->tm_year + 1900;
-        int baseYear = daysInYear(y) == 365 ? 2001 : 2000;
-        double baseTime = timeFromYear(baseYear);
-        yearOffset = timeFromYear(y) - baseTime;
-        t->tm_year = baseYear - 1900;
-    }
-
-    // Determine whether DST is in effect. mktime() can't do this for us because
-    // it doesn't know about ms and yearOffset.
-    // NOTE: Casting values of large magnitude to time_t (long) will 
-    // produce incorrect results, but there's no other option when calling localtime_r().
-    if (!utc) { 
-        time_t tval = mktime(t) + (time_t)((ms + yearOffset) / 1000);  
-        tm t3 = *localtime(&tval);  
-        t->tm_isdst = t3.tm_isdst;  
-    }
-
-    return (mktime(t) + utcOffset) * msPerSecond + ms + yearOffset;
-}
-
 inline static void skipSpacesAndComments(const char *&s)
 {
     int nesting = 0;
@@ -1233,8 +1069,8 @@ static double parseDate(const UString &date)
         t.tm_min = minute;
         t.tm_hour = hour;
 
-        // Use our makeTime() rather than mktime() as the latter can't handle the full year range.
-        return makeTime(&t, 0, false);
+        // Use our dateToMseconds() rather than mktime() as the latter can't handle the full year range.
+        return dateToMseconds(&t, 0, false);
     }
 
     return (ymdhmsToSeconds(year, month + 1, day, hour, minute, second) - (offset * 60.0)) * msPerSecond;
index a0efe8aca047d986efb8edbf2db956b28c2bf3e0..9061363415ff1d3b269ba8dd2144318267487a00 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <math.h>
 #include <stdio.h>
+
 #include <string.h>
 #if HAVE(SYS_TIME_H)
 #include <sys/time.h>
index bde43e6079641dcd1a83304f85aafa0eeb4c2bfe..48ae474d25c48ef3679c351ff9afe0da35e96ae9 100644 (file)
 #ifndef STDINT_WIN32_H
 #define STDINT_WIN32_H
 
+#include <wtf/Platform.h>
+
 /* This file emulates enough of stdint.h on Windows to make JavaScriptCore and WebCore compile. */
-   
+
 #if !PLATFORM(WIN_OS)
 #error "This stdint.h file should only be compiled under Windows"
 #endif