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

JavaScript Date and Time 0 :
Date Object Information
.

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.

Date and Time Information

The Date Object

JavaScript dates are Gregorian. They are held in milliseconds from the UNIX base of Thursday 1970-01-01 00:00:00.000 GMT, which works out as 1969-12-31 to the West of the Atlantic (12/31/69 in the USA). It could be unwise to over-trust all date arithmetic before that epoch, although I have as yet seen no such problems after AD 99. ECMA-262 JavaScript and GMT have no Leap Seconds; the use of the term UTC is in principle an error.

In the UK, new Date(0) will display as "Thu Jan 1 00:00:00 UTC 1970" or equivalent; in accordance with specification, only the current Summer Time rules, as set in the OS, are used.
That really should be "Thu Jan 1 01:00:00 UTC+0100 1970", since we then used British Standard Time, GMT+1, year-round.

Injudicious "Y2k correction" may make those base dates appear as 2070 or 2069.

The JavaScript 1.3 Date object is stated to cover up to ±1E8 days from 1970.0 UTC (i.e. from the start of BC 271822-04-20 UTC up to the start of AD 275760-09-13 UTC). The Proleptic date scale is Astronomical; year numbers run -2, -1, 0, 1, 2 (cf. The Non-Year Zero).

In MSIE 4, Date.parse() accepts "AD" and "BC", but not years BC 69 to AD 69; AD 70 to AD 99 become 1970 to 1999. Earlier JavaScript may not handle negative values.

Much use of years 0000 to 0099 seems liable to error.

Published general date algorithms should specify the calendar used or the range of validity, in order to prevent avoidable user error. JavaScript and calendar datings disagree in British locations before 1752-09-14; elsewhere, before 1582-10-15 or otherwise.

N.B. JavaScript numbers the months January to December from 0 to 11 (the code behind parts of these pages also uses 1 to 12).

N.B. The setTime, getTime and valueOf methods use GMT milliseconds; this needs to be borne in mind when doing civil date arithmetic, as Summer Time shifts days with respect to GMT. They are not needed in incrementing and decrementing dates; they are useful for subtracting dates, when precautions such as Math.round are needed.

N.B. JavaScript operations automatically transform their inputs to probably-suitable types, if possible. Let D1 D2 represent Date Objects. Then document.write(D1) writes the result of D1.toString() and D2-D1 converts each to Number with .valueOf() and gives the difference in milliseconds. And unary + can therefore be used in lieu of .valueOf() to give the number of milliseconds since 1970.0 GMT.

So, D2 = new Date(D1) may go via an intermediate String (slow, losing the milliseconds. and enabling the "first centade" error), whereas new Date(+D1) must go via an intermediate Number (fast, and without error).

It now appears that D2 = new Date(D1) conversion via String applies to MS IE (and in WSH) but not to other major browsers.

Date Methods

From time to time, Methods have been added to various Objects; care is therefore needed to avoid calling a Method which is not known in all target browsers. There's probably a full list on the Web somewhere.

Early browsers did not have getFullYear setFullYear, nor the UTC Methods?

Date Object String Output Methods
Routine               ECMA    Server   My My  My  My  My  My  My
                       262    JScript IE6 IE7 IE8 FF3 O10 Sf4 Cr4
                      3  5

D.now                 N  N    ?        N   N   N   N   N   N   N
Date.now              N  Y    ?        ?   ?   N   Y   N   Y   Y

toDateString          Y  Y    ?        Y   Y   Y   Y   Y   Y   Y
toTimeString          Y  Y    ?        Y   Y   Y   Y   Y   Y   Y
toLocaleDateString    Y  Y    ?        Y   Y   Y   Y   Y   Y   Y
toLocaleTimeString    Y  Y    ?        Y   Y   Y   Y   Y   Y   Y

getVarDate            N  N    Y        Y   Y   Y   N   N   N   N
toISOString           N  Y             ?   ?   N   N   N   Y   Y
toJSON                N  Y             ?   ?   Y   N   N   Y   Y
In Microsoft Date Type Extensions, there are routines such as Date.parseLocale(value, formats);. They are extensions to the base ECMAScript (JavaScript) Date object, provided as part of the Microsoft AJAX Library. Likewise for Array, Boolean, etc.
Some implementations of toJSON toISOString give results to 3 decimals of seconds; others just to seconds.

