© J R Stockton, ≥ 2012-04-06

JavaScript Date and Time 3 :
Input and Lengths
.

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.

My JavaScript RegExps and Validation deals with data validation in general, and indicates an efficient way of coding it.

The Input of Dates and Times

For output, one must select in detail between a wide range of possible specific formats. But in input, one should be more general, since it is the value and not the layout which is important. The day of the week is not usually given; and, if permitted, is frequently ignored.

For the manual input of dates and times, processing speed is of secondary importance; it may be useful to show what has actually been entered, normalised to a local / standard form. In the processing of pre-prepared dates and times, format flexibility is generally unnecessary.

Note that string reformatting operations may be of use both with input and with output; they are found mainly in 9: Output Formatting.

Date Input

The year should be 4-digit, but may be 2-digit. There are three basic styles, tested in Date and Time 4 : Validation :-

Techniques used for the above can be adapted for the input of dates in other notations - year-day, ISO or HMRC year-week-day, etc.; often the layout will be better known.

For input validation, see in 4: Validation.

Unless stated otherwise, any of these routines may map years 00-99 to 1900-1999.

String to Date Object

If possible, use either "yyyy/mm/dd" or "yyyy Mon dd", which are unambiguous and easily read.

Note, however, that browsers vary and new versions have changes. To be truly safe, avoid the built-in direct conversions between Date Object and String by using intermediate Numbers.

Note that the only alphabetical time-offset indicators accepted by all browsers are GMT & UTC. Instead, use the numeric equivalent.

UK Date Format

The following should read a UK-order numeric date string S into a Date object, with or without leading zeroes and with any separator, in any browser, assuming 20xx unless specified :-

Another reliable way to convert valid local date strings of known, numeric, format to Date Objects should be along the lines of

  A = St.split(/\D+/) ; D = new Date(+A[i], A[j]-1, +A[k])

where ijk is a permutation of 012.

For UK numeric date format string, separated or not, 2- or 4- digit year, to Numbers D M Y :-

  dd/mm/yyyy dd/mm/yy ddmmyyyy ddmmyy

  numeric D M Y array
dd-Mon-yy

The following should read a valid dd-Mon-yy string S into an ISO 8601 string and a Date object, in any browser, assuming 20xx :-

The matching shows extraction of a 1-character day string from "01".."09", not needed here.

"Military"

According to a letter in the Christmas 2008 PCW, p.121, a basic military date/time format is as "241030ZJUN08", meaning 2008-06-24T10:30Z. The letter, here Z, gives the offset from GMT, in hours. The following should read a valid string of that form S into a Date object, in any browser, assuming year 20xx. Output is also shown.

Note : I believe that the military use the reverse of what my Time Parsing shows for JavaScript; see in my Time Zones. If necessary, change the sign of Ofs, twice.

Interpretation of ##/##/##[##]

MS IE 4 & 6 yield "1903-01-02"; US field order is assumed and the previous century is given.

The interpretation of a ##/##/#### date out-of-range for the preferred system can vary.

The third row shows your system's preference. Of rows 2 & 1, one will be compatible with that, and the other will be interpreted either as 2003-01-22 (non-preferred order), or as 2004-09-02 (overrrange accepted); and row 0 will probably give 2004-09-22 (overrange forced) - but behaviour is not guaranteed.

Interpretation of ####/##/##

It seems likely that new Date(St) will always correctly interpret as a date a string of the form "YYYY/MM/DD" (but not "YYYY-MM-DD"), provided that YYYY represents a number greater than 99.

MS IE 4, 6 & 7, Firefox 2 & 3, Opera 9, and Safari 3.1 all give "1234-05-06", as is proper.

There is a date validator in 4: Validation.

Maybe not in Safari 1.3.2 ... - see in Date and Time Troubles.

Time Input

Time input processing is less often needed; it is similar, but simpler. Use the 24-hour clock, and think about the upper limit to be allowed. Be aware of the possible significance of Time Zone and Summer Time.

There is a time validator in 4: Validation.

Code Formats

Take care that a date string such as "2000-09-17" or "17/09/2000" is indeed interpreted as a string, and not as an arithmetic expression (leading in those cases to 1974 or 0.00094).

When defining a date in code, remember that the field order in a string is locale-dependent, and that new Date(Y, M-1, D) and new Date("YYYY Mon DD") are much safer than new Date("DD/MM/YY"), which should never be used on the Web. But new Date("YYYY/MM/DD") seems safe, though new Date("YYYY-MM-DD") is at best unreliable.

To input a string in GMT/UTC with new Date(S), add " GMT" or " UTC" to it; or " Z".

Determining Local Input Format

The following should be safe in any reasonable system.

Input from ISO 8601

See also for XML, which is older text; and in 8: Enhancing the Object.

