See "About This JavaScript Site" in JavaScript Index and Introduction.
See "General Date/Time Introduction" in JavaScript Date and Time Introduction.
See [MS-ES3]: Internet Explorer ECMA-262 ECMAScript Language Specification Standards Support Document for JScript and ECMA 3
The bugs below have, I hope, been avoided in these pages (except where noted); and the deviations accommodated.
From Summer 1998 to 2006-10-14, I used MS IE 4, on a desktop P2/300 PC with Win98 1st Edn.
I currently have a desktop P4/3G PC with Windows XP pro sp3 and a laptop PC with Windows 7 pro, and mainly use the desktop machine.
I got MS IE 6 with the desktop PC on 2006-10-19, replacing it with IE 7 on 2008-03-18 and IE 8 on 2009-07-21. The laptop has IE 9.
I got Firefox 2.0.0.3 on 2007-03-31 (updated in steps to 18.0.1).
I got Opera 9.20 on 2007-04-25 (updated in steps to 12.12).
I got Safari 3.0.4 on 2008-01-04 (updated in steps to 5.1.7).
I got Chrome 0.2 on 2008-09-10 (updated in steps to 24.0).
Non-date tests (lines A to H) are now in
Some Bugs in JavaScript Implementations.
Each of these tests has in the past either shown a problem in at least one of the browsers or shown a difference between browsers. Entries in the "Yours" column are computed by your browser using function X35. Other columns do not necessarily refer to the latest Windows browser release. Some of the more important results are colour-coded. Opera 10.61 was much better than Opera 10.10.
# | Test (details in code) | IE 6/7/8 (9) | Firefox 12.0 | Opera 11.61 | Safari 5.1.4 | Chrome 13.0 | Your Browser | ECMA 5 Standard |
---|---|---|---|---|---|---|---|---|
01 | Date.UTC(Y,M,0) OK | true | true ‡ | true | true | true | true | |
02 | new Date("Y/M/D") range | true | true | true | true | true | - | |
03 | getYear() for 2008 | 2008 | 108 | 108 ‡ | 108 | 108 | 108 | |
04 | new Date(2e99).toString() | NaN | Invalid Date | Invalid Date | Invalid Date | Invalid Date | NaN ?? | |
05 | new Date("2222/11/11 +03:00") OK | false | true | true | true | false + | - | |
06 | new Date("2222/11/11 +0300") OK | true | true | true | false | false + | - | |
07 | lastModified OK | true | true | true | true ‡ | true ‡ | N/A | |
08 | new Date("1969 Dec 29") | true | true | true | false | true | N/A | |
09 | Not Exceed Date Range | true | true | true | false | true | true | |
10 | new Date("1970/01/01 EST") OK | true | true | true | true | true | N/A | |
11 | new Date("2009/01/123") OK | true | true | true | true | false | N/A | |
12a | new Date("2009-05-07") OK | false | false | false | false | true | N/A | |
12b | new Date("2009-07-17").getHours() (UK summer) | NaN | 1 | 1 | NaN | 1 | N/A | |
12c | new Date("2009-01-02").getHours() (UK winter) | NaN | 0 | 0 | NaN | 0 | N/A | |
12d | new Date("2009/07/17").getHours() (UK summer) | 0 | 0 | 0 | 0 | 0 | N/A | |
12e | new Date("2009/01/02").getHours() (UK winter) | 0 | 0 | 0 | 0 | 0 | N/A | |
13 | new Date("0077/05/03").ISOlocaldateStr() | 1977-05-03 | 1977-05-03 | 1977-05-03 | 1977-05-03 | 1977-05-03 | N/A | |
14 | new Date("3/6/9").getFullYear() | 1909 | 1909 | 1909 ‡ | 2009 | 2009 | N/A | |
15 | new Date("2 Bananas 2004").getMonth() | NaN | NaN | NaN | NaN | NaN | N/A | |
16 | new Date("1 Octopus 2004").getMonth() | NaN | NaN | NaN | 9 | 9 | N/A | |
17 | new Date("25 2009")>0 | false | false | false | false | false | N/A | |
18 | !!new Date(0).toISOString | false ‡ | true | true | true | true | New | |
19 | toISOString() (see source) | false ‡ | 12345-06-07 T11:22:33.000Z | 12345-06-07 T11:22:33Z | 12345-06-07 T11:22:33Z | 12345-06-07 T11:22:33Z | +12345-06-07 T11:22:33.000Z | |
20 | no offset (see source) | false | false | false | false | false | N/A | |
21 | Military time offset (see source) | 17 | NaN | 17 | NaN | NaN | N/A (17) | |
22 | Local time offset (see source) | 21 | 21 | 21 | 21 | 21 | N/A (21) | |
23 | new Date("2099/12/28 GMT").getUTCDate() | 28 | 28 | 28 | 27 | 28 | 28 | |
24 | toJSON() (see source) | 2009-02-13 T23:31:30Z | 2009-02-13 T23:31:30.123Z | 2009-02-13 T23:31:30Z | 2009-02-13 T23:31:30.123Z | 2009-02-13 T23:31:30.123Z | ||
25 | new Date("01/359/2011").ISOlocaldateStr() | 2011-12-25 | 2011-12-25 | 2011-12-25 | 0NaN-NaN-NaN | 0NaN-NaN-NaN | N/A | |
26 | D=new Date(0), D.setDate(14609700), D.ISOlocaldateStr() | 41969-12-31 | 41969-12-31 | 41969-12-31 | 41969-12-31 | 41969-12-31 | 41969-12-31 | |
27 | new Date("2034/3/22 GMT")/864e5 | 23456 | 23456 | 23456 | 23455 | 23456 | 23456 | |
Z | VBScript DatePart WeekNo | 53 | . | . | . | . | MS IE only | 1 |
‡ : see corresponding Note below. |
See also Resolutions of new Date().
Date formats may be influenced by OS settings (Opera?).
ECMA and ISO/IEC standards (ES3) require (Annex B.2.4, non-normative) getYear() to return Year-1900. MS IE & Opera 9.5+ differ.
1897 1898 1899 2000 2001 2002 2097 2098 2099 2000 2001 2002 : Full Year 1897 1898 1899 0 1 2 97 98 99 2000 2001 2002 : IE 6/7/8 -3 -2 -1 0 1 2 97 98 99 100 101 102 : Firefox 2/3 -3 -2 -1 0 1 2 97 98 99 100 101 102 : Safari 3 -3 -2 -1 0 1 2 97 98 99 100 101 102 : Chrome 0.2 -3 -2 -1 0 1 2 97 98 99 100 101 102 : Opera 9.2 1897 1898 1899 0 1 2 97 98 99 2000 2001 2002 : " 9.6, 10.00 -3 -2 -1 0 1 2 97 98 99 100 101 102 : " 10.52, 11.51 -3 -2 -1 0 1 2 97 98 99 100 101 102 : STANDARD
In each case, it seems likely that the specific bug observed can be seen more generally. I have not necessarily seen all of these bugs myself.
Following results in green boxes quoted for Opera 10.51 to 11.01 were obtained with UK settings. I have been assured that only 10.50 and 10.51 have the offset bug.
In locations without seasonal clock changes, this section should be uninteresting.
I see, in Opera 9.21 .. 10.00, but not 10.52, with an XP system set for UK time, an error for one day near most EU Summer Time transitions before 1970 and from 2038. Note: that's the outside of the positive signed 32-bit integer of seconds-from-1970.0 range.
This checks whether new Date(Y,M,D) for all days in two ranges of years, around 1970 and around 2038, always gives an Object showing zero hours local time :-
Typical error line from Opera 9.27 in UK (I see 6 + 7) : 2038-03-31 -> Tue, 30 Mar 2038 23:00:00 GMT+0000
Apparently, this test showed errors in XP with the London setting, but not with New York, Azores, Paris, or Moscow 1981-2011 settings.
Within 1901-2099, Gregorian years differing by a multiple of 28 have matching calendars (apart from Easter-related dates). That includes the usual seasonal clock changes by current rules in almost all locations (JavaScript standards require current rules for all dates).
The tests use the day of the EU calendar change, but before the change time. In the EU, all should show Winter offset and 00:00:00. With UK settings and Opera 9.27 to 10.00, I have seen Winter offset and 00:00:00 for 1982 and 2010 but Summer offset and 01:00:00 for 2038 and 2066. Similar can also be seen elsewhere in the EU, evidently caused by miscalculation of the Offset. Correct from 10.52.
Non-Europeans can test their own dates.
My results - Local date and time, and offset to GMT: Opera 9.xx, 10.00, 10.10 Other browsers (good) Sun 1982-03-28 00:00:00 0 Sun 1982-03-28 00:00:00 0 Sun 2010-03-28 00:00:00 0 Sun 2010-03-28 00:00:00 0 Sun 2038-03-28 01:00:00 -60 Sun 2038-03-28 00:00:00 0 Sun 2066-03-28 01:00:00 -60 Sun 2066-03-28 00:00:00 0 Opera 10.51 Sun 1982-03-28 00:59:59 -59.99998333333333 Sun 2010-03-28 00:59:59 -59.99998333333333 Sun 2038-03-28 00:59:59 -59.99998333333333 Sun 2066-03-28 00:59:59 -59.99998333333333 Opera 10.52 and later Sun 1982-03-28 00:00:00 0 Sun 2010-03-28 00:00:00 0 Sun 2038-03-28 00:00:00 0 Sun 2066-03-28 00:00:00 0
There should be one change in each Spring and each Autumn, and in most places it should be early on a Sunday. This checks Offset at intervals of 86400 seconds.
I have seen, for the UK and other EU locations, outside 1968-2037, generally six changes per year in Opera 9.27 to 10.00; USA, AU & NZ locations are similar; but I have only ever seen the expected two changes per year in IE, Firefox, Opera 10.52, Safari & Chrome.
I mostly test these with a machine set for UK time.
These also occur when set to central US time in winter.
First test new Date("07/07/2044 12:00"), a local date, and
then test new Date("07/07/2044 12:00 GMT"), a UTC date :-
Safari 5.1.7 wrongly gives in each case '2044-07-06 12:00:00' (UK, summer time).
All sections should be year 0;.
In my Safari 5.1.7, the first three are year 0;,
but the second three are year 86400000;.
This tests D = new Date("yyyy/07/22 12:00 GMT") for each year in 100 to 3000, reporting changes in D.getDate().
All years in the range are tested with a string representing noon GMT on July 22nd, and only changes in the getDate() column are shown. Above this sentence, there should be a thin empty yellow box. My MS IE 8, Firefox 3.6.13, Opera 10.63, and Chrome 8.0 give that. My Safari 5.0.3 to 5.1.7 do not, reporting 30 changes. The pattern of changes repeats every 400 years. The problem seems not to depend on the day-of year tested (in particular, not on the state of Summer Time).
This tests all valid dates within a chosen range, using D = new Date("yyyy/mm/dd GMT") (or UTC), reporting changes in the error in the number of GMT days that D represents.
As before, only Safari shows errors, in a quarter of all dates. Maybe a Safari Leap Year calculation includes a 3 which should be a 4?
Sample from Safari 5.1.7 : Date String Errors: New Old "1800/03/01 GMT" 0 1 "2034/03/01 GMT" 1 0 "2100/03/01 GMT" 0 1 "2167/03/01 GMT" 1 0 "2200/03/01 GMT" 0 1 "2434/03/01 GMT" 1 0
Test +new Date("YYYY/MM/DD 12:00") for consecutive local dates :-
Safari 5.1.7 fails. Firefox gave :-
Test +new Date("YYYY/MM/DD 12:00") for consecutive local dates :- 23433.5 23434.5 23435.5 23436.5 47539.5 47540.5 47541.5 47542.5 Differences in each row should be 1.0 days.
It is well-known that the Gregorian Calendar, disregarding Easter, repeats exactly every 28 years (interval = 28×365.25 = 10227 days), except when there is a "missing century Leap Day".
Other browsers correctly show only 10227 true and Monday 14th, but Safari 5.1.7 shows a single 10226 false for 2042, at which there is a change to Sunday 13th.
Safari 5.0.3, 5.0.5, 5.1.1, 5.1.7 fail test X01b; MSIE8, Firefox, Opera, and Chrome pass it.
The ECMA spec says that the date range is 108 days each way from 1970-01-01 00:00:00 GMT, which means (Proleptic Astronomical Gregorian) -271821-04-20 to +275760-09-13 GMT.
The following detects the date range of your system, using new Date(Number). The approximate Numbers found are adjusted inwards by 99 ms to ensure safe conversion to a date string.
IE 7, FF 3, Op 9, Sf 3, Cr 1 were all OK for test X01a.
The ECMA spec appears to say that X=Date() should be equivalent to X=(new Date()).toString() ; in MSIE4, they gave me the forms Fri Sep 13 13:07:20 2002 and Fri Sep 13 13:07:31 UTC+0100 2002 respectively. They still differ in IE 6 to 8; they agree in FF 3, Op 9, Sf 3, Cr 8.
In Mac Netscape 4, setDate() with an argument below 1 does not go into the previous month (I think; and how about above 28..31?).
In some Netscape (e.g. 4.72, 4.78), Date functions with parameters Y M' D do not give the last day of the previous month for D=0.
Firefox 2.0.0.3-13 give me (UK) "Mon Dec 31 2001 ..." and "Tue Jan 01 2002 ..." respectively; Date.UTC(Y,M',D) takes D≤0 as D=1 - known at Bugzilla. My function YMD2YWD did use D=0 but has been changed.
In NS 4.08, some AM/PM time strings may be misunderstood; perhaps just from 12 up to 1.
Functions X05A and X05B should be equivalent for the original purpose; X05B may show better what happens in other systems.
There seems to be a possibility that YYYY/MM/DD may not always be recognised correctly.
However, I know of no actual cases of error, except as above for Opera not accepting YYY or YYYYY; RSVP with full details of code and system, if found.
If GMT or UTC were not recognised, there would be an alert when local time is not GMT/UTC.
In MSIE 4, Date.parse('... +0100') // no GMT did not (tested in UK Summer) give me a reasonable result; but Date.parse('... GMT') and Date.parse('... GMT+0100') was OK. Do I mean this?
I have read at IRT that JS 1.0, in MSIE 3 only, gave the wrong sign for getTimezoneOffset (which may well affect my OS Time Offset Settings Summer Time code). Also that NN2 & NN4 can give wrong offsets.
The correct results for that depend on your location; for the UK, it should give 0 -60 respectively. The Summer value should be less positive or more negative than the Winter one.
ECMA-262, 5th Edition, page 166, Section 15.9.1.8 "Daylight Saving Time Adjustment" says clearly enough that the current Summer Time rules for the location must be applied for all years. The 3rd Edition said the same.
ECMA-262, 5th Edition, page 164, Section 15.9.1.1 "Time Values and Time Range" indicates that Leap Seconds should have no effect detectable in JavaScript.
It appears that at least some Linux browsers, instead of obtaining the current rules and applying them to all dates, get the OS to do the conversion; and that the OS, having access to a TZ database, does the conversion according to the rules in force at the date in question.
Those in locations where the Summer Time Rules have changed should do appropriate tests.
Assuming that January 1st is always firmly in either Winter Time or Summer Time at a given location, each Minutes column below should show equal values for each year. The Minutes columns should differ, modulo 1440, by 0 or 60 (LHI:30).
Apparently it is different in Mozilla and Konqueror under Linux set for Brisbane, Australia, where things changed in 1992.
In North America, DST rules changed on 2007-03-01.
It seems also that, in some systems, Leap Seconds may have an unapproved effect
It is likely that a number of routines on these pages will FAIL on browsers that show Leap Seconds.
There were Leap Seconds in the middle of UTC 1997 and at the end of UTC 1998.
Intruding Leap Seconds would show as jumps of 1000 ms after the relevant UTC months in the milliseconds column below.
Using 0..11 for the months. Y2k errors ( getYear(), new Date() ). Field order. GMT/UTC confusion. One-character postfixes.
Often, new Date('##/##/####') and new Date('##/##/##') will use an incorrect, browser-dependent field order, and the latter may give an unwanted century. See in Your Settings.
String lastModified can behave in the same way.
Early Firefox 3.0 and Chrome 0.2 to 3.0 give an empty string for a local file.
N = Date.UTC(Y, M, D) and N = Date.UTC(Y) can return values of N outside Date Object range; Y can exceed 1e297 for finite N which might be surprising.
My MSIE 6, 7 & 8 show as for MSIE 4, but Firefox 2.0.0.3-3.0.7 and Chrome 1.0 show NaN. Safari 3.1 and 4.0 show 946684800000 (=2000/01/01 UTC), NaN. And 3.1556952e+109 = 1e99 × 365.2425 × 864e5.
Note that ECMA-262, 3 & 5, say that for fewer than two parameters the result is implementation-dependent.
Calling new Date(D) where D is a Date Object does not always return the same date in the new Object - this affected, in my MS IE 4, years -68..+69, which gave NaN in line B. IE also loses the milliseconds part. Use new Date(+D) instead; moreover, it is commonly much quicker.
For me, the middle result in IE4 was, and in IE6 & IE7 is, NaN; but Firefox, Opera, Safari and Chrome give all three the same. In IE, +D is notably faster than D (but slightly slower in Safari 3).
In my MSIE 4, setYear(2003, 9, 11) only set the Year, but setFullYear(2003, 9, 11) correctly set Year Month Day. The time was not changed. With setFullYear(Y) , Y in 1..99 gave those years, not 1900 higher; and Y<1 gave B.C. |Y|+1.
So D.setHours(0,0,0,0) ; D.setFullYear(Y, M-1, D) can be better than new Date(Y, M-1, D) if the Year may range widely.
Note that IE6 & IE7 give "10 B.C."; but Firefox 2.0.0.3-13 give "-0009" and Opera 9.21 and Safari 3.1 give "-009", which are Astronomers' notation.
I've read that some systems may give date strings whose formats vary unreasonably, for example when the year changes widely. MS IE 6 is one such. Date strings also vary between browsers.
It will be safer, and easy enough, to build one's own date strings, from numbers.
In some browsers, the tostring (default) method of Date Objects gives an unnecessarily long string; and the extra material is not necessarily correct.
IE7 : Wed Jun 24 14:22:00 UTC+0100 2009 FF3 : Wed Jun 24 2009 14:22:00 GMT+0100 (GMT Daylight Time) Op9 : Wed, 24 Jun 2009 14:22:00 GMT+0100 Op10 : Wed 24 Jun 2009 14:22:00 GMT+0100 Sf3 : Wed Jun 24 2009 14:22:00 GMT+0100 (GMT Daylight Time) Cr1 : Wed Jun 24 2009 14:22:00 GMT+0100 (GMT Daylight Time)
Parsing of date strings is unspecified. In particular, earlier Opera (including 10.10 but not 10.52) ignored regional indications such as EDT. Usually, only GMT, UTC, amd American ones are recognised.
Note that such as new Date("... EST") has commonly been used to initiate countdowns for events planned in UTC.
JavaScript is required by ECMA-262, 3rd Edn, Sec 15.9.1.1 to determine the state of Summer Time and Leap Year by using the current settings of the operating system for the current location, which are not necessarily correct for the date in question. Some systems do not comply.
Some browsers seem to determine the rules at page load or after, some at browser load.
Changes in Summer Time rules may cause difficulties.
It is possible for Summer Time clock changes to occur to/from local Midnight (example : the Azores). That could confound some routines, Date Validation in particular.
I see no direct reliable way of setting a year in the range 0000-0099 into a date object; year numbers in that range gave years in the 1900s in MSIE 4. One can use an out-of-range month; for example, new Date(4,1-12*1900,29) set Sunday 29th February 0004. Alternatively, use a 10000 year bias throughout. Or set the month and day into a safe Leap Year (e.g. 400) then use setFullYear(Y).
In later browsers, setFullYear(Y) should be reliable. Remember setFullYear(Y, M, D).
There was in fact no Leap Day in the year 4 AD; and we had one in each "century" year before 1800; JavaScript is strictly Gregorian Calendar. To use Julian Calendar dates, see in 8: Enhancing the Object.
Presenting, on the Internet, a date in a format which is internationally ambiguous. Neither DD/MM/YYYY nor MM/DD/YYYY is appropriate; nothing using YY is appropriate. Use ISO 8601 YYYY-MM-DD to be safe.
Using millisecond arithmetic where daycount arithmetic is appropriate; some days differ in length.
Forgetting other effects of Summer Time, or of its variation across the world.
Forgetting Time Zones.
Using a localised date.time unnecessarily; for example, using EST for a date/time originated in UTC.
Using daycount arithmetic where month or year arithmetic is appropriate; months and years vary in length. To go ahead a year, setMonth(getMonth()+12) seems best; it avoids getYear / getFullYear doubts.
Forgetting that in JavaScript the months are 0..11.
Seeing an unexpected year in the set 69, 70, 1969, 1970, 2069, 2070 and not connecting this with time being measured from 1970-01-01 00:00:00 GMT.
Seeing an error of 100 years or a multiple of 1900 years and not relating it to the "centade" defaulting to the 1900s and/or the use of two-digit years. Note : 1900 years is about 693960 days.
Using new Date() without parameters when the current date/time is not needed; the object given will be date-dependent and therefore results may be unnecessarily inconsistent. Use new Date(0), which is quicker, if necessary; remember GMT.
Using new Date() more than once, except for interval work; it keeps changing.
Using new Date(S) to validate a date string S; over-range fields can be silently accepted, and field order can be uncertain.
Changing an unknown date piecemeal; as months differ in length, setting Y M D in sequence can go through a non-existent date, with unexpected effects. One can safely set D=1, then Y=Y', M=M', D=D'; or setFullYear(Y', M', D') instead.
Forgetting that setTimeout delays have overhead, and also may need to wait for the next clock tick; see in 0: Date Object Information.
Inappropriately relying on the settings of a client computer. If a Form action needs a trustworthy date/time stamp, apply it at the server end, which should be more reliable.
Not realising that an error specific to the 8th & 9th of a month, and/or to August & September, is very probably caused by using parseInt without a second parameter - but use the unary + operator instead.
Not testing exhaustively, especially considering the previous.
Relying on I/O string formatting matching across all browsers, versions, and possible dates.
I do not know whether new Date('30 Apr 2008') is satisfactory in all browsers. It should be good for English-speaking ones. But a foreign browser that writes 'Avril' or 'Oktober' may not read 'April' and 'October' or their short forms. For safety, write new Date(2008, 3, 30). However, new Date('2008/04/30') is probably safe.
And new Date('####-##-##') was not recognised on my IE systems, while new Date('##-##-####') was read as MM-DD-YYYY (IE4?, IE6, IE7). Some results vary among browsers.