Date Object Creation

When it is necessary to create a Date Object, and it is not necessary that it holds the present moment, use new Date(0) rather than new Date() since (a) it is considerably faster, and (b) it gives a determinate result, which helps prevent intermittent error. Alternatively, consider new Date(NaN); sometimes slower.

Indeed, Q = new Date(ZellerMJD(2000, 2, 29)) was considerably faster than Q = new Date(2000, 1, 29) in my MSIE4 (see The Calendrical Works of Rektor Chr. Zeller : The Day-of-Week and Easter Formulae for ZellerMJD). The latter must consider Summer Time.

Leap Seconds

Some systems incorrectly show Leap Seconds; see Leap Seconds in Computing.

Written Date and Time Formats

Remember that the preferred formats for dates and times are dependent on locality. The ISO 8601 forms YYYY-MM-DD and hh:mm:ss can be used for international compatibility; both DD/MM/YYYY and MM/DD/YYYY are ambiguous on the Web. Leading zeroes should be applied to what would otherwise be single-digit fields. As far as I know, all systems accept new Date("YYYY/MM/DD") correctly.

It is best to use the ISO 8601 24-h clock, since a.m./p.m. can easily be misinterpreted - or wrong - I've read that Netscape's Date object transposed "am" and "pm" within 12:00..12:59. However, some code for 12-h times is accessible via 4: Validation, 9: Output Formatting and Include Files.

Field Rollover

This greatly simplifies much work; for example, it solves many month-length questions.

If one attempts to set a field of the date/time out of its normal range, then rollover and carry occurs to give a normal value - to such an extent that the following writes the UNIX gigasecond rollover, in GMT :-

or, somewhat differently and for the Great UNIX "time_t" Rollover :-

To convert Windows File Time (count of 100  ns from Gregorian 1601-01-01 00:00:00 UTC, which cannot now be held exactly) :-

Note that
  X = new Date() ; X.setYear(Y) ; X.setMonth(M-1) ; X.setDate(D)
will go wrong if the present date does not fit in the intended month; use
  X = new Date(Y, M-1, D)

instead. To set a date in the present but unknown year
  X = new Date() ; X.setDate(1) ; X.setMonth(M-1) ; X.setDate(D)

or the generally-forgotten
  X = new Date() ; X.setMonth(M-1, D)

If the Year may be small, use X = new Date(0) ; X.setHours(0,0,0,0) ; X.setFullYear(Y, M-1, D) .

Month Changing

Going, say, to a date 3 months ahead,

JavaScript will, if the nominal date is impossible (e.g. Feb 30, Apr 31), give D as an equivalent date at the start of the next month (see also in Date and Time 1 : Date Arithmetic). Different languages do differently.

Use getDate to see whether the day-of-month has changed, and, if so, use either setDate(1) or setDate(0) (NS4 Mac ?). Tested, though not exhaustively :-

Do similarly for year changing, if the initial date may be February 29th.

See also via Date and Time Introduction, and in Calendars and Clocks and include3.js, which contain various items of date/time code.

Regular Cycling of a Page/Image Set

Where, accessing a page on different occasions, a response should cycle regularly through a range of length N, the following may be suitable. Use additive constants after getTime() to adjust the time of the change and/or the phase of the cycle.

Consider whether the day is to be the GMT day, an author-defined day, or the user's local day. Don't forget Summer Time. N.B. those methods with getTime use the GMT day/hour; this can be changed to user's local time by subtracting getTimezoneOffset*60000.

With a Date object, (( getTime()/60000 - getTimezoneOffset() )/1440) % 1 gives the fraction of the civil day.

Load the page by such as window.location.href = PN where PN is the computed page name; it is easier to use numbers rather than names such as June or Friday.

Hourly

Try
  Math.floor( getTime()/3600000 ) % N

Daily

For N=7, use getDay(). Otherwise, try (changes at midnight GMT)
  Math.floor( getTime()/864e5 ) % N

Weekly

First decide upon the Week definition. Try
  Math.floor( ( X + getTime()/864e5 ) / 7 ) % N
