Date
)
This chapter describes JavaScript’s API for working with dates – the class Date
.
Date
The JavaScript Date
API is cumbersome to use. Hence, it’s best to rely on a library for anything related to dates. Popular libraries include:
Date
objects (for simpler use cases):
Intl
API is supported by most JavaScript platforms: Intl.DateTimeFormat
provides language-sensitive date and time formatting.
Additionally, TC39 is working on a new date API for JavaScript: Temporal.
Two things are important to keep in mind:
Tree-shaking can considerably reduce the size of a library. It is a technique of only deploying those exports of a library to a web server that are imported somewhere. Functions are much more amenable to tree-shaking than classes.
Support for time zones: As explained later, Date
does not support time zones, which introduces a number of pitfalls and is a key weakness. Make sure that your date library supports them.
UTC, Z, and GMT are ways of specifying time that are similar, but subtly different:
UTC (Coordinated Universal Time) is the time standard that all times zones are based on. They are specified relative to it. That is, no country or territory has UTC as its local time zone.
Z (Zulu Time Zone) is a military time zone that is often used in aviation and the military as another name for UTC+0.
GMT (Greenwich Mean Time) is a time zone used in some European and African countries. It is UTC plus zero hours and therefore has the same time as UTC.
Sources:
Dates support the following time standards:
Depending on the operation, only some of those options are available. For example, when converting dates to strings or extracting time units such as the day of the month, you can only choose between the local time zone and UTC.
Internally, Dates are stored as UTC. When converting from or to the local time zone, the necessary offsets are determined via the date. In the following example, the local time zone is Europe/Paris:
// CEST (Central European Summer Time)
assert.equal(
new Date('2122-06-29').getTimezoneOffset(), -120);
// CET (Central European Time)
assert.equal(
new Date('2122-12-29').getTimezoneOffset(), -60);
Whenever you create or convert dates, you need to be mindful of the time standard being used – for example: new Date()
uses the local time zone while .toISOString()
uses UTC.
> new Date(2077, 0, 27).toISOString()
'2077-01-26T23:00:00.000Z'
Dates interpret 0 as January. The day of the month is 27 in the local time zone, but 26 in UTC.
Documenting the time standards supported by each operation
In the remainder of this chapter, the supported time standards are noted for each operation.
Not being able to specify time zones has two downsides:
It makes it impossible to support multiple time zones.
It can lead to location-specific bugs. For example, the previous example produces different results depending on where it is executed. To be safe:
Z
or a time offset when parsing strings (see the next section for more information).
Date time formats describe:
Date.parse()
new Date()
Date.prototype.toISOString()
The following is an example of a date time string returned by .toISOString()
:
'2033-05-28T15:59:59.123Z'
Date time formats have the following structures:
Date formats: Y=year; M=month; D=day
YYYY-MM-DD
YYYY-MM
YYYY
Time formats: T=separator (the string 'T'
); H=hour; m=minute; s=second and millisecond; Z=Zulu Time Zone (the string 'Z'
)
THH:mm:ss.sss
THH:mm:ss.sssZ
THH:mm:ss
THH:mm:ssZ
THH:mm
THH:mmZ
Date time formats: are date formats followed by time formats.
YYYY-MM-DDTHH:mm:ss.sssZ
Instead of Z
(which is UTC+0), we can also specify time offsets relative to UTC:
THH:mm+HH:mm
(etc.)
THH:mm-HH:mm
(etc.)
Z
to make date parsing deterministicIf you add a Z
to the end of a string, date parsing doesn’t produce different results at different locations:
Without Z
: Input is January 27 (in the Europe/Paris time zone), output is January 26 (in UTC).
> new Date('2077-01-27T00:00').toISOString()
'2077-01-26T23:00:00.000Z'
With Z
: Input is January 27, output is January 27.
> new Date('2077-01-27T00:00Z').toISOString()
'2077-01-27T00:00:00.000Z'
A time value represents a date via the number of milliseconds since 1 January 1970 00:00:00 UTC.
Time values can be used to create Dates:
const timeValue = 0;
assert.equal(
new Date(timeValue).toISOString(),
'1970-01-01T00:00:00.000Z');
Coercing a Date to a number returns its time value:
> Number(new Date(123))
123
Ordering operators coerce their operands to numbers. Therefore, you can use these operators to compare Dates:
assert.equal(
new Date('1972-05-03') < new Date('2001-12-23'), true);
// Internally:
assert.equal(73699200000 < 1009065600000, true);
The following methods create time values:
Date.now(): number
(UTC)
Returns the current time as a time value.
Date.parse(dateTimeStr: string): number
(local time zone, UTC, time offset)
Parses dateTimeStr
and returns the corresponding time value.
Date.UTC(year, month, date?, hours?, minutes?, seconds?, milliseconds?): number
(UTC)
Returns the time value for the specified UTC date time.
Date.prototype.getTime(): number
(UTC)
Returns the time value corresponding to the Date.
Date.prototype.setTime(timeValue)
(UTC)
Sets this
to the date encoded by timeValue
.
new Date(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, milliseconds?: number)
(local time zone)
Two of the parameters have pitfalls:
For month
, 0 is January, 1 is February, etc.
If 0 ≤ year
≤ 99, then 1900 is added:
> new Date(12, 1, 22, 19, 11).getFullYear()
1912
That’s why, elsewhere in this chapter, we avoid the time unit year
and always use fullYear
. But in this case, we have no choice.
Example:
> new Date(2077,0,27, 21,49).toISOString() // CET (UTC+1)
'2077-01-27T20:49:00.000Z'
Note that the input hours (21) are different from the output hours (20). The former refer to the local time zone, the latter to UTC.
new Date(dateTimeStr: string)
(local time zone, UTC, time offset)
If there is a Z
at the end, UTC is used:
> new Date('2077-01-27T00:00Z').toISOString()
'2077-01-27T00:00:00.000Z'
If there is no Z
or time offset at the end, the local time zone is used:
> new Date('2077-01-27T00:00').toISOString() // CET (UTC+1)
'2077-01-26T23:00:00.000Z'
If a string only contains a date, it is interpreted as UTC:
> new Date('2077-01-27').toISOString()
'2077-01-27T00:00:00.000Z'
new Date(timeValue: number)
(UTC)
> new Date(0).toISOString()
'1970-01-01T00:00:00.000Z'
new Date()
(UTC)
The same as new Date(Date.now())
.
Dates have getters and setters for time units – for example:
Date.prototype.getFullYear()
Date.prototype.setFullYear(num)
These getters and setters conform to the following patterns:
Date.prototype.get«Unit»()
Date.prototype.set«Unit»(num)
Date.prototype.getUTC«Unit»()
Date.prototype.setUTC«Unit»(num)
These are the time units that are supported:
FullYear
Month
: month (0–11). Pitfall: 0 is January, etc.
Date
: day of the month (1–31)
Day
(getter only): day of the week (0–6, 0 is Sunday)
Hours
: hour (0–23)
Minutes
: minutes (0–59)
Seconds
: seconds (0–59)
Milliseconds
: milliseconds (0–999)
There is one more getter that doesn’t conform to the previously mentioned patterns:
Date.prototype.getTimezoneOffset()
Returns the time difference between local time zone and UTC in minutes. For example, for Europe/Paris, it returns -120
(CEST, Central European Summer Time) or -60
(CET, Central European Time):
> new Date('2122-06-29').getTimezoneOffset()
-120
> new Date('2122-12-29').getTimezoneOffset()
-60
Example Date:
const d = new Date(0);
Date.prototype.toTimeString()
(local time zone)
> d.toTimeString()
'01:00:00 GMT+0100 (Central European Standard Time)'
Date.prototype.toDateString()
(local time zone)
> d.toDateString()
'Thu Jan 01 1970'
Date.prototype.toString()
(local time zone)
> d.toString()
'Thu Jan 01 1970 01:00:00 GMT+0100 (Central European Standard Time)'
Date.prototype.toUTCString()
(UTC)
> d.toUTCString()
'Thu, 01 Jan 1970 00:00:00 GMT'
Date.prototype.toISOString()
(UTC)
> d.toISOString()
'1970-01-01T00:00:00.000Z'
The following three methods are not really part of ECMAScript, but rather of the ECMAScript internationalization API. That API has much functionality for formatting dates (including support for time zones), but not for parsing them.
Date.prototype.toLocaleTimeString()
Date.prototype.toLocaleDateString()
Date.prototype.toLocaleString()
Exercise: Creating a date string
exercises/dates/create_date_string_test.mjs