ISO 8601 Calendar Date formats are based on yyyy-mm-ddThh:mm:ss±oh:om, Ordinal Dates start yyyy-ddd and Week Dates start yyyy-Www-d instead; T W are literals. The Offset from GMT is + in the east and - in the west.

Similar RegExps can be used for Ordinal Date and for Week Date. It seems likely that no legitimate string will satisfy more than one of the three RegExps.

Simple ISO 8601

ISO 8601 8-Digit

Full AD Year Range, Y M D

This uses /\D+/ to be flexible about separators.

  Y M D    

Calendar Date, yyyy-mm-dd ...

Variations can be matched by a RegExp with optional fields. Consider for full Calendar Date

  ISO Calendar Date
  Partially tested
  GMT representation of Date Object
  Your local equivalent (LCT)

N.B. The code shows a conversion algorithm. It does not validate the format completely, and does not validate the field values at all; it will need to be adapted to its circumstances of use.

If the year is omitted, the code uses (19)77; other defaults should be added if they may be needed.

If the offset from GMT is omitted, then local date is implied; however, one must consider whether it is one's own local or the local of the data source. For non-own local, append offset fields.

function ISO_DT_to_JS_Date(ISO_DT) { // for new Date() argument
  return ISO_DT.replace(/^(....).(..).(.{11}).*$/, "$1/$2/$3") }
// Takes YYYY?MM?DD hh:mm:ss ignoring what follows
// For UTC, consider replacing $3 with $3Z or $3 UTC .

Ordinal Date, yyyy-ddd

For Ordinal Date, treat yyyy-ddd as YYYY Jan DDD and watch out for possible interpretation of, say, 044 as Octal.

  ISO Ordinal Date
  Partially tested
  GMT representation of Date Object
  Your local equivalent (LCT)

Week Date, yyyy-Www-d

For Week Date, process $1 $2 $3 as in Week Number Calculation, $4..$9 as above, and combine. Maybe convert YWD to a daycount DC from YMD, and use Y,M,D+DC.

Using ECMAScript 5th Edition

The 3rd Edition was finalised in 2000, and is routinely implemented. There will be no 4th Edition.

It was said that the 5th Edition would have partial support for input and output more-or-less like ISO 8601. That turns out to be somewhat exaggerated. The 5th Edition defines output support for a single UTC format suitable for use in JSON.

Some current browsers have some support.

BROWSERS
new Date(String)IE8FF3.6.8Op10.61Sf5.0Cr6.0THIS ONE, LCT
LCTLCTLCTLCTLCT
NaNGMTLCTNaNLCT
NaNNaNOKNaNOK
NaNNaNNaNNaNNaN
wrong dateNaNNaNNaNNaN
NaNNaNNaNNaNNaN
The first table row verifies correct testing of a safe date.
The test is only that the format is acceptable; not what the result is.
IE8 "2008-W25-7" : year 2008, month 25, date 7, "Zone" W ?

Input from XML/.NET

See also for ISO, which is newer text.

I have read that XML returns the format 2002-06-17T09:25:43.4670000+01:00 , which could mean (probably) 08:25 UTC, or 09:25 / 10:25 UTC. I've seen it described as "regular .NET format".

The following draft methods, which can be tested by pasting into eval (take and use a copy), assume that the format is exact except that the length of the fractional seconds may vary. Here k is constant, probably +1.

With, for example,

var In = "2002-06-17T09:25:43.4670000+01:00"

use A

var D = In.replace(/^(\d{4})-(\d{2})-(\d{2})T([0-9:]*)([.0-9]*)(.)(.*)$/,
  "$1/$2/$3 $4 GMT") // D = "2002/06/17 09:25:43 GMT"
D = Date.parse(D) + 1000*RegExp.$5 // add ms
var k = +1 // +1 or 0 or -1
D -= k * Date.parse("1970/01/01 "+RegExp.$7+" GMT") * (RegExp.$6+"1") // TZ
D = new Date(D) // Mon, 2002-06-17 08:25:43 UTC

or B (seemed incorrect in MSIE 4)

var D = In.replace(
  /^(\d{4})-(\d\d)-(\d\d)T([0-9:]*)([.0-9]*)(.)(\d\d):(\d\d)$/,
  "$1/$2/$3 $4 $6$7$8") // D = "2002/06/17 09:25:43 +0100"
D = Date.parse(D) // ??
D += 1000*RegExp.$5 // add ms
D = new Date(D) // Mon, 2002-06-17 07:25:43 UTC

or C (as below; seemed correct in MSIE 4)

They include no validation, which should be added for commercial use. They need thorough testing, especially away from the UK Time Zone. They can be compacted.

They did not all give me the same result in MSIE 4; Date.parse("... +0100") /* no GMT */ gave me an unexpected result (Offset).

  XML