with X=3 for ISO GMT weeks.

Monthly

For every Gregorian calendar month, use
  ( getFullYear()*12 + getMonth() ) % N

Scheduled Selection

Selection by GMT hour of week

This returns the desired string (briefly tested; not optimised). Note that it uses JavaScript Day-of-Week, in which Sun=0.

If updating is required, either use setInterval() to run the above at reasonable intervals, or use setTimeout() to schedule the next change.

Changing for user's local time is trivial; for other local time, see in 5: Date and Time Elsewhere.

Cookie Dates

I don't use cookies; but I believe that the following may set a usable one :-

I get format as Thu, 12 Feb 2004 22:24:00 UTC .

Normally, the expiry date should be calculated using the largest appropriate unit of time. The above will usually show what get/setMonth does over a Summer Time change. When forcing expiry by using a past date, there seems no need to calculate one; just write one in.

Formal standards may call for a slightly different format, Wdy, DD-Mon-YY HH:MM:SS GMT ; if necessary, a RegExp replace would fix it.

There seems to be a little-known Max-Age value, which would be useful if it were reliable - RFC 2965.

To expire a cookie, there's no point in calculating a date; and "expires=Thu, 01-Jan-1970 00:00:00 GMT" is insignificantly longer than "expires="+new Date(0).toUTCString() and definitely shorter than what is commonly used.

Cookie Links

I have read that :- "A new European Directive (2002/58/EC) will come into force in the UK during 2003. This imposes new rules on the use of cookies and similar mechanisms. ... " and that it is scheduled for October. Interpretation is unclear.

Date Information

Date Parsing

ECMA-262 does not define how date/time strings should be parsed.

My MSIE4 treated ##/##/#### as mm/dd/yyyy; I believe that to be general. It understood ####/##/## as yyyy-mm-dd, but gave NaN for ####-##-##, which Opera 10 understands. See also JavaScript Date and Time Troubles.

See also in Date and Time 3 : Input and Lengths.

Year 2000

