logo To Foot
© J R Stockton, ≥ 2010-03-06

JavaScript Date and Time Troubles.

No-Frame * Framed Index * Frame This
Links within this site :-

See "About This JavaScript Site" in JavaScript Index and Introduction.

See "General Date/Time Introduction" in JavaScript Date and Time Introduction.

The bugs below have, I hope, been avoided in these pages (except where noted); and the deviations accommodated.

Differences between Browsers

Except if otherwise indicated, these differences are all seen on my own systems.

From Summer 1998 to 2006-10-14, I used MS IE 4, on a desktop PC with Win98 1st Edn.

I currently have a desktop PC with Windows XP pro sp3 and a laptop PC with Windows XP pro sp3, and mainly use the desktop.

I got MS IE 6 with the desktop on 2006-10-19, replacing it with IE 7 on 2008-03-18 and IE8 on 2009-07-21.

I got MS IE 7 on the laptop on 2007-01-18, replacing it with IE 8 on 2009-07-19.

I got Firefox 2.0.0.3 on the laptop on 2007-03-31 (Firefox now on both machines, updated in steps to 3.0.18 and 3.6).

I got Opera 9.20 on the laptop on 2007-04-25 (Opera now on both machines, updated in steps to 10.10).

I got Safari 3.0.4 on the laptop on 2008-01-04 (Safari now on both machines, updated in steps to 4.0.4).

I got Chrome 0.2 on the laptop on 2008-09-10 (Chrome now on both machines, updated in steps to 4.0).

Automated Tests

Entries in the "Yours" column are computed by your browser using function X35. Other columns do not necessarily refer to the latest browser release.

#Test
(details in code)
IE
6/7/8
Firefox
3.0
Opera
9.6, 10
Safari
4
Chrome
3.0, 4.0
YoursISO
std
01Date.UTC(Y,M,0) OKtruetrue ‡truetruetruetrue
02new Date("Y/M/D") rangetruetruefalsetruetrue-
03getYear() for 200820081082008 ‡108108108
04new Date(2e99)NaNInvalid DateNaNInvalid DateInvalid DateNaN
05new Date("2222/11/11 +03:00") OKfalsetruetruetruefalse +-
06new Date("2222/11/11 +0300") OKtruetruetruefalsefalse +-
07lastModified OKtruetruetruetrue ‡true ‡N/A
08new Date("1969 Dec 29")truetruetruefalsetrueN/A
09Not Exceed Date Rangetruetruetruefalsetruetrue
10new Date("1970/01/01 EST") OKtruetruefalsetruetrueN/A
11new Date("2009/01/123") OKtruetruefalsetruefalseN/A
12new Date("2009-05-07") OKfalsefalsetruefalsetrueN/A
13new Date("0077/05/03").ISOlocaldateStr()1977-05-031977-05-030077-05-031977-05-031977-05-03N/A
14new Date("3/6/9").getFullYear()190919091909 ‡20092009N/A
15new Date("2 Bananas 2004").getMonth()NaNNaN# ‡NaNNaNN/A
16new Date("1 Octopus 2004").getMonth()NaNNaN# ‡99N/A
17new Date("25 2009")>0falsefalsetruefalsefalseN/A
18!!new Date(0).toISOStringfalsefalsefalsetruetrueNew
19toISOString() (see source)falsefalsefalse12345-06-07
T11:22:33Z
12345-06-07
T11:22:33Z
+12345-06-07
T11:22:33Z
20no offset (see source)falsefalsefalsefalsefalseN/A
21Military time offset (see source)17NaN12NaNNaNN/A
 
A\s matches \u2029falsetruetruetruefalsetrue
B(0.007).toFixed(2)0.000.010.010.010.010.01
C(0.5).toFixed(0)010, 1111
DparseFloat test1011111
EparseInt("09")00900?
FX = 0.1230.toPrecision(4)0.12300.12300.1230.12300.12300.1230
 
ZVBScript DatePart WeekNo53....MS IE only1
 ‡ : see corresponding Note below.
‡ Table Notes :-

See also Resolutions of new Date().

Date formats may be influenced by OS settings (Opera?).

Values from getYear()

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 : Opera 9.6, 10.00
   -3   -2   -1    0    1    2   97   98   99  100  101  102 : STANDARD

Other MS IE and Firefox

This section contains quick notes, for further test.

new Date("mm/dd/yyyy AD")	FF no good with AD/BC there
new Date("mm/dd/yyyy G")	FF no good with Zone letters
new Date(Bad date string)       FF gives "Invalid Date", not NaN

Date Object to String           Differing formats (allowed)

