// Copyright 2009 the Sputnik authors. All rights reserved. // This code is governed by the BSD license found in the LICENSE file. //the following values are normally generated by the sputnik.py driver var $LocalTZ, $DST_start_month, $DST_start_sunday, $DST_start_hour, $DST_start_minutes, $DST_end_month, $DST_end_sunday, $DST_end_hour, $DST_end_minutes; (function () { /** * Finds the first date, starting from |start|, where |predicate| * holds. */ var findNearestDateBefore = function(start, predicate) { var current = start; var month = 1000 * 60 * 60 * 24 * 30; for (var step = month; step > 0; step = Math.floor(step / 3)) { if (!predicate(current)) { while (!predicate(current)) current = new Date(current.getTime() + step); current = new Date(current.getTime() - step); } } while (!predicate(current)) { current = new Date(current.getTime() + 1); } return current; } var juneDate = new Date(2000, 5, 20, 0, 0, 0, 0); var decemberDate = new Date(2000, 11, 20, 0, 0, 0, 0); var juneOffset = juneDate.getTimezoneOffset(); var decemberOffset = decemberDate.getTimezoneOffset(); var isSouthernHemisphere = (juneOffset > decemberOffset); var winterTime = isSouthernHemisphere ? juneDate : decemberDate; var summerTime = isSouthernHemisphere ? decemberDate : juneDate; var dstStart = findNearestDateBefore(winterTime, function (date) { return date.getTimezoneOffset() == summerTime.getTimezoneOffset(); }); $DST_start_month = dstStart.getMonth(); $DST_start_sunday = dstStart.getDate() > 15 ? '"last"' : '"first"'; $DST_start_hour = dstStart.getHours(); $DST_start_minutes = dstStart.getMinutes(); var dstEnd = findNearestDateBefore(summerTime, function (date) { return date.getTimezoneOffset() == winterTime.getTimezoneOffset(); }); $DST_end_month = dstEnd.getMonth(); $DST_end_sunday = dstEnd.getDate() > 15 ? '"last"' : '"first"'; $DST_end_hour = dstEnd.getHours(); $DST_end_minutes = dstEnd.getMinutes(); return; })(); //15.9.1.2 Day Number and Time within Day function Day(t) { return Math.floor(t/msPerDay); } function TimeWithinDay(t) { return t%msPerDay; } //15.9.1.3 Year Number function DaysInYear(y){ if(y%4 != 0) return 365; if(y%4 == 0 && y%100 != 0) return 366; if(y%100 == 0 && y%400 != 0) return 365; if(y%400 == 0) return 366; } function DayFromYear(y) { return (365*(y-1970) + Math.floor((y-1969)/4) - Math.floor((y-1901)/100) + Math.floor((y-1601)/400)); } function TimeFromYear(y){ return msPerDay*DayFromYear(y); } function YearFromTime(t) { t = Number(t); var sign = ( t < 0 ) ? -1 : 1; var year = ( sign < 0 ) ? 1969 : 1970; for(var time = 0;;year += sign){ time = TimeFromYear(year); if(sign > 0 && time > t){ year -= sign; break; } else if(sign < 0 && time <= t){ break; } }; return year; } function InLeapYear(t){ if(DaysInYear(YearFromTime(t)) == 365) return 0; if(DaysInYear(YearFromTime(t)) == 366) return 1; } function DayWithinYear(t) { return Day(t)-DayFromYear(YearFromTime(t)); } //15.9.1.4 Month Number function MonthFromTime(t){ var day = DayWithinYear(t); var leap = InLeapYear(t); if((0 <= day) && (day < 31)) return 0; if((31 <= day) && (day < (59+leap))) return 1; if(((59+leap) <= day) && (day < (90+leap))) return 2; if(((90+leap) <= day) && (day < (120+leap))) return 3; if(((120+leap) <= day) && (day < (151+leap))) return 4; if(((151+leap) <= day) && (day < (181+leap))) return 5; if(((181+leap) <= day) && (day < (212+leap))) return 6; if(((212+leap) <= day) && (day < (243+leap))) return 7; if(((243+leap) <= day) && (day < (273+leap))) return 8; if(((273+leap) <= day) && (day < (304+leap))) return 9; if(((304+leap) <= day) && (day < (334+leap))) return 10; if(((334+leap) <= day) && (day < (365+leap))) return 11; } //15.9.1.5 Date Number function DateFromTime(t) { var day = DayWithinYear(t); var month = MonthFromTime(t); var leap = InLeapYear(t); if(month == 0) return day+1; if(month == 1) return day-30; if(month == 2) return day-58-leap; if(month == 3) return day-89-leap; if(month == 4) return day-119-leap; if(month == 5) return day-150-leap; if(month == 6) return day-180-leap; if(month == 7) return day-211-leap; if(month == 8) return day-242-leap; if(month == 9) return day-272-leap; if(month == 10) return day-303-leap; if(month == 11) return day-333-leap; } //15.9.1.6 Week Day function WeekDay(t) { var weekday = (Day(t)+4)%7; return (weekday < 0 ? 7+weekday : weekday); } //15.9.1.9 Daylight Saving Time Adjustment $LocalTZ = (new Date()).getTimezoneOffset() / -60; if (DaylightSavingTA((new Date()).valueOf()) !== 0) { $LocalTZ -= 1; } var LocalTZA = $LocalTZ*msPerHour; function DaysInMonth(m, leap) { m = m%12; //April, June, Sept, Nov if(m == 3 || m == 5 || m == 8 || m == 10 ) { return 30; } //Jan, March, May, July, Aug, Oct, Dec if(m == 0 || m == 2 || m == 4 || m == 6 || m == 7 || m == 9 || m == 11){ return 31; } //Feb return 28+leap; } function GetSundayInMonth(t, m, count){ var year = YearFromTime(t); if (count==='"first"') { for (var d=1; d <= DaysInMonth(m, InLeapYear(t)); d++) { tempDate = new Date(year, m, d); if (tempDate.getDay()===0) { return tempDate.valueOf(); } } } else if(count==='"last"') { for (var d=DaysInMonth(m, InLeapYear(t)); d>0; d--) { tempDate = new Date(year, m, d); if (tempDate.getDay()===0) { return tempDate.valueOf(); } } } throw new Error("Unsupported 'count' arg:" + count); } /* function GetSundayInMonth(t, m, count){ var year = YearFromTime(t); var leap = InLeapYear(t); var day = 0; if(m >= 1) day += DaysInMonth(0, leap); if(m >= 2) day += DaysInMonth(1, leap); if(m >= 3) day += DaysInMonth(2, leap); if(m >= 4) day += DaysInMonth(3, leap); if(m >= 5) day += DaysInMonth(4, leap); if(m >= 6) day += DaysInMonth(5, leap); if(m >= 7) day += DaysInMonth(6, leap); if(m >= 8) day += DaysInMonth(7, leap); if(m >= 9) day += DaysInMonth(8, leap); if(m >= 10) day += DaysInMonth(9, leap); if(m >= 11) day += DaysInMonth(10, leap); var month_start = TimeFromYear(year)+day*msPerDay; var sunday = 0; if(count === "last"){ for(var last_sunday = month_start+DaysInMonth(m, leap)*msPerDay; WeekDay(last_sunday)>0; last_sunday -= msPerDay ){}; sunday = last_sunday; } else { for(var first_sunday = month_start; WeekDay(first_sunday)>0; first_sunday += msPerDay ){}; sunday = first_sunday+7*msPerDay*(count-1); } return sunday; }*/ function DaylightSavingTA(t) { // t = t-LocalTZA; var DST_start = GetSundayInMonth(t, $DST_start_month, $DST_start_sunday) + $DST_start_hour*msPerHour + $DST_start_minutes*msPerMinute; var k = new Date(DST_start); var DST_end = GetSundayInMonth(t, $DST_end_month, $DST_end_sunday) + $DST_end_hour*msPerHour + $DST_end_minutes*msPerMinute; if ( t >= DST_start && t < DST_end ) { return msPerHour; } else { return 0; } } //15.9.1.9 Local Time function LocalTime(t){ return t+LocalTZA+DaylightSavingTA(t); } function UTC(t) { return t-LocalTZA-DaylightSavingTA(t-LocalTZA); } //15.9.1.10 Hours, Minutes, Second, and Milliseconds function HourFromTime(t){ return Math.floor(t/msPerHour)%HoursPerDay; } function MinFromTime(t){ return Math.floor(t/msPerMinute)%MinutesPerHour; } function SecFromTime(t){ return Math.floor(t/msPerSecond)%SecondsPerMinute; } function msFromTime(t){ return t%msPerSecond; } //15.9.1.11 MakeTime (hour, min, sec, ms) function MakeTime(hour, min, sec, ms){ if ( !isFinite(hour) || !isFinite(min) || !isFinite(sec) || !isFinite(ms)) { return Number.NaN; } hour = ToInteger(hour); min = ToInteger(min); sec = ToInteger(sec); ms = ToInteger(ms); return ((hour*msPerHour) + (min*msPerMinute) + (sec*msPerSecond) + ms); } //15.9.1.12 MakeDay (year, month, date) function MakeDay(year, month, date) { if ( !isFinite(year) || !isFinite(month) || !isFinite(date)) { return Number.NaN; } year = ToInteger(year); month = ToInteger(month); date = ToInteger(date ); var result5 = year + Math.floor(month/12); var result6 = month%12; var sign = ( year < 1970 ) ? -1 : 1; var t = ( year < 1970 ) ? 1 : 0; var y = ( year < 1970 ) ? 1969 : 1970; if( sign == -1 ){ for ( y = 1969; y >= year; y += sign ) { t += sign * DaysInYear(y)*msPerDay; } } else { for ( y = 1970 ; y < year; y += sign ) { t += sign * DaysInYear(y)*msPerDay; } } var leap = 0; for ( var m = 0; m < month; m++ ) { //if year is changed, than we need to recalculate leep leap = InLeapYear(t); t += DaysInMonth(m, leap)*msPerDay; } if ( YearFromTime(t) != result5 ) { return Number.NaN; } if ( MonthFromTime(t) != result6 ) { return Number.NaN; } if ( DateFromTime(t) != 1 ) { return Number.NaN; } return Day(t)+date-1; } //15.9.1.13 MakeDate (day, time) function MakeDate( day, time ) { if(!isFinite(day) || !isFinite(time)) { return Number.NaN; } return day*msPerDay+time; } //15.9.1.14 TimeClip (time) function TimeClip(time) { if(!isFinite(time) || Math.abs(time) > 8.64e15){ return Number.NaN; } return ToInteger(time); } //Test Functions function ConstructDate(year, month, date, hours, minutes, seconds, ms){ /* * 1. Call ToNumber(year) * 2. Call ToNumber(month) * 3. If date is supplied use ToNumber(date); else use 1 * 4. If hours is supplied use ToNumber(hours); else use 0 * 5. If minutes is supplied use ToNumber(minutes); else use 0 * 6. If seconds is supplied use ToNumber(seconds); else use 0 * 7. If ms is supplied use ToNumber(ms); else use 0 * 8. If Result(1) is not NaN and 0 <= ToInteger(Result(1)) <= 99, Result(8) is * 1900+ToInteger(Result(1)); otherwise, Result(8) is Result(1) * 9. Compute MakeDay(Result(8), Result(2), Result(3)) * 10. Compute MakeTime(Result(4), Result(5), Result(6), Result(7)) * 11. Compute MakeDate(Result(9), Result(10)) * 12. Set the [[Value]] property of the newly constructed object to TimeClip(UTC(Result(11))) */ var r1 = Number(year); var r2 = Number(month); var r3 = ((date && arguments.length > 2) ? Number(date) : 1); var r4 = ((hours && arguments.length > 3) ? Number(hours) : 0); var r5 = ((minutes && arguments.length > 4) ? Number(minutes) : 0); var r6 = ((seconds && arguments.length > 5) ? Number(seconds) : 0); var r7 = ((ms && arguments.length > 6) ? Number(ms) : 0); var r8 = r1; if(!isNaN(r1) && (0 <= ToInteger(r1)) && (ToInteger(r1) <= 99)) r8 = 1900+r1; var r9 = MakeDay(r8, r2, r3); var r10 = MakeTime(r4, r5, r6, r7); var r11 = MakeDate(r9, r10); return TimeClip(UTC(r11)); }