See "About This JavaScript Site" in JavaScript Index and Introduction.
See "General Date/Time Introduction" in JavaScript Date and Time Introduction.
The page with DATE1 is superseded, abandoned, and removed.
There are deficiencies in the native JavaScript Date Object of ECMA-262 3rd Edition (2000-03-24) and ISO/IEC 16262 2nd Edition (2002-06-01). It lacks general direct support for reading and writing ISO 8601:2004 formats† and for European numeric date strings. It does not directly handle ISO Week Number or Ordinal Date. It converts years given as 0-99 to 1900-1999 or 2000-2099. The output of Date.toString is overly browser-dependent; and, in some browsers, it has parenthesized trailing rubbish.
One can add new methods and properties to the native Date Object, as in include3.js (this page does not use that file). Or one can write a completely new DATE Object, using the native Date Object only for access to the current date/time and the local Time Offset Rules; that means implementing the Gregorian Calendar arithmetically in JavaScript. Or, as here, following a suggestion by LRHN, one can write a new DATE Object, using an internal native Date Object but not directly exposing its methods and properties.
† The 5th Edition (no 4th) of ECMA-262 has very limited support for ISO 8601, apparently intended just for use in JSON.
Object DATE2 is intended principally to provide a set of date methods, without necessarily showing how a new object type should be implemented.
A DATE2 Object has a property Q which holds a native Date Object which holds the Object's value. There should be no need to access Q directly.
The code is reasonably modular, so it should be easy enough to comment out and remove any parts not required.
A DATE2 Object as here so far coded may not have all the "generic" features of built-in Object types.
Most code using Date objects can be converted to use DATE2 objects by just changing to the corresponding DATE2 methods, and using where convenient the additional methods and properties. Method toString now takes an optional format argument, and should provide all necessary output formatting.
For each of the UTC methods of the Date Object, each of which corresponds to a LCT (Local Civil Time) method, the DATE2 Object has X methods (even provided for seconds and milliseconds, in case it matters when setting across offset changes). They simply use the corresponding LCT or UTC Date methods, for example method getXDate uses either getDate or getUTCDate, depending on whether the static DATE2.GMT currently amounts to false or true. The same applies to toString(), which is aliased to toXString().
The same applies to new DATE2() when it is given a second argument which is not undefined or object (RegExp) - when numbers are given for year, month, and perhaps more.
Routines containing DATE2 Object methods can thus be switched between LCT and UTC merely by setting DATE2.GMT, and do not need to be written in two versions.
The original methods are not directly exposed, but are available as methods of the Q property.
Offsets should only be used in GMT mode.
Constructor new DATE2 is patterned on new Date, but
accepts many more string formats, directly or using a Pattern
String RegExp(?).
Also, DATE2 Object method getXEasterSunday and static methods DATE2.ifXisOK and DATE2.giveXEasterSunday can create a new DATE2 Object.
The DATE2 Object constructor and DATE2.parse accept ISO 8601 date field separators, and the Object can write in ISO formats with selectable date/time separator and optional Offset field, using Extended (with separators) or Basic (without separators) Format. ISO yyyy-mm-dd, yyyy-Www-d and yyyy-ddd are handled both for input and for output.
A simple Week Object {Y:yn, W:wn, D:dn} is used for function return to represent ISO 8601 week numbering.
The toString method of the native Date Object gives a browser-dependent and often inappropriate string, as shown :-
Results of Date.toString(), etc. :- MS IE 7 : Sat Mar 7 13:13:14 UTC 2009 MS IE 7 : Wed Jul 1 00:00:00 UTC+0100 2009 Firefox 3.0.7 : Sat Mar 07 2009 13:11:55 GMT+0000 (GMT Standard Time) Opera 9.27 : Sat, 07 Mar 2009 13:14:33 GMT+0000 Opera 9.64 : Sat Mar 07 2009 00:00:00 GMT+0000 Safari 3.2.2 : Sat Mar 07 2009 13:15:12 GMT+0000 (GMT Standard Time) Chrome 1 : Sat Mar 07 2009 13:16:02 GMT+0000 (GMT Standard Time) Netscape : Mon Sep 28 14:36:22 GMT-0700 (Pacific Daylight Time) 1998 Default results of DATE2.toString() :- Sat, 2009 Mar 07, 13:16:46 GMT+0000 // DATE2.GMT false Sat, 2009 Mar 07, 13:16:46 GMT // DATE2.GMT true N.B. Day and Month abbreviations can be altered
A new method toXString is provided. Its default result format is given by the current DATE2.Fmt string, and is fixed-length and browser-independent, with fields in a more logical order. Method toXString can be given a Format String argument.
The Format String is vaguely mnemonic and is interpreted letter by letter - note that XVC are each one letter before YWD - non-specific characters, including T, W and Z, are copied, and $ is the escape character. Like other X methods, it uses either local time with offset, or GMT, depending on global DATE2.GMT.
FORMAT STRING CHARACTERS $ Escape character; the next character is taken literally Y Year using at least four digits y Two-digit year (not for Y<0) M Two-digit month o Month as in array DATE2.Mnth, default "Jan" - "Dec" D Two-digit day-of-month d 1/2-digit day-of-month x Suffix 'st' 'nd' 'rd' 'th' for day-of-month O Three-digit Ordinal Date (day-of-year) a Day as in array DATE2.DoWk, default "Sun" - "Sat" h Two-digit hours, 00 - 23 p US hours, 1 - 12 P postfix a.m. or p.m. m Two-digit minutes, 00 - 59 s Two-digit seconds, 00 - 59 i Three-digit milliseconds, 000 - 999 S As for native Date.toString() G String "GMT" U String "UTC" F Offset as ±hh:mm f Offset as ±hhmm X Week-numbering year using at least four digits V Week-numbering two-digit week, 01 to 52 or 53 C Week-numbering one-digit day, 1 to 7 R Month as single character Ⅰ to Ⅻ r Month as single character ⅰ to ⅻ Any other character stands for itself.
N.B. DATE2.toXString() is aliased to DATE2.toString().
DATE2.parse and new DATE2 can read dates with British, Continental, or ISO date field separators. Numeric fields are not validated. For input of European D M Y string dates, a leading tilde transposes the first two one-or-two-digit numeric fields, so dealing with JavaScript's mm/dd/yyyy FFF habit. The Month can be a single-character Roman numeral (Ⅰ-Ⅻ ⅰ-ⅻ, \u2160-\u216B \u2170-\u217B; not necessarily constant-width).
Negative years, and years after 9999, should work throughout. The 12-hour clock is tolerated in some input.
In string input, if the beginning or whitespace is followed by two zeroes and two digits, the field is presumed to represent a year. The second zero is replaced by a four (adding 400 years), and the corresponding number of milliseconds is later subtracted. That is to enable use of four-digit year strings for dates in the first century A.D., and should do no collateral damage. A similar fix deals with negative years in strings.
Any string S which can be read by new Date(S) can certainly be read as the same value into a DATE2 Object by new DATE2(+new Date(S)). Any such string should be accepted by using new DATE2(S), perhaps as a better value.
For input with "foreign" alphabetic Months, define array DATE2.Mnth; each language needs a dummy entry before its January. CAVEAT: in date string input, my Opera 9.64 ignores any mis-spelt month, substituting the current month.
To what extent should date string input validate the exact compliance with a defined format? Input should be, generally, liberal; but is a good place to offer rigour. There are two aspects of validity - the pattern of digits and other characters, and the values of the numbers. Validation requires some knowledge of the pattern. The new Object supports both liberal and rigorous input.
For validated date string input, new DATE2(Str, Rgxp, Ordr) behaves as DATE2.ifXisOK(Str, Rgxp, Ordr) except that failure returns a DATE2 Object of value NaN.
A DATE2 Object has almost none of the exact method names particular to a Date Objects; but for each Date method there is an obviously-corresponding DATE2 method. DATE2 methods are indicated in List of Methods.
DATE2 has its own setTime, getTime, toString and valueOf methods.
The internal Date object can be accessed as the Q property, which it should not be necessary to use.
Range and values are as for the native Date Object, 1970-01-01.0 GMT ± 1e8 days. Easter, as imported, is limited to non-negative years; otherwise, everything should be full-range.
Static properties of DATE2 are created by function SetStaticDATE2 (a function is used only for convenient display on this page).
Given a complete ISO Basic Format, DATE2.enlargeISO(BF) returns an enlarged form of it, which new DATE2() and DATE2.parse() can read.
DATE2.ifXisOK(Str, Rgxp, Ordr) reads and validates a numeric string date (no time or offset) from Str by matching it to the RegExp Rgxp, using the matches in order given by string Ordr to provide arguments Y M D to new DATE2(,,), and checking the Month. Therefore, Rgxp should ensure that the date field is smaller than about 330. DATE2.ifXisOK returns an Object with a property Bad, and, if the value of that is zero, a property Objwhich is a new DATE2 Object. Non-zero indicates whether pattern, logic, or value failed validation.
DATE2.readPtrn(St, Ptrn) reads a numeric string date/time/offset from St by matching it to the pattern Ptrn, using the matches to assign digits to fields, returning a DATE2 Object. Unlisted characters are ignored (could change to must match???); fields default to zero.
DATE2.readPtrn Patterns Date Y year M month D date Time h hours m mins s secs f msecs Offset i sign h hours k mins Example 'YYYY-MM-dd hh:mm'
Here, the additional Date Object methods of include3.js are not included. Two utility routines (LZ ToNd) from include1.js are used. Once the Object is debugged, LZ can be simplified or implemented with ToNd.
In general, the code is being optimised for minimum lexical repetition rather than for speed.
The set & inc routines all return this, so they can be chained.
In the expanded representation of a date, which can handle years outside 0000 to 9999, ISO 8601 requires either a plus or a minus before the year. That probably needs to be added for output here.
2009-10-01 : Name expandISO changed to enlargeISO to avoid possible confusion with the meaning of "expand" in ISO 8601.
During development, the code has been tested intermittently in Firefox, MS IE, Opera, Safari, Chrome, using Windows XP sp3.
A superior tester, but without DATE2, is at JavaScript/HTML/VBS Quick Trials.
The first control requires four fields - two optionally-signed year numbers, one unsigned number, and a character y m or d.
CONSTRUCTOR : new DATE2() Arguments as for new Date() OBJECT METHODS : Unlike for the Date object : toString() Now as Wed, 2009 Mar 04, 16:19:29 GMT+0000 toString(Fmt) Default Fmt = DATE2.Fmt : see DATE2.GMT Like for the Date object : valueOf() Still gives milliseconds from epoch. getTime() 〃 setTime() Still sets milliseconds from epoch. toLocalString() As for Date.toLocaleString New : toXString() Alias of toString() toXString(Fmt) getTimeOffset() As Date.getTimezoneOffset() getXPartYear() Two-digit string, LCT or GMT, year % 100 setXPartYear() Preserves Y/100|0 getXFullYear() As with Date, but LCT or GMT setXFullYear(Y4, M, D) 〃 getXMonth() 〃 setXMonth(M, D) 〃 getXDate() 〃 setXDate(D) 〃 getXHours() 〃 setXHours(h, m, s, ms) 〃 getXMinutes() 〃 setXMinutes(m, s, ms) 〃 getXSeconds() 〃 setXSeconds(s, ms) 〃 getXMilliseconds() 〃 setXMilliseconds(ms) 〃 getXDay() 〃 setXDay(d) if d in 0-6, same week 0-6 getMJD() MJD 0.0 = +1858-11-17 00:00:00 GMT, Wed setMJD(MJD) Use MJD with DATE2.GMT true getCJD() CJD 0.0 = -4713-11-24 00:00:00 LCT, Mon setCJD(CJD) Use CJD with DATE2.GMT false getXPosInMonth() Return 1-5 for 1st-5th Thisday of month setXPosInMonth(K, D) Set K'th D-day of month; 5 = last getXDayOfYear() Get Ordinal Date 1..366 setXDayOfYear() Set Ordinal Date getXDayCount() 1970-01-01 = 0 setXDayCount() 〃 toISO8601Xofst(BF) BF = Basic Format e.g. date YYYYMMDD toISO8601Xtime(BF) toISO8601Xdate(GOW, BF) GOW = Greg, Ord, Week toISO8601XYWDstr(BF) yyyy-Www-d toISO8601Xstr(T, GOW, ofs) T = Separator & BF, ofs = offset getISO8601XDay() Mon=1 to Sun=7 setISO8601XDay(d) 1-7, same ISO Week; but d unbounded getISO8601XYWD() {Y:y,W:w,D:d} setISO8601XYWD({Y:y,W:w,D:d}) Y W D all required incXFullYear(dY, dM, dD) Consider moving into a short month incXMonth(dM, dD) incXDate(dD) getXEasterSunday() Return new Object, same Y, new M D setXEasterSunday() Same Y, new M D STATIC METHODS : Like for the Date object : DATE2.now() Return current instant, ms from Epoch DATE2.UTC(...) Similar to Date.UTC(...), but YY OK DATE2.parse(String) Similar to Date.parse(String), 〃 Unlike for the Date object : DATE2.enlargeISO(String) Return expansion of ISO Basic formats DATE2.countDown(ms) Return { ± D h m s } DATE2.giveXEasterSunday(YR) Return DATE2 Object, if Easter available DATE2.ifXisOK(Str, Rgxp, Ordr) Return {Bad:#[, Obj:DATE2]} DATE2.readPtrn(St, Ptrn) Return DATE2 Object; Ptrn as "DD MM YYYY" STATIC PROPERTIES : DATE2.GMT Controls X methods : true is GMT/UTC DATE2.DoWk Array(8) ["Sun","Mon", ..., "Sun"] DATE2.Mnth Array(13n) ['***','Jan', ..., 'Dez'] DATE2.Fmt Default "a, Y o D, h:m:s Gf"; else Y=YYYY y=YY M=MM o='Mth' D=DD d=D+ x O=DDD a='Day', X=YNum V=WN C=D; R r months in Roman (single-character); h=hh m=mm s=ss i=m/s; F=off:set f=offset ; S = Date default ; $ = escape.
Get Longitude, Season, Hemisphere; get clock change dates, code. Increment time.
Check whether consistency in format string letters can be improved.
UTC work is faster than LCT work; LCT should be used only when needed. That could be encouraged by making the default value of DATE2.GMT true.
Determining any of year, month, date requires work largely sufficient to determine the other two; and commonly all three are needed together. Therefore, where practical, results should be more-or-less cached. The same applies to year, week-number, day - method toXString caches, to a limited extent, Y W D.
Consider function return of object types for {Y M D} {Y O} {Y W D} {h m s ms}.