Date, JavaScript’s current Date and time API is notoriously difficult to use. The ECMAScript proposal “Temporal “is a new and better date-time API currently in its third phase. It is produced by Philipp Dunkel,Maggie Johnson-Pint,Matt Johnson-Pint,Brian Terlson,Shane Carr,Ujjwal Sharma,Philip Chimento,Jason Williams andJustin Grant.

This post has two goals.

  • Give you a sense of how Temporal works
  • To help you get started

However, this is not an exhaustive document. For many details, you have to consult the (good) documentation of Temporal.

Warning. These are my first explorations of the API — feedback is welcome!


Directory.


Temporal API

The date-time API for Temporal can be accessed through the global variable Temporal. It is very pleasant to use.

  • All objects are immutable. Changing them produces new values, similar to how strings work in JavaScript.
  • It supports time zones and non-Gregorian calendars.
  • There are several classes dedicated to time values (date-time values with time zones, date-time values without time zones, date-time values without time zones, and so on). This has several benefits.
    • The context of a value (whether it is sometimes bounded, etc.) is easier to understand.
    • How to achieve a given task is often more obvious.
    • .toString(), can be used with much less consideration.
  • January is the first month.

Part of this blog post.

  • This article begins with background information. This will help you finish the rest of the article, but you should be ok without reading it.
  • Next, an overview of all the classes of the Temporal API and how they fit together.
  • At the end, there is a comprehensive section that contains the instance.

From solar time to standard time

Historically, the way we measure time has improved over the past few years.

  • Apparent solar time (local apparent time). One of the earliest ways to measure time was to determine the current time from the position of the sun. For example, noon is when the sun is directly above it.
  • Mean solar time (local mean time). This time representation corrects for variations in apparent solar time so that every day of the year has the same length.
  • Standard time and time zone. Standard time regulates how clocks in a geographical area are synchronized. It was established in the 19th century to support weather forecasting and train travel. In the 20th century, standard time was defined as global, with geographical areas becoming _ time zones _.

Wall clock _ time _ is the current time in a time zone (as indicated by the clock on the wall). Wall clock time is also known as _ local time _.

Time standard. UTC vs. Z vs. GMT

UTC, Z, and GMT are similar but slightly different ways of specifying time.

  • UTC (Coordinated Universal Time) is the time standard on which all time zones are based. They are specified relative to it. That is, no country or region uses UTC as its local time zone.

  • Z (Zulu Time Zone) is a military time zone, often used in aviation and military Settings, and is another name for UTC+0.

  • GMT (Greenwich Mean Time) is the time zone used in some European and African countries. It is UTC plus zero, so it has the same time as UTC.

Source.

Temporal time zone is based on IANA time zone database (TZ database for short). IANA stands for Internet Assigned Numbers Authority. In this database, each time zone has an identifier and rules that define the offset of UTC time. If a time zone has standard time and daylight saving time, the offset will change throughout the year.

In standard time, the time offset for the America/Los_Angeles time zone is -8:00 (line A). During DAYLIGHT saving time, the time offset is -7:00 (line B).

These are two good lists of time zone names.

The calendar

The calendars supported by Temporal are based on the standard Unicode Universal Encoding Common Geographic Data Repository (CLDR) — among other things.

  • buddhist: Thai Buddhist calendar
  • chinese: Traditional Chinese calendar
  • coptic: Coptic calendar
  • dangi: Traditional Korean calendar
  • ethiopic: Ethiopian calendar, Amete Mihret (c. 8th century AD).
  • gregory: Gregorian calendar
  • hebrew: Traditional Hebrew calendar
  • indian: Hindu calendar
  • islamic: Islamic calendar
  • iso8601: ISO calendar (Gregorian calendar using ISO 8601 calendar week rules).
  • japaneseImperial Calendar of Japan
  • persian: Persian calendar
  • roc: Republic of China calendar

Iso8601 used by most western countries, and get extra support, in the Temporal method includes: Temporal. Now the zonedDateTimeISO () returns the system time zone and ISO – 8601 calendar of the current date and time bracket clock).

ECMAScript Extension ISO-8601/RFC 3339 The character string is a character string

