See "About This JavaScript Site" in JavaScript Index and Introduction.
See "General Date/Time Introduction" in JavaScript Date and Time Introduction.
My JavaScript RegExps & Validation deals with data validation in general, and indicates an efficient way of coding it.
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.
The year should be 4-digit, but may be 2-digit. There are three basic styles, implemented 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.
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.
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 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 :-
The following should read a 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.
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.
Row 3 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.
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, 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 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.
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' .
I believe that new Date("27/12/2004").getDay() returns 1 if interpreted as the UK date format and 0 if as the US one. There are other such dates, and dates giving the reverse. The code presumes that there are no other possibilities for "##/##/####". Testing with December 32nd 1969 GMT seems better.
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.
Variations can be matched by a RegExp with optional fields. Consider for full Calendar Date
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 .
For Ordinal Date, treat yyyy-ddd as YYYY Jan DDD and watch out for possible interpretation of, say, 044 as Octal.
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.
4th Edition should have partial support for ISO 8601 input and output.
Opera 9.27 understands the all-numeric forms; misunderstands the T separator, and gives NaN for the W form. Firefox 2.0.0.13 and Safari 3.1 give "Invalid Date" throughout. IE 7 gives NaN except for the W form, which it misunderstands.
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).
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.
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.
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 :-
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.
Function LastOfMonth is by "rh" using CGjrs from below; see also in Date and Day Count.
Routines without Date Objects are much faster.
Opera 9.21 to 9.25 used to fail in TestMonths at 2038; Opera Summer Time refers.
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.
For information on thirty-day months sometimes used in accounting, see in Date Miscellany II.
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.
These are intended for current Gregorian. For Proleptic Gregorian before AD 100, consider adding to y a multiple of 400, such as 4e4.
Note how the routines using UTC is much faster than their non-UTC equivalents, and that routines without Date Objects are much faster than those with; except that Bsxt is amusingly inefficient.
Function LeapUgMm fails in Firefox 2.0.0.3 - 2.0.0.13, showing ? - Date.UTC(Y, M, D) dislikes negative D.
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.