1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is Mozilla Communicator client code, released
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
41 * Date functions used by tests in Date suite
44 var msPerDay = 86400000;
46 var MinutesPerHour = 60;
47 var SecondsPerMinute = 60;
48 var msPerSecond = 1000;
49 var msPerMinute = 60000; // msPerSecond * SecondsPerMinute
50 var msPerHour = 3600000; // msPerMinute * MinutesPerHour
51 var TZ_DIFF = getTimeZoneDiff(); // offset of tester's timezone from UTC
52 var TZ_ADJUST = TZ_DIFF * msPerHour;
53 var TZ_PST = -8; // offset of Pacific Standard Time from UTC
54 var PST_DIFF = TZ_DIFF - TZ_PST; // offset of tester's timezone from PST
56 var TIME_2000 = 946684800000;
57 var TIME_1900 = -2208988800000;
58 var UTC_29_FEB_2000 = TIME_2000 + 31*msPerDay + 28*msPerDay;
59 var UTC_1_JAN_2005 = TIME_2000 + TimeInYear(2000) + TimeInYear(2001) +
60 TimeInYear(2002) + TimeInYear(2003) + TimeInYear(2004);
62 var TIME_NOW = now.valueOf(); //valueOf() is to accurate to the millisecond
63 //Date.parse() is accurate only to the second
66 * Originally, the test suite used a hard-coded value TZ_DIFF = -8.
67 * But that was only valid for testers in the Pacific Standard Time Zone!
68 * We calculate the proper number dynamically for any tester. We just
69 * have to be careful not to use a date subject to Daylight Savings Time...
71 function getTimeZoneDiff()
73 return -((new Date(2000, 1, 1)).getTimezoneOffset())/60;
78 * Date test "ResultArrays" are hard-coded for Pacific Standard Time.
79 * We must adjust them for the tester's own timezone -
81 function adjustResultArray(ResultArray, msMode)
83 // If the tester's system clock is in PST, no need to continue -
84 if (!PST_DIFF) {return;}
86 /* The date testcases instantiate Date objects in two different ways:
88 * millisecond mode: e.g. dt = new Date(10000000);
89 * year-month-day mode: dt = new Date(2000, 5, 1, ...);
91 * In the first case, the date is measured from Time 0 in Greenwich (i.e. UTC).
92 * In the second case, it is measured with reference to the tester's local timezone.
94 * In the first case we must correct those values expected for local measurements,
95 * like dt.getHours() etc. No correction is necessary for dt.getUTCHours() etc.
97 * In the second case, it is exactly the other way around -
101 // The hard-coded UTC milliseconds from Time 0 derives from a UTC date.
102 // Shift to the right by the offset between UTC and the tester.
103 var t = ResultArray[TIME] + TZ_DIFF*msPerHour;
105 // Use our date arithmetic functions to determine the local hour, day, etc.
106 ResultArray[HOURS] = HourFromTime(t);
107 ResultArray[DAY] = WeekDay(t);
108 ResultArray[DATE] = DateFromTime(t);
109 ResultArray[MONTH] = MonthFromTime(t);
110 ResultArray[YEAR] = YearFromTime(t);
114 // The hard-coded UTC milliseconds from Time 0 derives from a PST date.
115 // Shift to the left by the offset between PST and the tester.
116 var t = ResultArray[TIME] - PST_DIFF*msPerHour;
118 // Use our date arithmetic functions to determine the UTC hour, day, etc.
119 ResultArray[TIME] = t;
120 ResultArray[UTC_HOURS] = HourFromTime(t);
121 ResultArray[UTC_DAY] = WeekDay(t);
122 ResultArray[UTC_DATE] = DateFromTime(t);
123 ResultArray[UTC_MONTH] = MonthFromTime(t);
124 ResultArray[UTC_YEAR] = YearFromTime(t);
130 return ( Math.floor(t/msPerDay ) );
132 function DaysInYear( y ) {
136 if ( (y % 4 == 0) && (y % 100 != 0) ) {
139 if ( (y % 100 == 0) && (y % 400 != 0) ) {
142 if ( (y % 400 == 0) ){
145 return "ERROR: DaysInYear(" + y + ") case not covered";
148 function TimeInYear( y ) {
149 return ( DaysInYear(y) * msPerDay );
151 function DayNumber( t ) {
152 return ( Math.floor( t / msPerDay ) );
154 function TimeWithinDay( t ) {
156 var r = t % msPerDay;
165 function YearNumber( t ) {
167 function TimeFromYear( y ) {
168 return ( msPerDay * DayFromYear(y) );
170 function DayFromYear( y ) {
171 return ( 365*(y-1970) +
172 Math.floor((y-1969)/4) -
173 Math.floor((y-1901)/100) +
174 Math.floor((y-1601)/400) );
176 function InLeapYear( t ) {
177 if ( DaysInYear(YearFromTime(t)) == 365 ) {
180 if ( DaysInYear(YearFromTime(t)) == 366 ) {
183 return "ERROR: InLeapYear("+ t + ") case not covered";
186 function YearFromTime( t ) {
188 var sign = ( t < 0 ) ? -1 : 1;
189 var year = ( sign < 0 ) ? 1969 : 1970;
190 for ( var timeToTimeZero = t; ; ) {
191 // subtract the current year's time from the time that's left.
192 timeToTimeZero -= sign * TimeInYear(year)
194 // if there's less than the current year's worth of time left, then break.
196 if ( sign * timeToTimeZero <= 0 ) {
202 if ( sign * timeToTimeZero < 0 ) {
211 function MonthFromTime( t ) {
212 // i know i could use switch but i'd rather not until it's part of ECMA
213 var day = DayWithinYear( t );
214 var leap = InLeapYear(t);
216 if ( (0 <= day) && (day < 31) ) {
219 if ( (31 <= day) && (day < (59+leap)) ) {
222 if ( ((59+leap) <= day) && (day < (90+leap)) ) {
225 if ( ((90+leap) <= day) && (day < (120+leap)) ) {
228 if ( ((120+leap) <= day) && (day < (151+leap)) ) {
231 if ( ((151+leap) <= day) && (day < (181+leap)) ) {
234 if ( ((181+leap) <= day) && (day < (212+leap)) ) {
237 if ( ((212+leap) <= day) && (day < (243+leap)) ) {
240 if ( ((243+leap) <= day) && (day < (273+leap)) ) {
243 if ( ((273+leap) <= day) && (day < (304+leap)) ) {
246 if ( ((304+leap) <= day) && (day < (334+leap)) ) {
249 if ( ((334+leap) <= day) && (day < (365+leap)) ) {
252 return "ERROR: MonthFromTime("+t+") not known";
255 function DayWithinYear( t ) {
256 return( Day(t) - DayFromYear(YearFromTime(t)));
258 function DateFromTime( t ) {
259 var day = DayWithinYear(t);
260 var month = MonthFromTime(t);
269 return ( day - 58 - InLeapYear(t) );
272 return ( day - 89 - InLeapYear(t));
275 return ( day - 119 - InLeapYear(t));
278 return ( day - 150- InLeapYear(t));
281 return ( day - 180- InLeapYear(t));
284 return ( day - 211- InLeapYear(t));
287 return ( day - 242- InLeapYear(t));
290 return ( day - 272- InLeapYear(t));
293 return ( day - 303- InLeapYear(t));
296 return ( day - 333- InLeapYear(t));
299 return ("ERROR: DateFromTime("+t+") not known" );
301 function WeekDay( t ) {
302 var weekday = (Day(t)+4) % 7;
303 return( weekday < 0 ? 7 + weekday : weekday );
306 // missing daylight savings time adjustment
308 function HourFromTime( t ) {
309 var h = Math.floor( t / msPerHour ) % HoursPerDay;
310 return ( (h<0) ? HoursPerDay + h : h );
312 function MinFromTime( t ) {
313 var min = Math.floor( t / msPerMinute ) % MinutesPerHour;
314 return( ( min < 0 ) ? MinutesPerHour + min : min );
316 function SecFromTime( t ) {
317 var sec = Math.floor( t / msPerSecond ) % SecondsPerMinute;
318 return ( (sec < 0 ) ? SecondsPerMinute + sec : sec );
320 function msFromTime( t ) {
321 var ms = t % msPerSecond;
322 return ( (ms < 0 ) ? msPerSecond + ms : ms );
324 function LocalTZA() {
325 return ( TZ_DIFF * msPerHour );
328 return ( t - LocalTZA() - DaylightSavingTA(t - LocalTZA()) );
331 function DaylightSavingTA( t ) {
334 var dst_start = GetDSTStart(t);
335 var dst_end = GetDSTEnd(t);
337 if ( t >= dst_start && t < dst_end )
343 function GetFirstSundayInMonth( t, m ) {
344 var year = YearFromTime(t);
345 var leap = InLeapYear(t);
351 // set time to first day of month m
352 var time = TimeFromYear(year);
353 for (var i = 0; i < m; ++i)
355 time += TimeInMonth(i, leap);
358 for ( var first_sunday = time; WeekDay(first_sunday) > 0;
359 first_sunday += msPerDay )
367 function GetLastSundayInMonth( t, m ) {
368 var year = YearFromTime(t);
369 var leap = InLeapYear(t);
375 // first day of following month
376 var time = TimeFromYear(year);
377 for (var i = 0; i <= m; ++i)
379 time += TimeInMonth(i, leap);
381 // prev day == last day of month
384 for ( var last_sunday = time; WeekDay(last_sunday) > 0;
385 last_sunday -= msPerDay )
393 15.9.1.9 Daylight Saving Time Adjustment
395 The implementation of ECMAScript should not try to determine whether
396 the exact time was subject to daylight saving time, but just whether
397 daylight saving time would have been in effect if the current
398 daylight saving time algorithm had been used at the time. This avoids
399 complications such as taking into account the years that the locale
400 observed daylight saving time year round.
406 Before 2007, DST starts first Sunday in April at 2 AM and ends last
407 Sunday in October at 2 AM
409 Starting in 2007, DST starts second Sunday in March at 2 AM and ends
410 first Sunday in November at 2 AM
412 Note that different operating systems behave differently.
414 Fully patched Windows XP uses the 2007 algorithm for all dates while
415 fully patched Fedora Core 6 and RHEL 4 Linux use the algorithm in
418 Since pre-2007 DST is a subset of 2007 DST rules, this only affects
419 tests that occur in the period Mar-Apr and Oct-Nov where the two
420 algorithms do not agree.
424 function GetDSTStart( t )
426 return (GetFirstSundayInMonth(t, 2) + 7*msPerDay + 2*msPerHour - LocalTZA());
429 function GetDSTEnd( t )
431 return (GetFirstSundayInMonth(t, 10) + 2*msPerHour - LocalTZA());
434 function GetOldDSTStart( t )
436 return (GetFirstSundayInMonth(t, 3) + 2*msPerHour - LocalTZA());
439 function GetOldDSTEnd( t )
441 return (GetLastSundayInMonth(t, 9) + 2*msPerHour - LocalTZA());
444 function LocalTime( t ) {
445 return ( t + LocalTZA() + DaylightSavingTA(t) );
447 function MakeTime( hour, min, sec, ms ) {
448 if ( isNaN( hour ) || isNaN( min ) || isNaN( sec ) || isNaN( ms ) ) {
452 hour = ToInteger(hour);
453 min = ToInteger( min);
454 sec = ToInteger( sec);
455 ms = ToInteger( ms );
457 return( (hour*msPerHour) + (min*msPerMinute) +
458 (sec*msPerSecond) + ms );
460 function MakeDay( year, month, date ) {
461 if ( isNaN(year) || isNaN(month) || isNaN(date) ) {
464 year = ToInteger(year);
465 month = ToInteger(month);
466 date = ToInteger(date );
468 var sign = ( year < 1970 ) ? -1 : 1;
469 var t = ( year < 1970 ) ? 1 : 0;
470 var y = ( year < 1970 ) ? 1969 : 1970;
472 var result5 = year + Math.floor( month/12 );
473 var result6 = month % 12;
476 for ( y = 1969; y >= year; y += sign ) {
477 t += sign * TimeInYear(y);
480 for ( y = 1970 ; y < year; y += sign ) {
481 t += sign * TimeInYear(y);
485 var leap = InLeapYear( t );
487 for ( var m = 0; m < month; m++ ) {
488 t += TimeInMonth( m, leap );
491 if ( YearFromTime(t) != result5 ) {
494 if ( MonthFromTime(t) != result6 ) {
497 if ( DateFromTime(t) != 1 ) {
501 return ( (Day(t)) + date - 1 );
503 function TimeInMonth( month, leap ) {
504 // september april june november
505 // jan 0 feb 1 mar 2 apr 3 may 4 june 5 jul 6
506 // aug 7 sep 8 oct 9 nov 10 dec 11
508 if ( month == 3 || month == 5 || month == 8 || month == 10 ) {
509 return ( 30*msPerDay );
513 if ( month == 0 || month == 2 || month == 4 || month == 6 ||
514 month == 7 || month == 9 || month == 11 ) {
515 return ( 31*msPerDay );
519 return ( (leap == 0) ? 28*msPerDay : 29*msPerDay );
521 function MakeDate( day, time ) {
522 if ( day == Number.POSITIVE_INFINITY ||
523 day == Number.NEGATIVE_INFINITY ) {
526 if ( time == Number.POSITIVE_INFINITY ||
527 time == Number.NEGATIVE_INFINITY ) {
530 return ( day * msPerDay ) + time;
532 function TimeClip( t ) {
534 return ( Number.NaN );
536 if ( Math.abs( t ) > 8.64e15 ) {
537 return ( Number.NaN );
540 return ( ToInteger( t ) );
542 function ToInteger( t ) {
546 return ( Number.NaN );
548 if ( t == 0 || t == -0 ||
549 t == Number.POSITIVE_INFINITY || t == Number.NEGATIVE_INFINITY ) {
553 var sign = ( t < 0 ) ? -1 : 1;
555 return ( sign * Math.floor( Math.abs( t ) ) );
557 function Enumerate ( o ) {
560 print( p +": " + o[p] );