The standards ISO-8601 and RFC 3339 specify how to represent dates as strings. Currently, they lack the functionality that Temporal needs and adds.

  • Represents month-day data as a string
  • Represents the IANA time zone name in a date-time string
  • Represents a calendar system in a date-time string

Our goal is to eventually standardize these additions (beyond ECMAScript).

Month – Japanese method

Moon – The Japanese method looks something like this.

> Temporal.PlainMonthDay.from('12-24').toString()
'12-24'
Copy the code

Date and time string with IANA time zone name and calendar system

The following code shows what a complete date and time string looks like. In practice, many of these parts are often left out.

const zdt = Temporal.ZonedDateTime.from({ timeZone: 'Africa/Nairobi', year: 2019, month: 11, day: 30, hour: 8, minute: 55, second: 0, millisecond: 123, microsecond: 456, nanosecond: 789, }); assert.equal( zdt.toString({calendarName: 'always', smallestUnit: 'nanosecond'}), 'the 2019-11-30 T08:55:00. 123456789 + 03:00 Africa/list/u - ca = iso8601');Copy the code

Part of the date and time string from the previous example.

  • The date.'2019-11-30'
  • The separator between the date and time.'T'
  • Time.'08:55:00. 123456789'
    • hours':'minutes':'
    • '. '(The delimiter between seconds and fractions of seconds
    • Ms (3 digits)
    • Microseconds (3 digits)
    • Nanosecond (3 digits)
  • Time offset relative to UTC.'+ 03:00'
    • Alternatives:'Z', which means'+ 0:00'
  • Time zone.'[Africa/Nairobi]'
  • A calendar.'[u-ca=iso8601]'

The last two items were not standardized.

Overview of the Temporal API

This section gives an overview of the time API classes. They can all be global variable Temporal (Temporal. Instant, Temporal ZonedDateTime, etc.) to access.

Examples of their use are given later in this section.

Temporal distinguishes between two kinds of time. Given a global moment in time.

  • Wall clock time(also called _ local time _ or _ clock time _) varies globally, depending on the time zone of a clock.
  • Precise time(also called _UTC time _) is the same everywhere.

Epoch time _ is a way of indicating the exact time. It is a number that counts units of time (such as nanoseconds) before or after the _Unix era (midnight UTC, January 1, 1970).

All date and/or time classes in Temporal support two direct creation approaches.

On the one hand, the constructor accepts the minimum amount of data required to fully specify a date-time value. For example, in two classes that are precise in time, Instant and ZonedDateTime, the time itself is specified by epoch nanosecond.

const epochNanoseconds = 6046783259163000000n; const timeZone = 'America/Mexico_City'; const zdt1 = new Temporal.ZonedDateTime(epochNanoseconds, timeZone); Assert. Equal (zdt1. ToString (), 'the 2161-08-12 T17:00:59. 163-05:00 America/Mexico_City');Copy the code

Static factory method. From () is overloaded. Most classes support three values for their arguments.

First, if the argument is an instance of the same class, that instance is cloned.

const zdt2 = Temporal.ZonedDateTime.from(zdt1); Assert. Equal (zdt2. ToString (), 'the 2161-08-12 T17:00:59. 163-05:00 America/Mexico_City');Copy the code

Second, all other objects are interpreted to specify various fields with time-dependent information.

const zdt3 = Temporal.ZonedDateTime.from({ timeZone: 'America/Mexico_City', year: 2161, month: 8, day: 12, hour: 17, minute: 0, second: 59, millisecond: 163, microsecond: 0, nanosecond: 0, }); Assert. Equal (zdt3. ToString (), 'the 2161-08-12 T17:00:59. 163-05:00 America/Mexico_City');Copy the code

Third, all raw values are coerced into strings and parsed.

Note that we do not need to specify the offset on line A, but the offset is displayed on line B.

The following table gives an overview of the date-time class.

Temporal.* Cal region
ZonedDateTime
← era, Region, Cal?
Instant (✓)
Please sinian
PlainDateTime
← Y, M, D, h? , m? , s? , ms? , mu s? , ns? , cal?
PlainDate
← Y, M, D, cal?
PlainTime
Please h? , m? , s? , ms? , mu s?
PlainYearMonth
Please Y, M, CAL? , refIsoDay?
PlainMonthDay
Please M, D, CAL? , refIsoYear?

By illustrations.

  • CAL: calendar
  • Zone: the zone
  • Epoch: epoch nanoseconds
  • Y, M, D: ISO Year, month, and day
  • H, m, S :ISO Hour, minute, second
  • Ms, μs, ns:ISO milliseconds, microseconds, nanoseconds
  • RefIsoDay: Reference to ISO day, used for disambiguating dates other than those using the ISO8601 calendar.
  • RefIsoYear: Reference to the ISO year, used for disambiguation when using a calendar other than the ISO 8601 calendar.
  • InstantInternally, a calendar is used, but this calendar cannot be configured with the constructor argument.

A name.

  • ZonedRepresents an explicitly specified time zone
  • PlainRepresents a value with no associated time zone (abstract time).

Object Temporal. Now, there are several factory methods used to create a Temporal value that represents the current time.

> Temporal. Now. Instant (), toString () 'the 2021-06-27 T12:51:10. 961 z' > Temporal. Now. ZonedDateTimeISO (' Asia/Shanghai). The toString () 'the 2021-06-27 T20:51:10) 961 + 08:00 Asia/Shanghai' > Temporal. Now. PlainDateTimeISO (), toString () 'the 2021-06-27 T20:51:10. 961' > Temporal. Now the plainTimeISO (). The toString () '20:51:10. 961'Copy the code

System-provided context: time zone and calendar

We can use Temporal. Now to access the system’s current time zone. This time zone can be changed — for example, when the system travels.

> Temporal.now.timeZone().toString()
'Asia/Shanghai'
Copy the code

Accessing the current calendar is more complicated.

const sysCal = new Intl.DateTimeFormat().resolvedOptions().calendar;
Copy the code

Temporal means the exact time in three ways.

  • Through the classInstant(UTC time).
  • Through the classZonedDateTimeWall clock time plus a time zone and a calendar.
  • By a large int expressing the number of nanoseconds since the epoch.

classInstant

Class Instant represents global precise time. It uses UTC as its “time zone”. Its calendar is always ISO8601.

Use this class to represent internal dates (timestamps in logs, and so on) that are not displayed to the end user.

const instant = Temporal.now.instant(); Assert. Equal (instant. The toString (), 'the 2021-06-27 T08: blot him. 18174345 z');Copy the code

The ZonedDateTime class represents time by wall clock time plus a time zone and a calendar.

Usage of this class.

  • Represents the actual event
  • Convert the time of different regions
  • Calculate when daylight saving time is likely to kick in (” one hour later “).

If a class has no time zone, Temporal calls it “normal”. There are three classes without time zones: PlainDateTime,PlainDate, and PlainTime. They are abstract representations of time.

Use cases for these classes.

  • Displays wall clock time for a specific time zone (see below).
  • When the time zone is not important, time is calculated (” first Wednesday in May 1998 “).

classPlainYearMonth

An instance of PlainYearMonth refers abstractly to a month of a year.

Use cases.

  • Identify a monthly recurring event (” October 2020 meeting “).
const plainYearMonth = Temporal.PlainYearMonth.from(
  {year: 2020, month: 10});
assert.equal(
  plainYearMonth.toString(),
  '2020-10');
Copy the code

classPlainMonthDay

An instance of PlainMonthDay refers abstractly to a day of a month.

Use cases.

  • Identify an event that repeats annually (” Bastille Day is July 14 “).

Helper classes

Calendar

All time classes that contain a full date use a calendar to help them with various calculations. Most of the code uses an ISO 8601 calendar, but other calendar systems are also supported.

These are three common ways to specify a calendar.

const pd1 = new Temporal.PlainDate(1992, 2, 24,
  'iso8601');
const pd2 = new Temporal.PlainDate(1992, 2, 24,
  {calendar: 'iso8601'});
const pd3 = new Temporal.PlainDate(1992, 2, 24,
  new Temporal.Calendar('iso8601'));
Copy the code

An instance of TimeZone represents the TimeZone. They support IANA time zones, UTC, and UTC offsets. For most usage, IANA time zones are the best choice because they handle DAYLIGHT saving time correctly.

These are three common ways to specify a time zone.

const zdt1 = new Temporal.ZonedDateTime(0n,
  'America/Lima');
const zdt2 = new Temporal.ZonedDateTime(0n,
  {timeZone: 'America/Lima'});
const zdt3 = new Temporal.ZonedDateTime(0n,
  new Temporal.TimeZone('America/Lima'));
Copy the code

Duration

Duration represents a length of time — for example, 3 hours and 45 minutes.

Duration is used for time calculation.

  • Measure the difference between two time values
  • Adds time to a time value
  • And so on.
const duration = Temporal.Duration.from({hours: 3, minutes: 45});
assert.equal(
  duration.total({unit: 'second'}),
  13500);
Copy the code

Note that there is no simple standardization for the duration.

  • Sometimes we mean “90 minutes “.
  • Sometimes, we mean “1 hour and 30 minutes “.

The former should not be automatically converted to the latter.

example

Input and output

Convert from string to string

Static factory methods. From () always accept strings.

const zdt = Temporal.ZonedDateTime.from(
  '2019-12-01T12:00:00[Pacific/Auckland]');
Copy the code

The.tostring () method works predictably and can be configured.

assert.equal(
  zdt.toString(),
  '2019-12-01T12:00:00+13:00[Pacific/Auckland]');

assert.equal(
  zdt.toString({offset: 'never', timeZoneName: 'never'}),
  '2019-12-01T12:00:00');

assert.equal(
  zdt.toString({smallestUnit: 'minute'}),
  '2019-12-01T12:00+13:00[Pacific/Auckland]');
Copy the code

However,.tostring () does not let you hide minutes in this case — if you want to do so, you must convert ZonedDateTime to PlainDate.

assert.equal(
  zdt.toPlainDate().toString(),
  '2019-12-01');
Copy the code

Convert to AND from JSON

All Temporal date-time values have a.tojson () method, so they can be stringed as JSON.

If you want to parse JSON with date-time values, you need to set up a JSON Reviver.

Convert to a human-readable string

Temporal supports converting date-time values to human-readable strings, similar to Intl.dateTimeFormat’s.

const zdt = Temporal.ZonedDateTime.from( '2019-12-01T12:00[Europe/Berlin]'); assert.equal( zdt.toLocaleString(), '12/1/2019, 12:00:00 PM GMT+1'); Assert.equal (zdt.tolocalestring (' de-de '), '1.12.2019, 12:00:00 MEZ'); assert.equal( zdt.toLocaleString('en-GB', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', }), 'Sunday, 1 December 2019');Copy the code

Temporal does not support parsing human-readable strings.

In the traditionalDateTemporalTo convert between

On the one hand, we can convert traditional dates into Temporal instances.

const legacyDate = new Date('1970-01-01T00:00:01Z');

const instant1 = legacyDate.toTemporalInstant();
assert.equal(
  instant1.toString(),
  '1970-01-01T00:00:01Z');
Copy the code

This is an alternative to the previous method.

const ms = legacyDate.getTime();
const instant2 = Temporal.Instant.fromEpochMilliseconds(ms);
assert.equal(
  instant2.toString(),
  '1970-01-01T00:00:01Z');
Copy the code

Instant, on the other hand, exposes a field that gives us the epoch time in milliseconds — which we can use to create a date.

const instant = Temporal.Instant.from('1970-01-01T00:00:01Z'); const legacyDate = new Date(instant.epochMilliseconds); Assert. Equal (legacyDate. ToISOString (), 'the 1970-01-01 T00:00:01onsaturday (UK time). 000 z');Copy the code

Work using time values

Using field values

Most date-time classes support rich fields such as. DayOfWeek,. Month, and. Calendar. The notable exception is Instant, whose time zone and calendar are fixed, and whose Settings and state are diachronic.

In all other date-time classes, we can use the static factory function.from() to configure the instance.

const zonedDateTime = Temporal.ZonedDateTime.from({ timeZone: 'Africa/Lagos', year: 1995, month: 12, day: 7, hour: 3, minute: 24, second: 30, millisecond: 0, microsecond: 3, nanosecond: 500, }); Assert. Equal (zonedDateTime. ToString (), 'the 1995-12-07 T03:13. 0000035 + 01:00 Africa/Lagos');Copy the code

These and other fields can also be used as properties, but these properties are immutable.

assert.equal(
  zonedDateTime.year,
  1995);

assert.equal(
  zonedDateTime.month,
  12);

assert.equal(
  zonedDateTime.dayOfWeek,
  4);

assert.equal(
  zonedDateTime.epochNanoseconds,
  818303070000003500n);
Copy the code

If we want to change these fields, we need to create a new value with.with().

const newZonedDateTime = zonedDateTime.with({ year: 2222, month: 3, }); Assert. Equal (zonedDateTime. ToString (), 'the 1995-12-07 T03:13. 0000035 + 01:00 Africa/Lagos');Copy the code

For each date-time class D, provide a function D.compare to sort the instance D.

const dates = [
  Temporal.ZonedDateTime.from('2022-12-01T12:00[Asia/Tehran]'),
  Temporal.ZonedDateTime.from('2001-12-01T12:00[Asia/Tehran]'),
  Temporal.ZonedDateTime.from('2009-12-01T12:00[Asia/Tehran]'),
];
dates.sort(Temporal.ZonedDateTime.compare);
assert.deepEqual(
  dates.map(d => d.toString()),
  [
    '2001-12-01T12:00:00+03:30[Asia/Tehran]',
    '2009-12-01T12:00:00+03:30[Asia/Tehran]',
    '2022-12-01T12:00:00+03:30[Asia/Tehran]',
  ]);
Copy the code

Conversion between time values

willInstantconvertZonedDateTimePlainDateTime

const instant = Temporal.Instant.from('1970-01-01T00:00:01Z');

const zonedDateTime = instant.toZonedDateTimeISO('Europe/Madrid');
assert.equal(
  zonedDateTime.toString(),
  '1970-01-01T01:00:01+01:00[Europe/Madrid]');

const plainDateTime1 = zonedDateTime.toPlainDateTime();
assert.equal(
  plainDateTime1.toString(),
  '1970-01-01T01:00:01');

const timeZone = Temporal.TimeZone.from('Europe/Madrid');
const plainDateTime2 = timeZone.getPlainDateTimeFor(instant);
assert.equal(
  plainDateTime2.toString(),
  '1970-01-01T01:00:01');
Copy the code

willZonedDateTimeconvertInstantPlainDateTime

const zonedDateTime = Temporal.ZonedDateTime.from(
  '2019-12-01T12:00[Europe/Minsk]');

const instant = zonedDateTime.toInstant();
assert.equal(
  instant.toString(),
  '2019-12-01T09:00:00Z');

const plainDateTime = zonedDateTime.toPlainDateTime();
assert.equal(
  plainDateTime.toString(),
  '2019-12-01T12:00:00');
Copy the code

willPlainDateTimeConverted toZonedDateTimeInstant

const plainDateTime = Temporal.PlainDateTime.from(
  '1995-12-07T03:24:30');

const zonedDateTime = plainDateTime.toZonedDateTime('Europe/Berlin');
assert.equal(
  zonedDateTime.toString(),
  '1995-12-07T03:24:30+01:00[Europe/Berlin]');

const instant = zonedDateTime.toInstant();
assert.equal(
  instant.toString(),
  '1995-12-07T02:24:30Z');
Copy the code
const source = Temporal.ZonedDateTime.from(
  '2020-01-09T02:00[America/Chicago]');
const target = source.withTimeZone('America/Anchorage');

assert.equal(
  target.toString(),
  '2020-01-08T23:00:00-09:00[America/Anchorage]');
Copy the code
const plainDate = Temporal.PlainDate.from('2020-03-08');
assert.equal(
  plainDate.add({days: 1}).toString(),
  '2020-03-09');
Copy the code

First Monday in September

To calculate Labor Day in a given year (the first Monday in September), we need to figure out how many days we have to add to September 1 to reach Weekday 1 (Monday).

The Temporal Polyfill

The NPM package proposal-temporal contains a preliminary Polyfill of temporal.

More on the APITemporalDate

  • Official Temporal documents are currently hosted on GitHub, but will eventually be moved to MDN Web Docs.
  • The traditionalDateThe API is in the book “JavaScript for Thirsty Programmers”Chapter oneRecord.