2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3 * Copyright (C) 2006 Apple Computer
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is Mozilla Communicator client code, released
20 * The Initial Developer of the Original Code is
21 * Netscape Communications Corporation.
22 * Portions created by the Initial Developer are Copyright (C) 1998
23 * the Initial Developer. All Rights Reserved.
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
45 #include <wtf/OwnPtr.h>
51 static const double secondsPerHour = 60.0 * 60.0;
52 static const double minutesPerDay = 24.0 * 60.0;
53 static const double secondsPerDay = 24.0 * 60.0 * 60.0;
54 static const double secondsPerYear = 24.0 * 60.0 * 60.0 * 365.0;
57 static const double usecPerMsec = 1000.0;
58 static const double usecPerSec = 1000000.0;
60 static const double maxUnixTime = 2145859200.0; /*equivalent to 12/31/2037 */
63 * The following array contains the day of year for the first day of
64 * each month, where index 0 is January, and day 0 is January 1.
66 static int firstDayOfMonth[2][12] = {
67 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
68 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
73 * Years and leap years on which Jan 1 is a Sunday, Monday, etc.
75 * yearStartingWith[0][i] is an example non-leap year where
76 * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
78 * yearStartingWith[1][i] is an example leap year where
79 * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
81 static int yearStartingWith[2][7] = {
82 {1978, 1973, 1974, 1975, 1981, 1971, 1977},
83 {1984, 1996, 1980, 1992, 1976, 1988, 1972}
87 static inline int daysInYear(int year)
98 static inline double daysFrom1970ToYear(int year)
100 return 365.0 * (year - 1970)
101 + floor((year - 1969) / 4.0)
102 - floor((year - 1901) / 100.0)
103 + floor((year - 1601) / 400.0);
106 static inline double msFrom1970ToYear(int year)
108 return msPerDay * daysFrom1970ToYear(year);
111 static inline double msToDays(double ms)
113 return floor(ms / msPerDay);
116 static inline int msToYear(double ms)
118 int y = static_cast<int>(floor(ms /(msPerDay*365.2425)) + 1970);
119 double t2 = msFrom1970ToYear(y);
124 if (t2 + msPerDay * daysInYear(y) <= ms)
130 static inline bool isLeapYear(int year)
141 static inline bool isInLeapYear(double ms)
143 return isLeapYear(msToYear(ms));
146 static inline int dayInYear(double ms, int year)
148 return static_cast<int>(msToDays(ms) - daysFrom1970ToYear(year));
151 static inline double msToMilliseconds(double ms)
154 result = fmod(ms, msPerDay);
160 // 0: Sunday, 1: Monday, etc.
161 static inline int msToWeekDay(double ms)
163 int wd = ((int)msToDays(ms) + 4) % 7;
169 static inline int msToSeconds(double ms)
171 int result = (int) fmod(floor(ms / msPerSecond), secondsPerMinute);
173 result += (int)secondsPerMinute;
177 static inline int msToMinutes(double ms)
179 int result = (int) fmod(floor(ms / msPerMinute), minutesPerHour);
181 result += (int)minutesPerHour;
185 static inline int msToHours(double ms)
187 int result = (int) fmod(floor(ms/msPerHour), hoursPerDay);
189 result += (int)hoursPerDay;
193 static inline int msToMonth(double ms)
196 int year = msToYear(ms);
197 d = dayInYear(ms, year);
201 step += (isInLeapYear(ms) ? 29 : 28);
204 if (d < (step += 31))
206 if (d < (step += 30))
208 if (d < (step += 31))
210 if (d < (step += 30))
212 if (d < (step += 31))
214 if (d < (step += 31))
216 if (d < (step += 30))
218 if (d < (step += 31))
220 if (d < (step += 30))
225 static inline int msToDayInMonth(double ms)
228 int year = msToYear(ms);
229 d = dayInYear(ms, year);
231 if (d <= (next = 30))
234 next += (isInLeapYear(ms) ? 29 : 28);
238 if (d <= (next += 31))
241 if (d <= (next += 30))
244 if (d <= (next += 31))
247 if (d <= (next += 30))
250 if (d <= (next += 31))
253 if (d <= (next += 31))
256 if (d <= (next += 30))
259 if (d <= (next += 31))
262 if (d <= (next += 30))
268 static inline int monthToDayInYear(int month, bool isLeapYear)
270 return firstDayOfMonth[isLeapYear][month];
273 static inline double timeToMseconds(double hour, double min, double sec, double ms)
275 return (((hour * minutesPerHour + min) * secondsPerMinute + sec) * msPerSecond + ms);
278 static int dateToDayInYear(int year, int month, int day)
280 year += static_cast<int>(floor(month / 12.0));
282 month = static_cast<int>(fmod(month, 12.0));
286 int yearday = static_cast<int>(floor(msFrom1970ToYear(year) / msPerDay));
287 int monthday = monthToDayInYear(month, isLeapYear(year));
289 return yearday + monthday + day - 1;
293 * Find a year for which any given date will fall on the same weekday.
295 * This function should be used with caution when used other than
296 * for determining DST; it hasn't been proven not to produce an
297 * incorrect year for times near year boundaries.
299 static inline int equivalentYearForDST(int year)
303 day = (int) daysFrom1970ToYear(year) + 4;
309 return yearStartingWith[isLeapYear(year)][day];
313 * Get the difference in milliseconds between this time zone and UTC (GMT)
316 double getUTCOffset() {
317 static double utcOffset;
318 static bool utcOffsetInitialized = false;
319 if (!utcOffsetInitialized) {
330 /* get the difference between this time zone and GMT */
334 #if !PLATFORM(WIN_OS)
339 utcOffset = mktime(<ime) - (hoursPerDay * secondsPerHour);
340 utcOffset *= -msPerSecond;
342 utcOffsetInitialized = true;
348 * Get the DST offset for the time passed in. Takes
349 * seconds (not milliseconds) and cannot handle dates before 1970
352 static double getDSTOffsetSimple(double localTimeSeconds)
354 if(localTimeSeconds > maxUnixTime)
355 localTimeSeconds = maxUnixTime;
356 else if(localTimeSeconds < 0) /*go ahead a day to make localtime work (does not work with 0) */
357 localTimeSeconds = secondsPerDay;
359 double offsetTime = (localTimeSeconds * usecPerMsec) + getUTCOffset() ;
362 prtm.tm_min = msToMinutes(offsetTime);
363 prtm.tm_hour = msToHours(offsetTime);
365 // FIXME: time_t has a potential problem in 2038
366 time_t localTime = static_cast<time_t>(localTimeSeconds);
370 localtime_s(&tm, &localTime);
372 localtime_r(&localTime, &tm);
375 double diff = ((tm.tm_hour - prtm.tm_hour) * secondsPerHour) + ((tm.tm_min - prtm.tm_min) * 60);
378 diff += secondsPerDay;
380 return (diff * usecPerMsec);
383 // get the DST offset the time passed in
384 static double getDSTOffset(double ms)
387 * If earlier than 1970 or after 2038, potentially beyond the ken of
388 * many OSes, map it to an equivalent year before asking.
390 if (ms < 0.0 || ms > 2145916800000.0) {
394 year = equivalentYearForDST(msToYear(ms));
395 day = dateToDayInYear(year, msToMonth(ms), msToDayInMonth(ms));
396 ms = (day * msPerDay) + msToMilliseconds(ms);
399 /* put our ms in an LL, and map it to usec for prtime */
400 return getDSTOffsetSimple(ms / usecPerMsec);
403 static inline double localTimeToUTC(double ms)
405 ms -= getUTCOffset();
406 ms -= getDSTOffset(ms);
410 static inline double UTCToLocalTime(double ms)
412 ms += getUTCOffset();
413 ms += getDSTOffset(ms);
417 double dateToMseconds(tm* t, double ms, bool inputIsUTC)
419 int day = dateToDayInYear(t->tm_year + 1900, t->tm_mon, t->tm_mday);
420 double msec_time = timeToMseconds(t->tm_hour, t->tm_min, t->tm_sec, ms);
421 double result = (day * msPerDay) + msec_time;
424 result = localTimeToUTC(result);
429 void msToTM(double ms, bool outputIsUTC, struct tm& tm)
433 ms = UTCToLocalTime(ms);
435 tm.tm_sec = msToSeconds(ms);
436 tm.tm_min = msToMinutes(ms);
437 tm.tm_hour = msToHours(ms);
438 tm.tm_wday = msToWeekDay(ms);
439 tm.tm_mday = msToDayInMonth(ms);
440 tm.tm_yday = dayInYear(ms, msToYear(ms));
441 tm.tm_mon = msToMonth(ms);
442 tm.tm_year = msToYear(ms) - 1900;
443 tm.tm_isdst = isDST(ms);
445 //everyone else seems to have these fields
446 #if !PLATFORM(WIN_OS)
448 // FIXME: time_t has a potential problem in 2038
449 time_t seconds = static_cast<time_t>(ms/usecPerMsec);
450 localtime_r(&seconds, &xtm);
451 tm.tm_gmtoff = xtm.tm_gmtoff;
452 tm.tm_zone = xtm.tm_zone;
456 bool isDST(const double& ms)
458 return getDSTOffset(ms) != 0;