blob: a971ebb2eef2e1914aa249cd4116d96097124f89 [file] [log] [blame]
keith_miller@apple.combcc77f22016-07-15 06:03:25 +00001//Date.library.js
2// Copyright 2009 the Sputnik authors. All rights reserved.
3// This code is governed by the BSD license found in the LICENSE file.
4
5//15.9.1.2 Day Number and Time within Day
6function Day(t) {
7 return Math.floor(t/msPerDay);
8}
9
10function TimeWithinDay(t) {
11 return t%msPerDay;
12}
13
14//15.9.1.3 Year Number
15function DaysInYear(y){
16 if(y%4 != 0) return 365;
17 if(y%4 == 0 && y%100 != 0) return 366;
18 if(y%100 == 0 && y%400 != 0) return 365;
19 if(y%400 == 0) return 366;
20}
21
22function DayFromYear(y) {
23 return (365*(y-1970)
24 + Math.floor((y-1969)/4)
25 - Math.floor((y-1901)/100)
26 + Math.floor((y-1601)/400));
27}
28
29function TimeFromYear(y){
30 return msPerDay*DayFromYear(y);
31}
32
33function YearFromTime(t) {
34 t = Number(t);
35 var sign = ( t < 0 ) ? -1 : 1;
36 var year = ( sign < 0 ) ? 1969 : 1970;
37
38 for(var time = 0;;year += sign){
39 time = TimeFromYear(year);
40
41 if(sign > 0 && time > t){
42 year -= sign;
43 break;
44 }
45 else if(sign < 0 && time <= t){
46 break;
47 }
48 };
49 return year;
50}
51
52function InLeapYear(t){
53 if(DaysInYear(YearFromTime(t)) == 365)
54 return 0;
55
56 if(DaysInYear(YearFromTime(t)) == 366)
57 return 1;
58}
59
60function DayWithinYear(t) {
61 return Day(t)-DayFromYear(YearFromTime(t));
62}
63
64//15.9.1.4 Month Number
65function MonthFromTime(t){
66 var day = DayWithinYear(t);
67 var leap = InLeapYear(t);
68
69 if((0 <= day) && (day < 31)) return 0;
70 if((31 <= day) && (day < (59+leap))) return 1;
71 if(((59+leap) <= day) && (day < (90+leap))) return 2;
72 if(((90+leap) <= day) && (day < (120+leap))) return 3;
73 if(((120+leap) <= day) && (day < (151+leap))) return 4;
74 if(((151+leap) <= day) && (day < (181+leap))) return 5;
75 if(((181+leap) <= day) && (day < (212+leap))) return 6;
76 if(((212+leap) <= day) && (day < (243+leap))) return 7;
77 if(((243+leap) <= day) && (day < (273+leap))) return 8;
78 if(((273+leap) <= day) && (day < (304+leap))) return 9;
79 if(((304+leap) <= day) && (day < (334+leap))) return 10;
80 if(((334+leap) <= day) && (day < (365+leap))) return 11;
81}
82
83//15.9.1.5 Date Number
84function DateFromTime(t) {
85 var day = DayWithinYear(t);
86 var month = MonthFromTime(t);
87 var leap = InLeapYear(t);
88
89 if(month == 0) return day+1;
90 if(month == 1) return day-30;
91 if(month == 2) return day-58-leap;
92 if(month == 3) return day-89-leap;
93 if(month == 4) return day-119-leap;
94 if(month == 5) return day-150-leap;
95 if(month == 6) return day-180-leap;
96 if(month == 7) return day-211-leap;
97 if(month == 8) return day-242-leap;
98 if(month == 9) return day-272-leap;
99 if(month == 10) return day-303-leap;
100 if(month == 11) return day-333-leap;
101}
102
103//15.9.1.6 Week Day
104function WeekDay(t) {
105 var weekday = (Day(t)+4)%7;
106 return (weekday < 0 ? 7+weekday : weekday);
107}
108
109//15.9.1.9 Daylight Saving Time Adjustment
110$LocalTZ = (new Date()).getTimezoneOffset() / -60;
111if (DaylightSavingTA((new Date()).valueOf()) !== 0) {
112 $LocalTZ -= 1;
113}
114var LocalTZA = $LocalTZ*msPerHour;
115
116function DaysInMonth(m, leap) {
117 m = m%12;
118
119 //April, June, Sept, Nov
120 if(m == 3 || m == 5 || m == 8 || m == 10 ) {
121 return 30;
122 }
123
124 //Jan, March, May, July, Aug, Oct, Dec
125 if(m == 0 || m == 2 || m == 4 || m == 6 || m == 7 || m == 9 || m == 11){
126 return 31;
127 }
128
129 //Feb
130 return 28+leap;
131}
132
133function GetSundayInMonth(t, m, count){
134 var year = YearFromTime(t);
135 var tempDate;
136
137 if (count==='"first"') {
138 for (var d=1; d <= DaysInMonth(m, InLeapYear(t)); d++) {
139 tempDate = new Date(year, m, d);
140 if (tempDate.getDay()===0) {
141 return tempDate.valueOf();
142 }
143 }
144 } else if(count==='"last"') {
145 for (var d=DaysInMonth(m, InLeapYear(t)); d>0; d--) {
146 tempDate = new Date(year, m, d);
147 if (tempDate.getDay()===0) {
148 return tempDate.valueOf();
149 }
150 }
151 }
152 throw new Error("Unsupported 'count' arg:" + count);
153}
154/*
155function GetSundayInMonth(t, m, count){
156 var year = YearFromTime(t);
157 var leap = InLeapYear(t);
158 var day = 0;
159
160 if(m >= 1) day += DaysInMonth(0, leap);
161 if(m >= 2) day += DaysInMonth(1, leap);
162 if(m >= 3) day += DaysInMonth(2, leap);
163 if(m >= 4) day += DaysInMonth(3, leap);
164 if(m >= 5) day += DaysInMonth(4, leap);
165 if(m >= 6) day += DaysInMonth(5, leap);
166 if(m >= 7) day += DaysInMonth(6, leap);
167 if(m >= 8) day += DaysInMonth(7, leap);
168 if(m >= 9) day += DaysInMonth(8, leap);
169 if(m >= 10) day += DaysInMonth(9, leap);
170 if(m >= 11) day += DaysInMonth(10, leap);
171
172 var month_start = TimeFromYear(year)+day*msPerDay;
173 var sunday = 0;
174
175 if(count === "last"){
176 for(var last_sunday = month_start+DaysInMonth(m, leap)*msPerDay;
177 WeekDay(last_sunday)>0;
178 last_sunday -= msPerDay
179 ){};
180 sunday = last_sunday;
181 }
182 else {
183 for(var first_sunday = month_start;
184 WeekDay(first_sunday)>0;
185 first_sunday += msPerDay
186 ){};
187 sunday = first_sunday+7*msPerDay*(count-1);
188 }
189
190 return sunday;
191}*/
192
193function DaylightSavingTA(t) {
194// t = t-LocalTZA;
195
196 var DST_start = GetSundayInMonth(t, $DST_start_month, $DST_start_sunday) +
197 $DST_start_hour*msPerHour +
198 $DST_start_minutes*msPerMinute;
199
200 var k = new Date(DST_start);
201
202 var DST_end = GetSundayInMonth(t, $DST_end_month, $DST_end_sunday) +
203 $DST_end_hour*msPerHour +
204 $DST_end_minutes*msPerMinute;
205
206 if ( t >= DST_start && t < DST_end ) {
207 return msPerHour;
208 } else {
209 return 0;
210 }
211}
212
213//15.9.1.9 Local Time
214function LocalTime(t){
215 return t+LocalTZA+DaylightSavingTA(t);
216}
217
218function UTC(t) {
219 return t-LocalTZA-DaylightSavingTA(t-LocalTZA);
220}
221
222//15.9.1.10 Hours, Minutes, Second, and Milliseconds
223function HourFromTime(t){
224 return Math.floor(t/msPerHour)%HoursPerDay;
225}
226
227function MinFromTime(t){
228 return Math.floor(t/msPerMinute)%MinutesPerHour;
229}
230
231function SecFromTime(t){
232 return Math.floor(t/msPerSecond)%SecondsPerMinute;
233}
234
235function msFromTime(t){
236 return t%msPerSecond;
237}
238
239//15.9.1.11 MakeTime (hour, min, sec, ms)
240function MakeTime(hour, min, sec, ms){
241 if ( !isFinite(hour) || !isFinite(min) || !isFinite(sec) || !isFinite(ms)) {
242 return Number.NaN;
243 }
244
245 hour = ToInteger(hour);
246 min = ToInteger(min);
247 sec = ToInteger(sec);
248 ms = ToInteger(ms);
249
250 return ((hour*msPerHour) + (min*msPerMinute) + (sec*msPerSecond) + ms);
251}
252
253//15.9.1.12 MakeDay (year, month, date)
254function MakeDay(year, month, date) {
255 if ( !isFinite(year) || !isFinite(month) || !isFinite(date)) {
256 return Number.NaN;
257 }
258
259 year = ToInteger(year);
260 month = ToInteger(month);
261 date = ToInteger(date );
262
263 var result5 = year + Math.floor(month/12);
264 var result6 = month%12;
265
266 var sign = ( year < 1970 ) ? -1 : 1;
267 var t = ( year < 1970 ) ? 1 : 0;
268 var y = ( year < 1970 ) ? 1969 : 1970;
269
270 if( sign == -1 ){
271 for ( y = 1969; y >= year; y += sign ) {
272 t += sign * DaysInYear(y)*msPerDay;
273 }
274 } else {
275 for ( y = 1970 ; y < year; y += sign ) {
276 t += sign * DaysInYear(y)*msPerDay;
277 }
278 }
279
280 var leap = 0;
281 for ( var m = 0; m < month; m++ ) {
282 //if year is changed, than we need to recalculate leep
283 leap = InLeapYear(t);
284 t += DaysInMonth(m, leap)*msPerDay;
285 }
286
287 if ( YearFromTime(t) != result5 ) {
288 return Number.NaN;
289 }
290 if ( MonthFromTime(t) != result6 ) {
291 return Number.NaN;
292 }
293 if ( DateFromTime(t) != 1 ) {
294 return Number.NaN;
295 }
296
297 return Day(t)+date-1;
298}
299
300//15.9.1.13 MakeDate (day, time)
301function MakeDate( day, time ) {
302 if(!isFinite(day) || !isFinite(time)) {
303 return Number.NaN;
304 }
305
306 return day*msPerDay+time;
307}
308
309//15.9.1.14 TimeClip (time)
310function TimeClip(time) {
311 if(!isFinite(time) || Math.abs(time) > 8.64e15){
312 return Number.NaN;
313 }
314
315 return ToInteger(time);
316}
317
318//Test Functions
319//ConstructDate is considered deprecated, and should not be used directly from
320//test262 tests as it's incredibly sensitive to DST start/end dates that
321//vary with geographic location.
322function ConstructDate(year, month, date, hours, minutes, seconds, ms){
323 /*
324 * 1. Call ToNumber(year)
325 * 2. Call ToNumber(month)
326 * 3. If date is supplied use ToNumber(date); else use 1
327 * 4. If hours is supplied use ToNumber(hours); else use 0
328 * 5. If minutes is supplied use ToNumber(minutes); else use 0
329 * 6. If seconds is supplied use ToNumber(seconds); else use 0
330 * 7. If ms is supplied use ToNumber(ms); else use 0
331 * 8. If Result(1) is not NaN and 0 <= ToInteger(Result(1)) <= 99, Result(8) is
332 * 1900+ToInteger(Result(1)); otherwise, Result(8) is Result(1)
333 * 9. Compute MakeDay(Result(8), Result(2), Result(3))
334 * 10. Compute MakeTime(Result(4), Result(5), Result(6), Result(7))
335 * 11. Compute MakeDate(Result(9), Result(10))
336 * 12. Set the [[Value]] property of the newly constructed object to TimeClip(UTC(Result(11)))
337 */
338 var r1 = Number(year);
339 var r2 = Number(month);
340 var r3 = ((date && arguments.length > 2) ? Number(date) : 1);
341 var r4 = ((hours && arguments.length > 3) ? Number(hours) : 0);
342 var r5 = ((minutes && arguments.length > 4) ? Number(minutes) : 0);
343 var r6 = ((seconds && arguments.length > 5) ? Number(seconds) : 0);
344 var r7 = ((ms && arguments.length > 6) ? Number(ms) : 0);
345
346 var r8 = r1;
347
348 if(!isNaN(r1) && (0 <= ToInteger(r1)) && (ToInteger(r1) <= 99))
349 r8 = 1900+r1;
350
351 var r9 = MakeDay(r8, r2, r3);
352 var r10 = MakeTime(r4, r5, r6, r7);
353 var r11 = MakeDate(r9, r10);
354
355 var retVal = TimeClip(UTC(r11));
356 return retVal;
357}
358
359
360
361/**** Python code for initialize the above constants
362// We may want to replicate the following in JavaScript.
363// However, using JS date operations to generate parameters that are then used to
364// test those some date operations seems unsound. However, it isn't clear if there
365//is a good interoperable alternative.
366
367# Copyright 2009 the Sputnik authors. All rights reserved.
368# This code is governed by the BSD license found in the LICENSE file.
369
370def GetDaylightSavingsTimes():
371# Is the given floating-point time in DST?
372def IsDst(t):
373return time.localtime(t)[-1]
374# Binary search to find an interval between the two times no greater than
375# delta where DST switches, returning the midpoint.
376def FindBetween(start, end, delta):
377while end - start > delta:
378middle = (end + start) / 2
379if IsDst(middle) == IsDst(start):
380start = middle
381else:
382end = middle
383return (start + end) / 2
384now = time.time()
385one_month = (30 * 24 * 60 * 60)
386# First find a date with different daylight savings. To avoid corner cases
387# we try four months before and after today.
388after = now + 4 * one_month
389before = now - 4 * one_month
390if IsDst(now) == IsDst(before) and IsDst(now) == IsDst(after):
391logger.warning("Was unable to determine DST info.")
392return None
393# Determine when the change occurs between now and the date we just found
394# in a different DST.
395if IsDst(now) != IsDst(before):
396first = FindBetween(before, now, 1)
397else:
398first = FindBetween(now, after, 1)
399# Determine when the change occurs between three and nine months from the
400# first.
401second = FindBetween(first + 3 * one_month, first + 9 * one_month, 1)
402# Find out which switch is into and which if out of DST
403if IsDst(first - 1) and not IsDst(first + 1):
404start = second
405end = first
406else:
407start = first
408end = second
409return (start, end)
410
411
412def GetDaylightSavingsAttribs():
413times = GetDaylightSavingsTimes()
414if not times:
415return None
416(start, end) = times
417def DstMonth(t):
418return time.localtime(t)[1] - 1
419def DstHour(t):
420return time.localtime(t - 1)[3] + 1
421def DstSunday(t):
422if time.localtime(t)[2] > 15:
423return "'last'"
424else:
425return "'first'"
426def DstMinutes(t):
427return (time.localtime(t - 1)[4] + 1) % 60
428attribs = { }
429attribs['start_month'] = DstMonth(start)
430attribs['end_month'] = DstMonth(end)
431attribs['start_sunday'] = DstSunday(start)
432attribs['end_sunday'] = DstSunday(end)
433attribs['start_hour'] = DstHour(start)
434attribs['end_hour'] = DstHour(end)
435attribs['start_minutes'] = DstMinutes(start)
436attribs['end_minutes'] = DstMinutes(end)
437return attribs
438
439*********/