Trap : a date string such as 00/02/29 may be interpreted as being in the wrong century! One sign of this would be a Day-of-Week error (##00-02-29 is always Tuesday).

For "Year2000", see the "Java/Javascript" section under Year 2000 Programming; getYear() returns strange, browser-dependent values; but getFullYear() should be available for Version 4 browsers and above (JS1.2 & up). One day, maybe, the deprecated getYear() behaviour will start to disappear.

See also at Last Modified.

To get a two- or four- digit year number from a Date object, one can use the Mod operator :-

getYear

In some systems, getYear() returns either a two-digit number or a number 1900 less than expected. And getFullYear() is not always available. For your system :-

Note that the result of the above is reportedly browser-dependent.

"Method getYear can return any one of these three sequences for years : 97,98,99,00,01 or 97,98,99,2000,2001 or 97,98,99,100,101". As far as I know, getYear() always increments over 2099..2100; but it might not do so for browsers of the first sort.

	          For Y ≥ 0 : FY = Y.getFullYear()
STANDARDS	  Y.getYear() = FY-1900
Firefox 2.0.0.7	  Y.getYear() = FY-1900
Opera 9.2x	  Y.getYear() = FY-1900
Opera 9.50	  Y.getYear() = Math.floor(FY/100)==19 ? FY%100 : FY
Safari 3.1	  Y.getYear() = FY-1900
Chrome		  Y.getYear() = FY-1900
MS IE 6 / 7	  Y.getYear() = Math.floor(FY/100)==19 ? FY%100 : FY
Unknown		  Y.getYear() = FY%100

getFullYear

JavaScript function getFullYear() , where present, returns the true (Astronomical) year number, ... -2 -1 0 +1 +2 ... 1899 1900 1901 ... 1999 2000 2001 ... .

Where getFullYear() is not provided, one can define one's own, to cover a limited but adequate range of years - maybe by :-

But that fails where getYear() for 2000 returns 0.

This approach should be better; it assumes only that getYear()%100 is always correct :-

We know that the answer must be close to YE, but will, rarely, differ by a year; that may affect the first two digits, so it's not possible to use 100*(YE div 100)+Y2. Offset from GMT is accommodated by using getYear rather than only getTime. Function getFY tested below is an optimised version of the above getFullYear algorithm.

 =  ()

The algorithm could be made a method of the date object.

Again, see also in Year 2000 Programming.

Two-Digit Years

Often, one must accept dates which may have two- or four- digit years, perhaps parsed in error by centuries, and convert them to true years. In the case of lastModified, it is certain that the year in question is not earlier than the year of coding; in other cases, the context may limit the year span. Consider, therefore, with x preselected :-

It may be appropriate to use a dynamic limit; so many years forward, and so many back, from the current date or year.

Using a 10000-year bias can avoid difficulties.

To convert a string S whose first four-digit field is ccyy to have yy instead (a foolish move), consider :-

Date Comparison

If the dates are in Date Objects, just compare (< <= >= > == !=) the valueOf() or getTime() for each object. It may be useful to adjust one or both Object values before comparison. Ordered comparisons (< <= >= >) can in fact be performed on the objects themselves (i.e. conversion to Number is automatic) but for equality testing (== !=) conversion to Number must be explicit, though unary + suffices.

If they are in strings, the result depends on the format of the strings. ISO 8601 date strings can be compared directly. A fixed-length numeric date string can easily be normalised with .replace() or otherwise; see in 9: Output Formatting.

If the dates are already number-triples, convert them to pseudo-daycounts as below and compare. It is only necessary that the multipliers are large enough; the method will even work for the Hebrew Calendar, if the months are counted carefully. The unary + signs ensure addition, even for a string parameter.

The following technique can convert any normal separated numeric format to such a pseudo-date :-

The negative signs force conversion from String to Number; change the indexes around for other field orders. Or use a RegExp such as follows or below.

For Array sorting, see in JavaScript Sorting and Order. For differencing, see in 1: Date Arithmetic.

To tell whether a date is more than 4 months ago, it is useful to compare it with (D = new Date()).setMonth(D.getMonth()-4) considering whether it matters that the destination month may not accommodate the current Date. For this task, direct subtraction is unadvisable.

Personal Age

A personal age changes when the month/date becomes equal to or greater than the month/date of the day of birth.

Age depends on year/month/date, independently of the lengths of the months; subtracting a Pseudo-DayCount is effective (unary + is used in PDCount to convert string to number) :-

Another method is to subtract the years, then to subtract one if the start month is after the end month or the months are equal and the start day is after the end day.

See also in 1 : Date Arithmetic.

Season

For checking the season, there is no need to test day and month individually; one can test a Pseudo-DayOfYear. If the seasons begin on the 21st,

Note the use of OR for the season spanning New Year.

To get an index, 0..3, for the Season (Southerners :- xor with 2, or add 6 months) :-

See also in 2 : Demonstrations.

Day of Year

Properly called Ordinal Date; sometimes Ordinal Day of Year or [business] Julian Date, but see Date Miscellany I. The last column is a reverse count with Dec 31 = 1; some prefer Dec 31 = 0.

Another way :-

For the Julian Calendar, either use Meeus or use 2000+Y%4.

The reverse is easy :-

Days Before Month

Easter Sunday

The date of Gregorian Easter Sunday can be calculated by routines in estr-inc.js, shown in Include Files; see also via The Date of Easter Sunday :-

Further routines, including Julian Easter, can be found in my Zeller pages, and a discussion of Easter etc. is in my The Date of Easter Sunday. JavaScript algorithms derived from the Book of Common Prayer and elsewhere are in my The Calculation of Easter Sunday from the Book of Common Prayer of the Church of England. The Roman Catholic standard is implemented (with matching results) in Easter Algorithms from the Six Canons of Christopher Clavius, etc.

Note that Easter algorithms generally compute the date in days from a fixed date in March, and then convert to customary form covering March 22nd to April 25th. If a Date Object is required, just set that number of days in March - ESu = new Date(Y, 2, Days) - since the Object handles month roll-over.

Time Information

Time Parsing

ECMA-262 does not define how date/time strings should be parsed.

See also in 3 : Input and Lengths.

Offset from GMT

Date strings can accept a trailing field designating the offset from GMT; but this seems unreliable. Using my MSIE 6 :-

  Date.parse("2000/01/01  +0830") represents 1999/12/31 15:30 GMT
  Date.parse("2000/01/01  -0830") gives NaN
  Date.parse("2000/01/01 +-0830") represents 2000/01/01 08:30 GMT
  Date.parse("2000/01/01 -+0830") represents 1999/12/31 15:30 GMT

In my MSIE4 (in UK summer) :-

  Date.parse('1/1/1 ' + '10:00AM') represents 1901-01-01 10:00:00 GMT
  Date.parse('1/1/1 ' + '10:00PM') represents 1901-01-01 22:00:00 GMT
but
  Date.parse('1/1/1 ' + '10:00A')  represents 1901-01-01 11:00:00 GMT
  Date.parse('1/1/1 ' + '10:00P')  represents 1901-01-01 07:00:00 GMT

For compatibility, there should be no colon in the Offset part :-

 IE 7Firefox 2Opera 9Safari 3Chrome?
ANaNOKD OK, T odd"Invalid Date"
BOKOKOKOK
CNaNOKD OK, T odd"Invalid Date"
DOKOKOKOK
ENaNOKD OK, T odd"Invalid Date"
FOKOKOKOK
GNaNOKD OK, T odd"Invalid Date"
HOKOKOKOK

Single Postfix Letters

A single postfix letter used as in D = new Date('1/1/1 12:00e') is usually taken as giving a time zone; the JavaScript designation, where "working", reverses the military one, but agrees with a refuted Internet RFC.

My MSIE 4 (MSIE 6 agrees) gave the following GMT hours of that day (1901-01-01) :-

   A   B   C   D   E   F   G   H   I   J   K   L   M
  13  14  15  16  17  18  19  20  21 NaN  22  23  24

   N   O   P   Q   R   S   T   U   V   W   X   Y   Z
  11  10   9   8   7   6   5   4   3   2   1   0  12

There, A to M are for zones to the West, and N to Y are for zones to the East; and Z (Zulu) is for GMT.

Your system gives the following GMT hours of a day :-

Non-MSIE browsers do various peculiar things; Sun Oct 25 1959 00:00:00 local time has been reported in Safari, but the cause may differ.

My Firefox 2 did not recognise Zone letters; all results above for A-Z showed as NaN and "Zone E noon" gave "Invalid Date".

My Opera 9.2 did not recognise Zone letters; all results above for A-Z showed as 12 and "Zone E noon" gave "Fri, 08 Jun 2007 00:48:00 GMT" on that day.

My Safari 3.1 does not recognise Zone letters; all results above for A-Z show as NaN and "Zone E noon" gives "Invalid Date".

Chrome?

Clearly, however,
  (a) The notation is unsafe in JavaScript.
  (b) But it explains why such as 01:02:03A and 02:03:04P are not taken as AM and PM.

For the true "military" system, see in my Zone Designations; JavaScript differs.

Time Comparision

Times can be compared by conversion to [pseudo-]seconds with simple arithmetic, or by combining with a date and parsing into a Date Object. See also above.

D = new Date()
X = 100*D.getHours() + D.getMinutes()
OK = X > 0900 && X < 1745  // between 09:00 - 17:45 LCT

Care is needed with non-ISO notations, and where a variable offset from GMT is to be included.

12-h Comparison

The following should convert a well-formed 12-h clock string to a form for which string comparison matches chronological order :-

This should be more liberal :-

Differences from GMT

Whenever doing date arithmetic, remember to think about the effects of Summer Time and about the possibility of the executing computer having a different Time Zone Offset. Days do not all last for 24 hours or 86400 seconds. Setting the hours to 12 may help, as may using UTC functions. For administrative date work, consider working with day counts instead of date objects.

As I see it, Summer Time in Windows uses only the current rules for the location. JavaScript uses the current rules provided by the OS and applies them for all years, which is historically inaccurate. For the UK, my Win 98 1st Edn MSIE 4 correctly used (its incorrect version of) the present EU rules throughout; in the UK, different rules were applied before 1996 (and gave different results in 1995 and in most earlier years, especially around 1970).

GMT & UTC are standard, well-defined terms. But other three-letter abbreviations can be, world-wide, ambiguous (AIUI).

British Time code, possible New York Time code, probable Beijing Time code, and Date And Time Anywhere, is in 5: Date and Time Elsewhere ff..

Caveat

Here, as elsewhere, 864e5 is the number of milliseconds in a standard day.

For those with a browser set for a location which is not on GMT, the above will (I expect) show that some Inputs are taken as Local Time; so care will clearly be needed in doing arithmetic with such values. Date code for the Internet needs to be tested for Summer Time effects.

Time Zone Offset

The number given by getTimezoneOffset() is the difference in minutes between local time and GMT - actually getTimezoneOffset = (GMT-local). Like the offset in a TZ string, it is negative in Australasia and positive in the Americas; it is zero in UK Winter and -60 in UK Summer; local = GMT-getTimezoneOffset. It matches the formula given in Win32 Help :- UTC = local+bias. These treat local time as prime and GMT as subsidiary.

It is of the opposite sign to the time zone indicator given by Date.toString(), which in MSIE 4 is of the form UTC±hhmm. That is what must be added to GMT to get local time, which is rational; but in headers (without GMT/UTC) it looks to me a bit silly -

Date: Wed, 8 Aug 2001 20:29:41 +0100

actually means 19:29:41 GMT (example is in UK Summer). A better header style would be

Date: Wed, 8 Aug 2001 19:29:41 GMT (20:29:41)

In include3.js, function TZstr() is added to the Date object to provide the time zone indicator ±hh:mm. Note that the colon may be superfluous; easily fixed.

JavaScript cannot access the name or abbreviation of the local time zone.

Epoch and Interval

For time, there is a clear distinction to be drawn between an Interval, which is a length of time or a duration, and an Epoch, which is an instant of time. An Interval requires a scale, nowadays related either to an astronomical motion (Year, Day) or to an atomic frequency (Second). An Epoch additionally requires a known Reference Point of given value.

A JavaScript Date Object stores an Epoch. The difference of two Epochs is an Interval.

The only proper Epoch arithmetic operations are Epoch = Epoch ± Interval and Interval = Epoch - Epoch.

An Interval in [milli]seconds can be converted without ambiguity to Minutes-and-Seconds; and in Minutes to Hours-and-Minutes. Converting Hours to Days-and-Hours needs care, because of possible Summer Time transitions. Converting Days to Months-and-Days is unsatisfactory, because of the differing month lengths; but converting Months to Years-and-Months is safe.

See also in Difference in Time and Cardinals and Ordinals.

setTimeout and setInterval

Methods setTimeout() and setInterval() cause the cited code to be executed at or after the given delay, when other execution threads are completed. They are not equivalent to the Delay function of other languages, since they do not suspend the thread which called them.

Methods setTimeout() and setInterval() do not always give, unaided, absolute timing. The stipulated delay may be rounded to the nearest, or extended to the next, tick of an internal timer. The timer is presumably that used in implementing new Date() for which see in Date and Time Introduction.

In MSIE 4 Win 98, the DOS 18.2  Hz timer is used. For timing in steps of one second, this gives an error of the order of 4-5%.

In WinXP sp2 IE6, one-second intervals seem accurate.

In this page, the following starts the timers below :-

<BODY onLoad="Tick();Tock();setInterval('Interval()', 1000)">

Method setTimeout()

To get intervals synchronised as well as possible to proper computer time, call new Date(), calculate the time Q to go until the next event, and use setTimeout(..., Q) as in function Tock() .

Tick()   Tock()
 
seconds

In my IE4, Tick ran slow and thus missed some seconds, whereas Tock showed every second. In my IE6, FF2, Op9 and Sf3, Tick sometimes slips, but Tock seems reliable.

For other examples, see function Running() in Calendars and Clocks and/or function TimeNow() in Alarm and/or function EachSecond() in 2: Demonstrations, also in 5: Date and Time Elsewhere.

Method setInterval()

A seconds countdown clock using setInterval may run slow, and therefore finish late.

Interval()
.
.

In my IE4, Interval - which was started by setInterval('Interval', 1000) - also ran slow and missed some seconds.

Page Load Time

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.