2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
4 * Copyright (C) 2009 Google Inc. All rights reserved.
5 * Copyright (C) 2007-2009 Torch Mobile, Inc.
7 * The Original Code is Mozilla Communicator client code, released
10 * The Initial Developer of the Original Code is
11 * Netscape Communications Corporation.
12 * Portions created by the Initial Developer are Copyright (C) 1998
13 * the Initial Developer. All Rights Reserved.
15 * This library is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Lesser General Public
17 * License as published by the Free Software Foundation; either
18 * version 2.1 of the License, or (at your option) any later version.
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29 * Alternatively, the contents of this file may be used under the terms
30 * of either the Mozilla Public License Version 1.1, found at
31 * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
32 * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
33 * (the "GPL"), in which case the provisions of the MPL or the GPL are
34 * applicable instead of those above. If you wish to allow use of your
35 * version of this file only under the terms of one of those two
36 * licenses (the MPL or the GPL) and not to allow others to use your
37 * version of this file under the LGPL, indicate your decision by
38 * deletingthe provisions above and replace them with the notice and
39 * other provisions required by the MPL or the GPL, as the case may be.
40 * If you do not delete the provisions above, a recipient may use your
41 * version of this file under any of the LGPL, the MPL or the GPL.
43 * Copyright 2006-2008 the V8 project authors. All rights reserved.
44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted provided that the following conditions are
48 * * Redistributions of source code must retain the above copyright
49 * notice, this list of conditions and the following disclaimer.
50 * * Redistributions in binary form must reproduce the above
51 * copyright notice, this list of conditions and the following
52 * disclaimer in the documentation and/or other materials provided
53 * with the distribution.
54 * * Neither the name of Google Inc. nor the names of its
55 * contributors may be used to endorse or promote products derived
56 * from this software without specific prior written permission.
58 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
59 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
60 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
61 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
62 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
63 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
64 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
65 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
66 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
67 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
68 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
74 #include "Assertions.h"
75 #include "ASCIICType.h"
76 #include "CurrentTime.h"
77 #include "MathExtras.h"
78 #include "StringExtras.h"
92 extern "C" size_t strftime(char * const s
, const size_t maxsize
, const char * const format
, const struct tm
* const t
);
93 extern "C" struct tm
* localtime(const time_t *timer
);
100 #if HAVE(SYS_TIMEB_H)
101 #include <sys/timeb.h>
105 #include "CallFrame.h"
108 #define NaN std::numeric_limits<double>::quiet_NaN()
116 static const double minutesPerDay
= 24.0 * 60.0;
117 static const double secondsPerDay
= 24.0 * 60.0 * 60.0;
118 static const double secondsPerYear
= 24.0 * 60.0 * 60.0 * 365.0;
120 static const double usecPerSec
= 1000000.0;
122 static const double maxUnixTime
= 2145859200.0; // 12/31/2037
123 // ECMAScript asks not to support for a date of which total
124 // millisecond value is larger than the following value.
125 // See 15.9.1.14 of ECMA-262 5th edition.
126 static const double maxECMAScriptTime
= 8.64E15
;
128 // Day of year for the first day of each month, where index 0 is January, and day 0 is January 1.
129 // First for non-leap years, then for leap years.
130 static const int firstDayOfMonth
[2][12] = {
131 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
132 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
135 static inline bool isLeapYear(int year
)
146 static inline int daysInYear(int year
)
148 return 365 + isLeapYear(year
);
151 static inline double daysFrom1970ToYear(int year
)
153 // The Gregorian Calendar rules for leap years:
154 // Every fourth year is a leap year. 2004, 2008, and 2012 are leap years.
155 // However, every hundredth year is not a leap year. 1900 and 2100 are not leap years.
156 // Every four hundred years, there's a leap year after all. 2000 and 2400 are leap years.
158 static const int leapDaysBefore1971By4Rule
= 1970 / 4;
159 static const int excludedLeapDaysBefore1971By100Rule
= 1970 / 100;
160 static const int leapDaysBefore1971By400Rule
= 1970 / 400;
162 const double yearMinusOne
= year
- 1;
163 const double yearsToAddBy4Rule
= floor(yearMinusOne
/ 4.0) - leapDaysBefore1971By4Rule
;
164 const double yearsToExcludeBy100Rule
= floor(yearMinusOne
/ 100.0) - excludedLeapDaysBefore1971By100Rule
;
165 const double yearsToAddBy400Rule
= floor(yearMinusOne
/ 400.0) - leapDaysBefore1971By400Rule
;
167 return 365.0 * (year
- 1970) + yearsToAddBy4Rule
- yearsToExcludeBy100Rule
+ yearsToAddBy400Rule
;
170 static inline double msToDays(double ms
)
172 return floor(ms
/ msPerDay
);
175 int msToYear(double ms
)
177 int approxYear
= static_cast<int>(floor(ms
/ (msPerDay
* 365.2425)) + 1970);
178 double msFromApproxYearTo1970
= msPerDay
* daysFrom1970ToYear(approxYear
);
179 if (msFromApproxYearTo1970
> ms
)
180 return approxYear
- 1;
181 if (msFromApproxYearTo1970
+ msPerDay
* daysInYear(approxYear
) <= ms
)
182 return approxYear
+ 1;
186 int dayInYear(double ms
, int year
)
188 return static_cast<int>(msToDays(ms
) - daysFrom1970ToYear(year
));
191 static inline double msToMilliseconds(double ms
)
193 double result
= fmod(ms
, msPerDay
);
199 // 0: Sunday, 1: Monday, etc.
200 static inline int msToWeekDay(double ms
)
202 int wd
= (static_cast<int>(msToDays(ms
)) + 4) % 7;
208 static inline int msToSeconds(double ms
)
210 double result
= fmod(floor(ms
/ msPerSecond
), secondsPerMinute
);
212 result
+= secondsPerMinute
;
213 return static_cast<int>(result
);
216 static inline int msToMinutes(double ms
)
218 double result
= fmod(floor(ms
/ msPerMinute
), minutesPerHour
);
220 result
+= minutesPerHour
;
221 return static_cast<int>(result
);
224 static inline int msToHours(double ms
)
226 double result
= fmod(floor(ms
/msPerHour
), hoursPerDay
);
228 result
+= hoursPerDay
;
229 return static_cast<int>(result
);
232 int monthFromDayInYear(int dayInYear
, bool leapYear
)
234 const int d
= dayInYear
;
239 step
+= (leapYear
? 29 : 28);
242 if (d
< (step
+= 31))
244 if (d
< (step
+= 30))
246 if (d
< (step
+= 31))
248 if (d
< (step
+= 30))
250 if (d
< (step
+= 31))
252 if (d
< (step
+= 31))
254 if (d
< (step
+= 30))
256 if (d
< (step
+= 31))
258 if (d
< (step
+= 30))
263 static inline bool checkMonth(int dayInYear
, int& startDayOfThisMonth
, int& startDayOfNextMonth
, int daysInThisMonth
)
265 startDayOfThisMonth
= startDayOfNextMonth
;
266 startDayOfNextMonth
+= daysInThisMonth
;
267 return (dayInYear
<= startDayOfNextMonth
);
270 int dayInMonthFromDayInYear(int dayInYear
, bool leapYear
)
272 const int d
= dayInYear
;
278 const int daysInFeb
= (leapYear
? 29 : 28);
279 if (checkMonth(d
, step
, next
, daysInFeb
))
281 if (checkMonth(d
, step
, next
, 31))
283 if (checkMonth(d
, step
, next
, 30))
285 if (checkMonth(d
, step
, next
, 31))
287 if (checkMonth(d
, step
, next
, 30))
289 if (checkMonth(d
, step
, next
, 31))
291 if (checkMonth(d
, step
, next
, 31))
293 if (checkMonth(d
, step
, next
, 30))
295 if (checkMonth(d
, step
, next
, 31))
297 if (checkMonth(d
, step
, next
, 30))
303 static inline int monthToDayInYear(int month
, bool isLeapYear
)
305 return firstDayOfMonth
[isLeapYear
][month
];
308 static inline double timeToMS(double hour
, double min
, double sec
, double ms
)
310 return (((hour
* minutesPerHour
+ min
) * secondsPerMinute
+ sec
) * msPerSecond
+ ms
);
313 double dateToDaysFrom1970(int year
, int month
, int day
)
323 double yearday
= floor(daysFrom1970ToYear(year
));
324 ASSERT((year
>= 1970 && yearday
>= 0) || (year
< 1970 && yearday
< 0));
325 int monthday
= monthToDayInYear(month
, isLeapYear(year
));
327 return yearday
+ monthday
+ day
- 1;
330 // There is a hard limit at 2038 that we currently do not have a workaround
331 // for (rdar://problem/5052975).
332 static inline int maximumYearForDST()
337 static inline int minimumYearForDST()
339 // Because of the 2038 issue (see maximumYearForDST) if the current year is
340 // greater than the max year minus 27 (2010), we want to use the max year
341 // minus 27 instead, to ensure there is a range of 28 years that all years
343 return std::min(msToYear(jsCurrentTime()), maximumYearForDST() - 27) ;
347 * Find an equivalent year for the one given, where equivalence is deterined by
348 * the two years having the same leapness and the first day of the year, falling
349 * on the same day of the week.
351 * This function returns a year between this current year and 2037, however this
352 * function will potentially return incorrect results if the current year is after
353 * 2010, (rdar://problem/5052975), if the year passed in is before 1900 or after
354 * 2100, (rdar://problem/5055038).
356 int equivalentYearForDST(int year
)
358 // It is ok if the cached year is not the current year as long as the rules
359 // for DST did not change between the two years; if they did the app would need
361 static int minYear
= minimumYearForDST();
362 int maxYear
= maximumYearForDST();
366 difference
= minYear
- year
;
367 else if (year
< minYear
)
368 difference
= maxYear
- year
;
372 int quotient
= difference
/ 28;
373 int product
= (quotient
) * 28;
376 ASSERT((year
>= minYear
&& year
<= maxYear
) || (product
- year
== static_cast<int>(NaN
)));
380 static int32_t calculateUTCOffset()
383 time_t localTime
= static_cast<time_t>(currentTime());
385 time_t localTime
= time(0);
388 getLocalTime(&localTime
, &localt
);
390 // Get the difference between this time zone and UTC on the 1st of January of this year.
396 // Not setting localt.tm_year!
401 localt
.tm_gmtoff
= 0;
408 time_t utcOffset
= timegm(&localt
) - mktime(&localt
);
410 // Using a canned date of 01/01/2009 on platforms with weaker date-handling foo.
411 localt
.tm_year
= 109;
412 time_t utcOffset
= 1230768000 - mktime(&localt
);
415 return static_cast<int32_t>(utcOffset
* 1000);
419 * Get the DST offset for the time passed in.
421 static double calculateDSTOffsetSimple(double localTimeSeconds
, double utcOffset
)
423 if (localTimeSeconds
> maxUnixTime
)
424 localTimeSeconds
= maxUnixTime
;
425 else if (localTimeSeconds
< 0) // Go ahead a day to make localtime work (does not work with 0)
426 localTimeSeconds
+= secondsPerDay
;
428 //input is UTC so we have to shift back to local time to determine DST thus the + getUTCOffset()
429 double offsetTime
= (localTimeSeconds
* msPerSecond
) + utcOffset
;
431 // Offset from UTC but doesn't include DST obviously
432 int offsetHour
= msToHours(offsetTime
);
433 int offsetMinute
= msToMinutes(offsetTime
);
435 // FIXME: time_t has a potential problem in 2038
436 time_t localTime
= static_cast<time_t>(localTimeSeconds
);
439 getLocalTime(&localTime
, &localTM
);
441 double diff
= ((localTM
.tm_hour
- offsetHour
) * secondsPerHour
) + ((localTM
.tm_min
- offsetMinute
) * 60);
444 diff
+= secondsPerDay
;
446 return (diff
* msPerSecond
);
449 // Get the DST offset, given a time in UTC
450 static double calculateDSTOffset(double ms
, double utcOffset
)
452 // On Mac OS X, the call to localtime (see calculateDSTOffsetSimple) will return historically accurate
453 // DST information (e.g. New Zealand did not have DST from 1946 to 1974) however the JavaScript
454 // standard explicitly dictates that historical information should not be considered when
455 // determining DST. For this reason we shift away from years that localtime can handle but would
456 // return historically accurate information.
457 int year
= msToYear(ms
);
458 int equivalentYear
= equivalentYearForDST(year
);
459 if (year
!= equivalentYear
) {
460 bool leapYear
= isLeapYear(year
);
461 int dayInYearLocal
= dayInYear(ms
, year
);
462 int dayInMonth
= dayInMonthFromDayInYear(dayInYearLocal
, leapYear
);
463 int month
= monthFromDayInYear(dayInYearLocal
, leapYear
);
464 double day
= dateToDaysFrom1970(equivalentYear
, month
, dayInMonth
);
465 ms
= (day
* msPerDay
) + msToMilliseconds(ms
);
468 return calculateDSTOffsetSimple(ms
/ msPerSecond
, utcOffset
);
471 void initializeDates()
474 static bool alreadyInitialized
;
475 ASSERT(!alreadyInitialized
);
476 alreadyInitialized
= true;
479 equivalentYearForDST(2000); // Need to call once to initialize a static used in this function.
482 static inline double ymdhmsToSeconds(long year
, int mon
, int day
, int hour
, int minute
, int second
)
484 double days
= (day
- 32075)
485 + floor(1461 * (year
+ 4800.0 + (mon
- 14) / 12) / 4)
486 + 367 * (mon
- 2 - (mon
- 14) / 12 * 12) / 12
487 - floor(3 * ((year
+ 4900.0 + (mon
- 14) / 12) / 100) / 4)
489 return ((days
* hoursPerDay
+ hour
) * minutesPerHour
+ minute
) * secondsPerMinute
+ second
;
492 // We follow the recommendation of RFC 2822 to consider all
493 // obsolete time zones not listed here equivalent to "-0000".
494 static const struct KnownZone
{
513 inline static void skipSpacesAndComments(const char*& s
)
518 if (!isASCIISpace(ch
)) {
521 else if (ch
== ')' && nesting
> 0)
523 else if (nesting
== 0)
530 // returns 0-11 (Jan-Dec); -1 on failure
531 static int findMonth(const char* monthStr
)
535 for (int i
= 0; i
< 3; ++i
) {
538 needle
[i
] = static_cast<char>(toASCIILower(*monthStr
++));
541 const char *haystack
= "janfebmaraprmayjunjulaugsepoctnovdec";
542 const char *str
= strstr(haystack
, needle
);
544 int position
= static_cast<int>(str
- haystack
);
545 if (position
% 3 == 0)
551 static bool parseLong(const char* string
, char** stopPosition
, int base
, long* result
)
553 *result
= strtol(string
, stopPosition
, base
);
554 // Avoid the use of errno as it is not available on Windows CE
555 if (string
== *stopPosition
|| *result
== LONG_MIN
|| *result
== LONG_MAX
)
560 // Odd case where 'exec' is allowed to be 0, to accomodate a caller in WebCore.
561 static double parseDateFromNullTerminatedCharacters(const char* dateString
, bool& haveTZ
, int& offset
)
566 // This parses a date in the form:
567 // Tuesday, 09-Nov-99 23:12:40 GMT
569 // Sat, 01-Jan-2000 08:00:00 GMT
571 // Sat, 01 Jan 2000 08:00:00 GMT
573 // 01 Jan 99 22:00 +0100 (exceptions in rfc822/rfc2822)
574 // ### non RFC formats, added for Javascript:
575 // [Wednesday] January 09 1999 23:12:40 GMT
576 // [Wednesday] January 09 23:12:40 GMT 1999
578 // We ignore the weekday.
580 // Skip leading space
581 skipSpacesAndComments(dateString
);
584 const char *wordStart
= dateString
;
585 // Check contents of first words if not number
586 while (*dateString
&& !isASCIIDigit(*dateString
)) {
587 if (isASCIISpace(*dateString
) || *dateString
== '(') {
588 if (dateString
- wordStart
>= 3)
589 month
= findMonth(wordStart
);
590 skipSpacesAndComments(dateString
);
591 wordStart
= dateString
;
596 // Missing delimiter between month and day (like "January29")?
597 if (month
== -1 && wordStart
!= dateString
)
598 month
= findMonth(wordStart
);
600 skipSpacesAndComments(dateString
);
605 // ' 09-Nov-99 23:12:40 GMT'
608 if (!parseLong(dateString
, &newPosStr
, 10, &day
))
610 dateString
= newPosStr
;
620 // ### where is the boundary and what happens below?
621 if (*dateString
!= '/')
623 // looks like a YYYY/MM/DD date
627 if (!parseLong(dateString
, &newPosStr
, 10, &month
))
630 dateString
= newPosStr
;
631 if (*dateString
++ != '/' || !*dateString
)
633 if (!parseLong(dateString
, &newPosStr
, 10, &day
))
635 dateString
= newPosStr
;
636 } else if (*dateString
== '/' && month
== -1) {
638 // This looks like a MM/DD/YYYY date, not an RFC date.
639 month
= day
- 1; // 0-based
640 if (!parseLong(dateString
, &newPosStr
, 10, &day
))
642 if (day
< 1 || day
> 31)
644 dateString
= newPosStr
;
645 if (*dateString
== '/')
650 if (*dateString
== '-')
653 skipSpacesAndComments(dateString
);
655 if (*dateString
== ',')
658 if (month
== -1) { // not found yet
659 month
= findMonth(dateString
);
663 while (*dateString
&& *dateString
!= '-' && *dateString
!= ',' && !isASCIISpace(*dateString
))
669 // '-99 23:12:40 GMT'
670 if (*dateString
!= '-' && *dateString
!= '/' && *dateString
!= ',' && !isASCIISpace(*dateString
))
676 if (month
< 0 || month
> 11)
680 if (year
<= 0 && *dateString
) {
681 if (!parseLong(dateString
, &newPosStr
, 10, &year
))
685 // Don't fail if the time is missing.
690 dateString
= newPosStr
;
693 if (!(isASCIISpace(*newPosStr
) || *newPosStr
== ',')) {
694 if (*newPosStr
!= ':')
696 // There was no year; the number was the hour.
699 // in the normal case (we parsed the year), advance to the next number
700 dateString
= ++newPosStr
;
701 skipSpacesAndComments(dateString
);
704 parseLong(dateString
, &newPosStr
, 10, &hour
);
705 // Do not check for errno here since we want to continue
706 // even if errno was set becasue we are still looking
709 // Read a number? If not, this might be a timezone name.
710 if (newPosStr
!= dateString
) {
711 dateString
= newPosStr
;
713 if (hour
< 0 || hour
> 23)
720 if (*dateString
++ != ':')
723 if (!parseLong(dateString
, &newPosStr
, 10, &minute
))
725 dateString
= newPosStr
;
727 if (minute
< 0 || minute
> 59)
731 if (*dateString
&& *dateString
!= ':' && !isASCIISpace(*dateString
))
734 // seconds are optional in rfc822 + rfc2822
735 if (*dateString
==':') {
738 if (!parseLong(dateString
, &newPosStr
, 10, &second
))
740 dateString
= newPosStr
;
742 if (second
< 0 || second
> 59)
746 skipSpacesAndComments(dateString
);
748 if (strncasecmp(dateString
, "AM", 2) == 0) {
754 skipSpacesAndComments(dateString
);
755 } else if (strncasecmp(dateString
, "PM", 2) == 0) {
761 skipSpacesAndComments(dateString
);
766 // Don't fail if the time zone is missing.
767 // Some websites omit the time zone (4275206).
769 if (strncasecmp(dateString
, "GMT", 3) == 0 || strncasecmp(dateString
, "UTC", 3) == 0) {
774 if (*dateString
== '+' || *dateString
== '-') {
776 if (!parseLong(dateString
, &newPosStr
, 10, &o
))
778 dateString
= newPosStr
;
780 if (o
< -9959 || o
> 9959)
783 int sgn
= (o
< 0) ? -1 : 1;
785 if (*dateString
!= ':') {
786 offset
= ((o
/ 100) * 60 + (o
% 100)) * sgn
;
787 } else { // GMT+05:00
789 if (!parseLong(dateString
, &newPosStr
, 10, &o2
))
791 dateString
= newPosStr
;
792 offset
= (o
* 60 + o2
) * sgn
;
796 for (int i
= 0; i
< int(sizeof(known_zones
) / sizeof(KnownZone
)); i
++) {
797 if (0 == strncasecmp(dateString
, known_zones
[i
].tzName
, strlen(known_zones
[i
].tzName
))) {
798 offset
= known_zones
[i
].tzOffset
;
799 dateString
+= strlen(known_zones
[i
].tzName
);
807 skipSpacesAndComments(dateString
);
809 if (*dateString
&& year
== -1) {
810 if (!parseLong(dateString
, &newPosStr
, 10, &year
))
812 dateString
= newPosStr
;
815 skipSpacesAndComments(dateString
);
821 // Y2K: Handle 2 digit years.
822 if (year
>= 0 && year
< 100) {
829 return ymdhmsToSeconds(year
, month
+ 1, day
, hour
, minute
, second
) * msPerSecond
;
832 double parseDateFromNullTerminatedCharacters(const char* dateString
)
836 double ms
= parseDateFromNullTerminatedCharacters(dateString
, haveTZ
, offset
);
840 // fall back to local timezone
842 double utcOffset
= calculateUTCOffset();
843 double dstOffset
= calculateDSTOffset(ms
, utcOffset
);
844 offset
= static_cast<int>((utcOffset
+ dstOffset
) / msPerMinute
);
846 return ms
- (offset
* msPerMinute
);
849 double timeClip(double t
)
853 if (fabs(t
) > maxECMAScriptTime
)
862 // Get the DST offset for the time passed in.
864 // NOTE: The implementation relies on the fact that no time zones have
865 // more than one daylight savings offset change per month.
866 // If this function is called with NaN it returns NaN.
867 static double getDSTOffset(ExecState
* exec
, double ms
, double utcOffset
)
869 DSTOffsetCache
& cache
= exec
->globalData().dstOffsetCache
;
870 double start
= cache
.start
;
871 double end
= cache
.end
;
874 // If the time fits in the cached interval, return the cached offset.
875 if (ms
<= end
) return cache
.offset
;
877 // Compute a possible new interval end.
878 double newEnd
= end
+ cache
.increment
;
881 double endOffset
= calculateDSTOffset(newEnd
, utcOffset
);
882 if (cache
.offset
== endOffset
) {
883 // If the offset at the end of the new interval still matches
884 // the offset in the cache, we grow the cached time interval
885 // and return the offset.
887 cache
.increment
= msPerMonth
;
890 double offset
= calculateDSTOffset(ms
, utcOffset
);
891 if (offset
== endOffset
) {
892 // The offset at the given time is equal to the offset at the
893 // new end of the interval, so that means that we've just skipped
894 // the point in time where the DST offset change occurred. Updated
895 // the interval to reflect this and reset the increment.
898 cache
.increment
= msPerMonth
;
900 // The interval contains a DST offset change and the given time is
901 // before it. Adjust the increment to avoid a linear search for
902 // the offset change point and change the end of the interval.
903 cache
.increment
/= 3;
906 // Update the offset in the cache and return it.
907 cache
.offset
= offset
;
913 // Compute the DST offset for the time and shrink the cache interval
914 // to only contain the time. This allows fast repeated DST offset
915 // computations for the same time.
916 double offset
= calculateDSTOffset(ms
, utcOffset
);
917 cache
.offset
= offset
;
920 cache
.increment
= msPerMonth
;
925 * Get the difference in milliseconds between this time zone and UTC (GMT)
928 double getUTCOffset(ExecState
* exec
)
930 double utcOffset
= exec
->globalData().cachedUTCOffset
;
931 if (!isnan(utcOffset
))
933 exec
->globalData().cachedUTCOffset
= calculateUTCOffset();
934 return exec
->globalData().cachedUTCOffset
;
937 double gregorianDateTimeToMS(ExecState
* exec
, const GregorianDateTime
& t
, double milliSeconds
, bool inputIsUTC
)
939 double day
= dateToDaysFrom1970(t
.year
+ 1900, t
.month
, t
.monthDay
);
940 double ms
= timeToMS(t
.hour
, t
.minute
, t
.second
, milliSeconds
);
941 double result
= (day
* WTF::msPerDay
) + ms
;
943 if (!inputIsUTC
) { // convert to UTC
944 double utcOffset
= getUTCOffset(exec
);
946 result
-= getDSTOffset(exec
, result
, utcOffset
);
953 void msToGregorianDateTime(ExecState
* exec
, double ms
, bool outputIsUTC
, GregorianDateTime
& tm
)
958 utcOff
= getUTCOffset(exec
);
959 dstOff
= getDSTOffset(exec
, ms
, utcOff
);
960 ms
+= dstOff
+ utcOff
;
963 const int year
= msToYear(ms
);
964 tm
.second
= msToSeconds(ms
);
965 tm
.minute
= msToMinutes(ms
);
966 tm
.hour
= msToHours(ms
);
967 tm
.weekDay
= msToWeekDay(ms
);
968 tm
.yearDay
= dayInYear(ms
, year
);
969 tm
.monthDay
= dayInMonthFromDayInYear(tm
.yearDay
, isLeapYear(year
));
970 tm
.month
= monthFromDayInYear(tm
.yearDay
, isLeapYear(year
));
971 tm
.year
= year
- 1900;
972 tm
.isDST
= dstOff
!= 0.0;
973 tm
.utcOffset
= static_cast<long>((dstOff
+ utcOff
) / WTF::msPerSecond
);
977 double parseDateFromNullTerminatedCharacters(ExecState
* exec
, const char* dateString
)
982 double ms
= WTF::parseDateFromNullTerminatedCharacters(dateString
, haveTZ
, offset
);
986 // fall back to local timezone
988 double utcOffset
= getUTCOffset(exec
);
989 double dstOffset
= getDSTOffset(exec
, ms
, utcOffset
);
990 offset
= static_cast<int>((utcOffset
+ dstOffset
) / WTF::msPerMinute
);
992 return ms
- (offset
* WTF::msPerMinute
);