Also - certain centreing, sizes differ slightly.
Back from a calculated page loses position.

Other MS IE and Opera

This section contains quick notes, for further test.

new Date("mm/dd/yyyy BC")	Op ignores BC
new Date("mm/dd/yyyy G")	Op no good with Zone letters
new Date(Bad date string)       Op gives NaN or <today>
Date.UTC(2E99)                  Op kills script ?

Date Object to String           Differing formats (allowed)

Also - certain centreing, sizes differ slightly.

Other MS IE and Safari

This section contains quick notes, for further test.

new Date(Bad date string)       Sf gives "Invalid Date", not NaN ??

Date Object to String           Differing formats (allowed)

Other MS IE and Chrome

This section may contain quick notes, for further test.

Some Date Bugs

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.

Opera Summer Time

In locations without seasonal clock changes, this section should be uninteresting.

2009-09-22
I had thought that the error was fixed in Opera 9.64. Either that was a mistaken observation, or something rather inexplicable happened.
I saw these errors in Opera 10.00, with location set to UK, independently of the state of Summer Time at the date to which the PC is set.

Opera Error with new Date(Y,M,D)

I see, in Opera 9.21 .. 10.00, 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

It appears that this test shows errors in XP with the London setting, but not with New York, Azores, Paris, or Moscow settings.

Opera Error with Date.getTimezoneOffset()

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.

Non-Europeans can test their own dates.

My results - Local date and time, and offset to GMT:
Opera (9.xx and 10.00)			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

List Offset Changes

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, Safari & Chrome.

Test Every Mid-Quarter-Hour

Years : -     Maybe 15 secs/century

Date Range Fault

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.

I hear that Safari 1.2.3 on Mac OS 10.3. shows a range of ±231 seconds from zero - 1901-12-13 to 2038-01-19 GMT. That suggests that the update interval of new Date() may be one second, and that its resolution may be one second - see in Date and Time Introduction. However, a 1 ms resolution has been reported for Safari.

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 are all OK.

Date() / new Date()

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.

Day Underflow 1

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?).

Day Underflow 2

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.

AM/PM Error

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.

YYYY/MM/DD Input Error?

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.

Zero Test

If GMT or UTC were not recognised, there would be an alert when local time is not GMT/UTC.

Offset

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?

Offset Sign

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.

Unapproved Chronology

ECMA-262, 3rd Edn, page 118, Sec 15.9.1.9 says clearly enough that the current Time Rules must be applied for all years. Page 120, para 1 (in the *first* 15.9.1.9) says clearly enough that the current Summer Time rules must be applied for all years.

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.

Date-Dependent Rules

Assuming that January 1st is always firmly in either Winter or Summer at a given location, that should show equal values for each year. So I, with Win98 IE4 in UK, saw Hours 0 0 0 0. Apparently it is different in Mozilla and Konqueror under Linux set for Brisbane, Australia, where things changed in 1992; and the Hours appear as 13 13 14 14.

In North America, things changed on 2007-03-01.

Leap Seconds

It seems also that, in such systems, Leap Seconds may have an unapproved effect :-

There were Leap Seconds in the middle of UTC 1997 and at the end of UTC 1998.

I see 0 0 0 0; and so I think should everyone else with ECMA-compliant systems. Intruding Leap Seconds show as jumps of one second after the relevant UTC months.

It is likely that a number of routines on these pages will FAIL on browsers that show Leap Seconds.

Some Deviations from Reason

Using 0..11 for the months. Y2k errors ( getYear(), new Date() ). Field order. GMT/UTC confusion. One-character postfixes.

Interpretation

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.

lastModified

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.

Range

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.

In Opera 9.21, but not 9.64, results were strange with vast M for Date.UTC(2000, M, 1).
Test X11b is now suppressed in Opera.
Date.UTC(1e99) wrong number of arguments.

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, 3rd Edn, says that for fewer than two parameters the result is implementation-dependent.

Date Replication

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).

    P4 3GHz XP sp2 IE6 : 4 seconds.

setYear()

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.

Output Date Formats

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.

Some Mere Difficulties

Time Offset Indication

Parsing of date strings is unspecified. In particular, Opera ignores 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.

Summer Time

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.

Early Years

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.

Some Programmers' Follies

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.

Unknown

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.

JavaScript Date and Time Index
Home Page
Mail: no HTML
© Dr J R Stockton, near London, UK.
All Rights Reserved.
These pages are tested mainly with Firefox 3.0 and W3's Tidy.
This site, http://www.merlyn.demon.co.uk/, is maintained by me.
Head.