source: webkit/trunk/JavaScriptCore/kjs/DateMath.cpp@ 17333

Last change on this file since 17333 was 17333, checked in by weinig, 19 years ago

Reviewed by Darin.

Fix build with older gcc 3.3.4.

  • kjs/DateMath.cpp: Remove inline prefix. (KJS::equivalentYearForDST):
File size: 11.0 KB
Line 
1/*
2 * Copyright (C) 1999-2000 Harri Porten ([email protected])
3 * Copyright (C) 2006 Apple Computer
4 *
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 *
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/
11 *
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
15 * License.
16 *
17 * The Original Code is Mozilla Communicator client code, released
18 * March 31, 1998.
19 *
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.
24 *
25 * Contributor(s):
26 *
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.
38 *
39 */
40
41#include "config.h"
42#include "DateMath.h"
43
44#include <math.h>
45#include <stdint.h>
46#include <wtf/OwnPtr.h>
47
48namespace KJS {
49
50/* Constants */
51
52static const double minutesPerDay = 24.0 * 60.0;
53static const double secondsPerDay = 24.0 * 60.0 * 60.0;
54static const double secondsPerYear = 24.0 * 60.0 * 60.0 * 365.0;
55
56static const double usecPerSec = 1000000.0;
57
58static const double maxUnixTime = 2145859200.0; /*equivalent to 12/31/2037 */
59
60/*
61 * The following array contains the day of year for the first day of
62 * each month, where index 0 is January, and day 0 is January 1.
63 */
64static int firstDayOfMonth[2][12] = {
65 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
66 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
67};
68
69
70/*
71 * Years and leap years on which Jan 1 is a Sunday, Monday, etc.
72 *
73 * yearStartingWith[0][i] is an example non-leap year where
74 * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
75 *
76 * yearStartingWith[1][i] is an example leap year where
77 * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
78 */
79static int yearStartingWith[2][7] = {
80 {1978, 1973, 1974, 1975, 1981, 1971, 1977},
81 {1984, 1996, 1980, 1992, 1976, 1988, 1972}
82};
83
84
85static inline int daysInYear(int year)
86{
87 if (year % 4 != 0)
88 return 365;
89 if (year % 400 == 0)
90 return 366;
91 if (year % 100 == 0)
92 return 365;
93 return 366;
94}
95
96static inline double daysFrom1970ToYear(int year)
97{
98 return 365.0 * (year - 1970)
99 + floor((year - 1969) / 4.0)
100 - floor((year - 1901) / 100.0)
101 + floor((year - 1601) / 400.0);
102}
103
104static inline double msFrom1970ToYear(int year)
105{
106 return msPerDay * daysFrom1970ToYear(year);
107}
108
109static inline double msToDays(double ms)
110{
111 return floor(ms / msPerDay);
112}
113
114static inline int msToYear(double ms)
115{
116 int y = static_cast<int>(floor(ms /(msPerDay*365.2425)) + 1970);
117 double t2 = msFrom1970ToYear(y);
118
119 if (t2 > ms) {
120 y--;
121 } else {
122 if (t2 + msPerDay * daysInYear(y) <= ms)
123 y++;
124 }
125 return y;
126}
127
128static inline bool isLeapYear(int year)
129{
130 if (year % 4 != 0)
131 return false;
132 if (year % 400 == 0)
133 return true;
134 if (year % 100 == 0)
135 return false;
136 return true;
137}
138
139static inline bool isInLeapYear(double ms)
140{
141 return isLeapYear(msToYear(ms));
142}
143
144static inline int dayInYear(double ms, int year)
145{
146 return static_cast<int>(msToDays(ms) - daysFrom1970ToYear(year));
147}
148
149static inline double msToMilliseconds(double ms)
150{
151 double result;
152 result = fmod(ms, msPerDay);
153 if (result < 0)
154 result += msPerDay;
155 return result;
156}
157
158// 0: Sunday, 1: Monday, etc.
159static inline int msToWeekDay(double ms)
160{
161 int wd = ((int)msToDays(ms) + 4) % 7;
162 if (wd < 0)
163 wd += 7;
164 return wd;
165}
166
167static inline int msToSeconds(double ms)
168{
169 int result = (int) fmod(floor(ms / msPerSecond), secondsPerMinute);
170 if (result < 0)
171 result += (int)secondsPerMinute;
172 return result;
173}
174
175static inline int msToMinutes(double ms)
176{
177 int result = (int) fmod(floor(ms / msPerMinute), minutesPerHour);
178 if (result < 0)
179 result += (int)minutesPerHour;
180 return result;
181}
182
183static inline int msToHours(double ms)
184{
185 int result = (int) fmod(floor(ms/msPerHour), hoursPerDay);
186 if (result < 0)
187 result += (int)hoursPerDay;
188 return result;
189}
190
191static inline int msToMonth(double ms)
192{
193 int d, step;
194 int year = msToYear(ms);
195 d = dayInYear(ms, year);
196
197 if (d < (step = 31))
198 return 0;
199 step += (isInLeapYear(ms) ? 29 : 28);
200 if (d < step)
201 return 1;
202 if (d < (step += 31))
203 return 2;
204 if (d < (step += 30))
205 return 3;
206 if (d < (step += 31))
207 return 4;
208 if (d < (step += 30))
209 return 5;
210 if (d < (step += 31))
211 return 6;
212 if (d < (step += 31))
213 return 7;
214 if (d < (step += 30))
215 return 8;
216 if (d < (step += 31))
217 return 9;
218 if (d < (step += 30))
219 return 10;
220 return 11;
221}
222
223static inline int msToDayInMonth(double ms)
224{
225 int d, step, next;
226 int year = msToYear(ms);
227 d = dayInYear(ms, year);
228
229 if (d <= (next = 30))
230 return d + 1;
231 step = next;
232 next += (isInLeapYear(ms) ? 29 : 28);
233 if (d <= next)
234 return d - step;
235 step = next;
236 if (d <= (next += 31))
237 return d - step;
238 step = next;
239 if (d <= (next += 30))
240 return d - step;
241 step = next;
242 if (d <= (next += 31))
243 return d - step;
244 step = next;
245 if (d <= (next += 30))
246 return d - step;
247 step = next;
248 if (d <= (next += 31))
249 return d - step;
250 step = next;
251 if (d <= (next += 31))
252 return d - step;
253 step = next;
254 if (d <= (next += 30))
255 return d - step;
256 step = next;
257 if (d <= (next += 31))
258 return d - step;
259 step = next;
260 if (d <= (next += 30))
261 return d - step;
262 step = next;
263 return d - step;
264}
265
266static inline int monthToDayInYear(int month, bool isLeapYear)
267{
268 return firstDayOfMonth[isLeapYear][month];
269}
270
271static inline double timeToMS(double hour, double min, double sec, double ms)
272{
273 return (((hour * minutesPerHour + min) * secondsPerMinute + sec) * msPerSecond + ms);
274}
275
276static int dateToDayInYear(int year, int month, int day)
277{
278 year += month / 12;
279
280 month %= 12;
281 if (month < 0) {
282 month += 12;
283 --year;
284 }
285
286 int yearday = static_cast<int>(floor(msFrom1970ToYear(year) / msPerDay));
287 int monthday = monthToDayInYear(month, isLeapYear(year));
288
289 return yearday + monthday + day - 1;
290}
291
292/*
293 * Find a year for which any given date will fall on the same weekday.
294 *
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.
298 */
299int equivalentYearForDST(int year)
300{
301 int day;
302
303 day = (int) daysFrom1970ToYear(year) + 4;
304 day %= 7;
305
306 if (day < 0)
307 day += 7;
308
309 return yearStartingWith[isLeapYear(year)][day];
310}
311
312/*
313 * Get the difference in milliseconds between this time zone and UTC (GMT)
314 * NOT including DST.
315 */
316double getUTCOffset() {
317 static double utcOffset;
318 static bool utcOffsetInitialized = false;
319 if (!utcOffsetInitialized) {
320 tm localt;
321
322 memset(&localt, 0, sizeof(localt));
323
324 // get the difference between this time zone and GMT
325 localt.tm_mday = 2;
326 localt.tm_year = 70;
327
328 utcOffset = mktime(&localt) - (hoursPerDay * secondsPerHour);
329 utcOffset *= -msPerSecond;
330
331 utcOffsetInitialized = true;
332 }
333 return utcOffset;
334}
335
336/*
337 * Get the DST offset for the time passed in. Takes
338 * seconds (not milliseconds) and cannot handle dates before 1970
339 * on some OS'
340 */
341static double getDSTOffsetSimple(double localTimeSeconds)
342{
343 if(localTimeSeconds > maxUnixTime)
344 localTimeSeconds = maxUnixTime;
345 else if(localTimeSeconds < 0) // Go ahead a day to make localtime work (does not work with 0)
346 localTimeSeconds += secondsPerDay;
347
348 double offsetTime = (localTimeSeconds * msPerSecond) + getUTCOffset() ;
349
350 // Offset from UTC but doesn't include DST obviously
351 int offsetHour = msToHours(offsetTime);
352 int offsetMinute = msToMinutes(offsetTime);
353
354 // FIXME: time_t has a potential problem in 2038
355 time_t localTime = static_cast<time_t>(localTimeSeconds);
356
357 tm localTM;
358 #if PLATFORM(WIN_OS)
359 localtime_s(&localTM, &localTime);
360 #else
361 localtime_r(&localTime, &localTM);
362 #endif
363
364 double diff = ((localTM.tm_hour - offsetHour) * secondsPerHour) + ((localTM.tm_min - offsetMinute) * 60);
365
366 if(diff < 0)
367 diff += secondsPerDay;
368
369 return (diff * msPerSecond);
370}
371
372// Get the DST offset the time passed in
373// ms is in UTC
374static double getDSTOffset(double ms)
375{
376 /*
377 * If earlier than 1970 or after 2038, potentially beyond the ken of
378 * many OSes, map it to an equivalent year before asking.
379 */
380 if (ms < 0.0 || ms > 2145916800000.0) {
381 int year;
382 int day;
383
384 year = equivalentYearForDST(msToYear(ms));
385 day = dateToDayInYear(year, msToMonth(ms), msToDayInMonth(ms));
386 ms = (day * msPerDay) + msToMilliseconds(ms);
387 }
388
389 return getDSTOffsetSimple(ms / msPerSecond);
390}
391
392double gregorianDateTimeToMS(const GregorianDateTime& t, double milliSeconds, bool inputIsUTC)
393{
394
395 int day = dateToDayInYear(t.year + 1900, t.month, t.monthDay);
396 double ms = timeToMS(t.hour, t.minute, t.second, milliSeconds);
397 double result = (day * msPerDay) + ms;
398
399 if(!inputIsUTC) { // convert to UTC
400 result -= getUTCOffset();
401 result -= getDSTOffset(result);
402 }
403
404 return result;
405}
406
407void msToGregorianDateTime(double ms, bool outputIsUTC, struct GregorianDateTime& tm)
408{
409 // input is UTC
410 double dstOff = 0.0;
411
412 if(!outputIsUTC) { // convert to local time
413 dstOff = getDSTOffset(ms);
414 ms += dstOff + getUTCOffset();
415 }
416
417 tm.second = msToSeconds(ms);
418 tm.minute = msToMinutes(ms);
419 tm.hour = msToHours(ms);
420 tm.weekDay = msToWeekDay(ms);
421 tm.monthDay = msToDayInMonth(ms);
422 tm.yearDay = dayInYear(ms, msToYear(ms));
423 tm.month = msToMonth(ms);
424 tm.year = msToYear(ms) - 1900;
425 tm.isDST = dstOff != 0.0;
426
427 tm.utcOffset = static_cast<long>((dstOff + getUTCOffset()) / msPerSecond);
428 tm.timeZone = NULL;
429}
430
431} // namespace KJS
432
Note: See TracBrowser for help on using the repository browser.