ECMAScript Date
In ECMAScript, the Date object is the built-in mechanism for handling dates and times. At its core, a Date instance does not store a complex set of calendar fields; instead, it maintains a single numeric value: the time value. This value represents the number of milliseconds that have elapsed since the Unix Epoch—1970-01-01T00:00:00Z.
This internal timestamp can be positive or negative, allowing the Date object to represent dates far into the past or future (approximately $\pm 100,000,000$ days relative to the epoch). If a date is created with a value outside this range or if a string fails to parse, the instance becomes an Invalid Date, and its internal time value is set to NaN.
An important distinction in usage is that Date can be invoked both as a constructor and as a regular function. When called with new Date(), it returns a Date object. When called as a function—Date()—it returns a human-readable string representing the current time, regardless of any arguments passed to it.
Creating Date Instances
There are several ways to instantiate a Date object, depending on the available data:
// 1. Current time and date
const now = new Date();
// 2. From a millisecond timestamp
const fromTimestamp = new Date(1705307400000);
// 3. From an ISO 8601 string
const fromString = new Date("2024-01-15T08:30:00.000Z");
// 4. From date components (Local Time)
// Note: Months are 0-indexed (0 = January, 11 = December)
const fromParts = new Date(2024, 0, 15, 8, 30, 0, 0);
// 5. From date components (UTC Time)
const fromUtcParts = new Date(Date.UTC(2024, 0, 15, 8, 30, 0, 0));
Critical Implementation Details
When working with the Date constructor, developers should be aware of a few specific behaviors:
- Zero-Indexed Months: The
monthIndexargument starts at0. Passing0results in January, while11results in December. - Two-Digit Years: If the year provided is between
0and99, JavaScript automatically maps it to the range1900–1999. To specify a year like0024 AD, you must usesetFullYear(). - Local vs. UTC: When using the
(year, month, ...)signature, the inputs are interpreted according to the user's local system timezone.
Timestamps and UTC Methods
For many applications, working with raw timestamps is more efficient than manipulating date objects. Date.now() is a static method that returns the current time in milliseconds without the overhead of creating a new object.
Similarly, Date.UTC() allows you to calculate a timestamp based on UTC components without instantiating a Date object immediately.
Date.now(); // e.g., 1705307400000
Date.UTC(2024, 0, 15, 8, 30); // 1705307400000
const d = new Date(Date.UTC(2024, 0, 15, 8, 30));
console.log(d.getTime()); // 1705307400000
console.log(d.valueOf()); // 1705307400000 (identical to getTime())
It is vital to remember that Date instances do not store timezone information. They store a UTC timestamp. The timezone is only applied when you use "local" methods to read or write the date.
Reading and Modifying Date Components
The Date API provides two parallel sets of methods: one for the local timezone and one for UTC. Because Date objects are mutable, setter methods modify the original instance.
Getters and Setters
Common methods include:
- Year:
getFullYear()/setFullYear()$\leftrightarrow$getUTCFullYear()/setUTCFullYear() - Month:
getMonth()/setMonth()$\leftrightarrow$getUTCMonth()/setUTCMonth() - Date:
getDate()/setDate()$\leftrightarrow$getUTCDate()/setUTCDate() - Day of Week:
getDay()/getUTCDay()$\leftrightarrow$getUTCDay()(No setter for day of week) - Time:
getHours(),getMinutes(),getSeconds(),getMilliseconds()(and their UTC counterparts).
Automatic Rollover
One powerful (and sometimes surprising) feature of Date is automatic rollover. If you set a component to a value outside its normal range, JavaScript adjusts the other components accordingly.
const d = new Date(2024, 0, 31); // January 31, 2024
d.setMonth(1); // Set to February.
// Since Feb 31 doesn't exist, it rolls over to March 2nd or 3rd.
Similarly, setting the date to 0 will move the object back to the last day of the previous month.
Timezone Offsets
To determine the difference between the local time and UTC, use getTimezoneOffset(). This returns the difference in minutes. For example, in a UTC+8 timezone, this method typically returns -480.
Parsing and Formatting
Parsing Strings
Date.parse() converts a date string into a millisecond timestamp. While many formats are supported across different browsers, the ISO 8601 format is the only one guaranteed by the ECMAScript specification to be parsed consistently.
Important Parsing Nuance:
- A date-only ISO string (e.g.,
"2024-01-01") is treated as UTC. - A date-time string without a specified timezone (e.g.,
"2024-01-01T00:00:00") is treated as local time.
Formatting Output
Depending on the required output, Date provides several formatting methods:
toISOString(): Returns a string in the simplified ISO 8601 format (always UTC).toJSON(): Used byJSON.stringify(); typically returns the same result astoISOString().toString(): Returns a full string representation in the local timezone.toLocaleString(),toLocaleDateString(), andtoLocaleTimeString(): Returns strings formatted according to the user's locale and language settings.
const d = new Date("2024-01-01");
console.log(d.toISOString()); // "2024-01-01T00:00:00.000Z"
console.log(d.toString()); // Localized string (e.g., "Wed Jan 01 2024 ...")