Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / tests / ecma_3 / Date / shell.js
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
4  *
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/
9  *
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
13  * License.
14  *
15  * The Original Code is Mozilla Communicator client code, released
16  * March 31, 1998.
17  *
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.
22  *
23  * Contributor(s):
24  *
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.
36  *
37  * ***** END LICENSE BLOCK ***** */
38
39
40 /*
41  * Date functions used by tests in Date suite
42  *
43  */
44 var msPerDay =   86400000;
45 var HoursPerDay =  24;
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
55 var TIME_1970  = 0;
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);
61 var now = new Date();
62 var TIME_NOW = now.valueOf();  //valueOf() is to accurate to the millisecond
63                                //Date.parse() is accurate only to the second
64
65 /*
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...
70  */
71 function getTimeZoneDiff()
72 {
73   return -((new Date(2000, 1, 1)).getTimezoneOffset())/60;
74 }
75
76
77 /*
78  * Date test "ResultArrays" are hard-coded for Pacific Standard Time.
79  * We must adjust them for the tester's own timezone -
80  */
81 function adjustResultArray(ResultArray, msMode)
82 {
83   // If the tester's system clock is in PST, no need to continue -
84   if (!PST_DIFF) {return;}
85
86   /* The date testcases instantiate Date objects in two different ways:
87    *
88    *        millisecond mode: e.g.   dt = new Date(10000000);
89    *        year-month-day mode:  dt = new Date(2000, 5, 1, ...);
90    *
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.
93    *
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.
96    *
97    * In the second case, it is exactly the other way around -
98    */
99   if (msMode)
100   {
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;
104
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); 
111   }
112   else
113   {
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;
117
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);
125   }
126 }
127
128
129 function Day( t ) {
130   return ( Math.floor(t/msPerDay ) );
131 }
132 function DaysInYear( y ) {
133   if ( y % 4 != 0 ) {
134     return 365;
135   }
136   if ( (y % 4 == 0) && (y % 100 != 0) ) {
137     return 366;
138   }
139   if ( (y % 100 == 0) && (y % 400 != 0) ) {
140     return 365;
141   }
142   if ( (y % 400 == 0) ){
143     return 366;
144   } else {
145     return "ERROR: DaysInYear(" + y + ") case not covered";
146   }
147 }
148 function TimeInYear( y ) {
149   return ( DaysInYear(y) * msPerDay );
150 }
151 function DayNumber( t ) {
152   return ( Math.floor( t / msPerDay ) );
153 }
154 function TimeWithinDay( t ) {
155
156   var r = t % msPerDay;
157
158   if (r < 0)
159   {
160     r += msPerDay;
161   }
162   return r;
163
164 }
165 function YearNumber( t ) {
166 }
167 function TimeFromYear( y ) {
168   return ( msPerDay * DayFromYear(y) );
169 }
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) );
175 }
176 function InLeapYear( t ) {
177   if ( DaysInYear(YearFromTime(t)) == 365 ) {
178     return 0;
179   }
180   if ( DaysInYear(YearFromTime(t)) == 366 ) {
181     return 1;
182   } else {
183     return "ERROR:  InLeapYear("+ t + ") case not covered";
184   }
185 }
186 function YearFromTime( t ) {
187   t = Number( 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)
193
194       // if there's less than the current year's worth of time left, then break.
195       if ( sign < 0 ) {
196         if ( sign * timeToTimeZero <= 0 ) {
197           break;
198         } else {
199           year += sign;
200         }
201       } else {
202         if ( sign * timeToTimeZero < 0 ) {
203           break;
204         } else {
205           year += sign;
206         }
207       }
208   }
209   return ( year );
210 }
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);
215
216   if ( (0 <= day) && (day < 31) ) {
217     return 0;
218   }
219   if ( (31 <= day) && (day < (59+leap)) ) {
220     return 1;
221   }
222   if ( ((59+leap) <= day) && (day < (90+leap)) ) {
223     return 2;
224   }
225   if ( ((90+leap) <= day) && (day < (120+leap)) ) {
226     return 3;
227   }
228   if ( ((120+leap) <= day) && (day < (151+leap)) ) {
229     return 4;
230   }
231   if ( ((151+leap) <= day) && (day < (181+leap)) ) {
232     return 5;
233   }
234   if ( ((181+leap) <= day) && (day < (212+leap)) ) {
235     return 6;
236   }
237   if ( ((212+leap) <= day) && (day < (243+leap)) ) {
238     return 7;
239   }
240   if ( ((243+leap) <= day) && (day < (273+leap)) ) {
241     return 8;
242   }
243   if ( ((273+leap) <= day) && (day < (304+leap)) ) {
244     return 9;
245   }
246   if ( ((304+leap) <= day) && (day < (334+leap)) ) {
247     return 10;
248   }
249   if ( ((334+leap) <= day) && (day < (365+leap)) ) {
250     return 11;
251   } else {
252     return "ERROR: MonthFromTime("+t+") not known";
253   }
254 }
255 function DayWithinYear( t ) {
256   return( Day(t) - DayFromYear(YearFromTime(t)));
257 }
258 function DateFromTime( t ) {
259   var day = DayWithinYear(t);
260   var month = MonthFromTime(t);
261
262   if ( month == 0 ) {
263     return ( day + 1 );
264   }
265   if ( month == 1 ) {
266     return ( day - 30 );
267   }
268   if ( month == 2 ) {
269     return ( day - 58 - InLeapYear(t) );
270   }
271   if ( month == 3 ) {
272     return ( day - 89 - InLeapYear(t));
273   }
274   if ( month == 4 ) {
275     return ( day - 119 - InLeapYear(t));
276   }
277   if ( month == 5 ) {
278     return ( day - 150- InLeapYear(t));
279   }
280   if ( month == 6 ) {
281     return ( day - 180- InLeapYear(t));
282   }
283   if ( month == 7 ) {
284     return ( day - 211- InLeapYear(t));
285   }
286   if ( month == 8 ) {
287     return ( day - 242- InLeapYear(t));
288   }
289   if ( month == 9 ) {
290     return ( day - 272- InLeapYear(t));
291   }
292   if ( month == 10 ) {
293     return ( day - 303- InLeapYear(t));
294   }
295   if ( month == 11 ) {
296     return ( day - 333- InLeapYear(t));
297   }
298
299   return ("ERROR:  DateFromTime("+t+") not known" );
300 }
301 function WeekDay( t ) {
302   var weekday = (Day(t)+4) % 7;
303   return( weekday < 0 ? 7 + weekday : weekday );
304 }
305
306 // missing daylight savings time adjustment
307
308 function HourFromTime( t ) {
309   var h = Math.floor( t / msPerHour ) % HoursPerDay;
310   return ( (h<0) ? HoursPerDay + h : h  );
311 }
312 function MinFromTime( t ) {
313   var min = Math.floor( t / msPerMinute ) % MinutesPerHour;
314   return( ( min < 0 ) ? MinutesPerHour + min : min  );
315 }
316 function SecFromTime( t ) {
317   var sec = Math.floor( t / msPerSecond ) % SecondsPerMinute;
318   return ( (sec < 0 ) ? SecondsPerMinute + sec : sec );
319 }
320 function msFromTime( t ) {
321   var ms = t % msPerSecond;
322   return ( (ms < 0 ) ? msPerSecond + ms : ms );
323 }
324 function LocalTZA() {
325   return ( TZ_DIFF * msPerHour );
326 }
327 function UTC( t ) {
328   return ( t - LocalTZA() - DaylightSavingTA(t - LocalTZA()) );
329 }
330
331 function DaylightSavingTA( t ) {
332   t = t - LocalTZA();
333
334   var dst_start = GetDSTStart(t);
335   var dst_end   = GetDSTEnd(t);
336
337   if ( t >= dst_start && t < dst_end )
338     return msPerHour;
339
340   return 0;
341 }
342
343 function GetFirstSundayInMonth( t, m ) {
344   var year = YearFromTime(t);
345   var leap = InLeapYear(t);
346
347 // month m 0..11
348 // april == 3
349 // march == 2
350
351   // set time to first day of month m
352   var time = TimeFromYear(year);
353   for (var i = 0; i < m; ++i)
354   {
355     time += TimeInMonth(i, leap);
356   }
357
358   for ( var first_sunday = time; WeekDay(first_sunday) > 0;
359         first_sunday += msPerDay )
360   {
361     ;
362   }
363
364   return first_sunday;
365 }
366
367 function GetLastSundayInMonth( t, m ) {
368   var year = YearFromTime(t);
369   var leap = InLeapYear(t);
370
371 // month m 0..11
372 // april == 3
373 // march == 2
374
375   // first day of following month
376   var time = TimeFromYear(year);
377   for (var i = 0; i <= m; ++i)
378   {
379     time += TimeInMonth(i, leap);
380   }
381   // prev day == last day of month
382   time -= msPerDay;
383
384   for ( var last_sunday = time; WeekDay(last_sunday) > 0;
385         last_sunday -= msPerDay )
386   {
387     ;
388   }
389   return last_sunday;
390 }
391
392 /*
393   15.9.1.9 Daylight Saving Time Adjustment
394
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.
401 */
402
403 /*
404   US DST algorithm
405
406   Before 2007, DST starts first Sunday in April at 2 AM and ends last
407   Sunday in October at 2 AM
408
409   Starting in 2007, DST starts second Sunday in March at 2 AM and ends
410   first Sunday in November at 2 AM
411
412   Note that different operating systems behave differently.
413
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
416   effect at the time.
417
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.
421
422 */
423
424 function GetDSTStart( t )
425 {
426   return (GetFirstSundayInMonth(t, 2) + 7*msPerDay + 2*msPerHour - LocalTZA());
427 }
428
429 function GetDSTEnd( t )
430 {
431   return (GetFirstSundayInMonth(t, 10) + 2*msPerHour - LocalTZA());
432 }
433
434 function GetOldDSTStart( t )
435 {
436   return (GetFirstSundayInMonth(t, 3) + 2*msPerHour - LocalTZA());
437 }
438
439 function GetOldDSTEnd( t )
440 {
441   return (GetLastSundayInMonth(t, 9) + 2*msPerHour - LocalTZA());
442 }
443
444 function LocalTime( t ) {
445   return ( t + LocalTZA() + DaylightSavingTA(t) );
446 }
447 function MakeTime( hour, min, sec, ms ) {
448   if ( isNaN( hour ) || isNaN( min ) || isNaN( sec ) || isNaN( ms ) ) {
449     return Number.NaN;
450   }
451
452   hour = ToInteger(hour);
453   min  = ToInteger( min);
454   sec  = ToInteger( sec);
455   ms  = ToInteger( ms );
456
457   return( (hour*msPerHour) + (min*msPerMinute) +
458           (sec*msPerSecond) + ms );
459 }
460 function MakeDay( year, month, date ) {
461   if ( isNaN(year) || isNaN(month) || isNaN(date) ) {
462     return Number.NaN;
463   }
464   year = ToInteger(year);
465   month = ToInteger(month);
466   date = ToInteger(date );
467
468   var sign = ( year < 1970 ) ? -1 : 1;
469   var t =    ( year < 1970 ) ? 1 :  0;
470   var y =    ( year < 1970 ) ? 1969 : 1970;
471
472   var result5 = year + Math.floor( month/12 );
473   var result6 = month % 12;
474
475   if ( year < 1970 ) {
476     for ( y = 1969; y >= year; y += sign ) {
477       t += sign * TimeInYear(y);
478     }
479   } else {
480     for ( y = 1970 ; y < year; y += sign ) {
481       t += sign * TimeInYear(y);
482     }
483   }
484
485   var leap = InLeapYear( t );
486
487   for ( var m = 0; m < month; m++ ) {
488     t += TimeInMonth( m, leap );
489   }
490
491   if ( YearFromTime(t) != result5 ) {
492     return Number.NaN;
493   }
494   if ( MonthFromTime(t) != result6 ) {
495     return Number.NaN;
496   }
497   if ( DateFromTime(t) != 1 ) {
498     return Number.NaN;
499   }
500
501   return ( (Day(t)) + date - 1 );
502 }
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
507
508   if ( month == 3 || month == 5 || month == 8 || month == 10 ) {
509     return ( 30*msPerDay );
510   }
511
512   // all the rest
513   if ( month == 0 || month == 2 || month == 4 || month == 6 ||
514        month == 7 || month == 9 || month == 11 ) {
515     return ( 31*msPerDay );
516   }
517
518   // save february
519   return ( (leap == 0) ? 28*msPerDay : 29*msPerDay );
520 }
521 function MakeDate( day, time ) {
522   if ( day == Number.POSITIVE_INFINITY ||
523        day == Number.NEGATIVE_INFINITY ) {
524     return Number.NaN;
525   }
526   if ( time == Number.POSITIVE_INFINITY ||
527        time == Number.NEGATIVE_INFINITY ) {
528     return Number.NaN;
529   }
530   return ( day * msPerDay ) + time;
531 }
532 function TimeClip( t ) {
533   if ( isNaN( t ) ) {
534     return ( Number.NaN );
535   }
536   if ( Math.abs( t ) > 8.64e15 ) {
537     return ( Number.NaN );
538   }
539
540   return ( ToInteger( t ) );
541 }
542 function ToInteger( t ) {
543   t = Number( t );
544
545   if ( isNaN( t ) ){
546     return ( Number.NaN );
547   }
548   if ( t == 0 || t == -0 ||
549        t == Number.POSITIVE_INFINITY || t == Number.NEGATIVE_INFINITY ) {
550     return 0;
551   }
552
553   var sign = ( t < 0 ) ? -1 : 1;
554
555   return ( sign * Math.floor( Math.abs( t ) ) );
556 }
557 function Enumerate ( o ) {
558   var p;
559   for ( p in o ) {
560     print( p +": " + o[p] );
561   }
562 }
563