Further

I have read :-

However, xml extensions have been developed that are being used by many bloggers; and they are known as the "Dublin Core".

Here is a Dublin Core date
  <dc:date>2004-05-25T01:37:59-08:00</dc:date>
and its defining xml schema.

That follows ISO 8601, and must represent about 38 minutes past one in the morning, local time, 8 hours away from GMT.

Input from HTML

HTML 5 includes new input control types date datetime datetime-local time week month.

This tests <input type=date> and others, which are browser-dependent. They accept and give strings in ISO 8601 YYYY-MM-DD format. So far, only Opera seems interesting and semi-usable.

Controltype=Result at onChange
date  
datetime
datetime-local
time
week
month
BrowserKnown typeShown asWorks properlyMy Result
MS IE 8 No type=textNoCopy
Firefox 3.6.10No type=textNoCopy
Opera 10.62 YesDrop Cal + up/downY *Derived
Safari 5.0.2 No type=textNoCopy
Chrome 6.0 Yestype=text + up/downNo ‡None

* Except week & month, which give no onChange. Up/down reverts to minutes.
‡ Up/down by 1 LSD only; useless.

Known draft HTML5 attributes, not necessarily all implemented, are type min max value.

See Datetime types by Olav Junker Kjær; and HTML 5: The Markup Language, a W3C Editor's Draft; and maybe via W3C's HTML5 / A vocabulary and associated APIs for HTML and XHTML.

See also my Date / Time Choosers, Calendar Weeks, Week Number Calculation.

Day, Month and Year Lengths

Note that it is not really necessary to determine whether a year is Leap, since the length of a month can be obtained without it. As usual, code involving 86400000 or the equivalent is liable to fail at certain times and places.

Day-Length

The UTC day can vary in length by a Leap Second, but JavaScript should know nothing of that.

The civil day can vary in length by an hour, because of Summer Time, which JavaScript understands. See in Date and Time Introduction, 2 : Demonstrations, 5 : Date and Time Elsewhere.

This calculates the difference in 24-hour days between civil dates a week apart, necessarily spanning each EU clock transition :-

Month-Length

From Date Object, etc.

Note that new Date(D) where D is a Date Object is not reliable for years before A.D. 100. If D is known to be a Date Object, use +D which will also often be quicker.

From Year and Month

Function LastOfMonth is by "rh" using CGjrs from below; see also in Date and Day Count.

  P4 3GHz XP sp2 IE6 : 3 seconds.
  P4 3GHz XP sp2 IE6 : 7 seconds.
  ms each of 9,     ...

Routines without Date Objects are much faster.

Opera Summer Time refers to related errors for years outside about 1968-2038.

Miscellaneous

February :-
		Y%4 != 0 ? 28 : Y%100 !=0 ? 29 : Y%400 != 0 ? 28 : 29
		28 + (y%4==0) ^ (y%100==0) ^ (y%400==0)
		28 + (!(y%4)) ^ (!(y%100)) ^ (!(y%400))
		28 | !(y%4)^!(y%100)^!(y%400)
Other Months :-
  m = 3..13	30 + ((3*m+1)%5 < 3)
  m = 1,3-12	30 | (m>>3^m)
All Months :-
  m = 0..11

Some of those I have yet to test.

Thirty-Day Months

For information on thirty-day months sometimes used in accounting, see in Date Miscellany II.

D2 :   D1 :  
EU :   US :   Intervals based on 30-day months ???

The EU version, but not the US, can be transformed into a straight difference of 30-day/month daycounts.

Check whether those are the genuine applicable rules.

Year-Length

These are intended for current Gregorian. For Proleptic Gregorian before AD 100, consider adding to y a multiple of 400, such as 4e4.

Leap Year

  P4 3GHz XP sp3 IE8 : 6 seconds.
 

Note how the routines using UTC are much faster than their non-UTC equivalents, and that routines without Objects are much faster than those with; except that Bsxt is amusingly inefficient.

Function LeapUgMm failed in Firefox 2 (3 is OK), TryLY showing ? - Date.UTC(Y, M, D) dislikes negative D.

A base-20 year number string can be tested by the Regular Expressions in the above functions Leap20 and leap20 :- /([^5AF]0|[48CG])$/i
/([48cg]|[^5af]0)$/

Days in Year

Or 365 + Number(Leap(y)) for that year.

Note that the difference in time between the beginnings of consecutive instances of YYYY-MM-DD for given MM-DD is usually exactly 365 or 366 days, but can often be greater or less by one hour (ignoring Leap Seconds, as JavaScript should). It can also be 1461 days, or even 2921 days, both probably exact.

The difference for some MM-DD HH-MM can be more complex.

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 and W3's Tidy.
This site, , is maintained by me.
Head.