zurück zum Artikel

JavaScripts Temporal API: New era for date and time calculations

Sebastian Springer
Woman turns the clock

(Bild: New Africa/Shutterstock.com)

The Temporal API fixes JavaScripts date and time issues. It offers consistency, precision and time zone support. Soon to be standard in all browsers.

Something is happening with the Temporal API, the interface that is supposed to eliminate one of the biggest weaknesses of the JavaScript programming language: the handling of date and time. TC39, the standardization committee for JavaScript, has been working for some time [1] on the Temporal API, which is intended to replace the Date interface. The problems of the Date interface are manifold, there are inconsistencies, susceptibility to errors and a lack of support for time zones. The Temporal API is not only intended to replace the Date API, but also to compete with established libraries such as date-fns, Day.js or Luxon.

Sebastian Springer
Sebastian Springer

Sebastian Springer works as a JavaScript Engineer at MaibornWolff. In addition to developing and designing applications, his focus is on imparting knowledge. As a lecturer for JavaScript, speaker at numerous conferences and author, he tries to arouse enthusiasm for professional development with JavaScript.

The TC39 itself has implemented a polyfill, i.e. a program code module written in JavaScript, which makes the interface available in various JavaScript environments such as the browser or on the server side. However, it is explicitly not intended for productive use. There are now two packages, @js-temporal/polyfill and temporal-poyfill, which can be used instead. With around 160,000 and 130,000 weekly NPM downloads respectively, their distribution cannot be compared with the 26 million of date-fns or the 22 million of Day.js. However, the situation will change in the near future.

Firefox is the first browser to deliver a complete implementation of the Temporal API – although only in the nightly build of the browser, which is the first step towards the integration of a new interface. Safari provides individual parts of the API in its Technical Preview and all other browsers are also actively working on integrating the new API.

At the moment, the interface can only be used via the polyfill packages, but it is well on the way to becoming the new JavaScript standard for working with dates and times.

The Temporal API not only addresses the shortcomings of JavaScript's Date API, but also adopts numerous useful functions from the established date libraries. The interface is also based on modern architectural patterns. The main features of Temporal are

The Temporal API provides a range of classes for the different use cases when processing date and time values:

The classes of the Temporal API

The classes of the Temporal API

(Image: TC39 [2])

Depending on the use case, there are several ways to create a new Temporal instance. Listing 1 shows these using the PlainDateTime class as an example.

const now = Temporal.Now.plainDateTimeISO();
console.log(now.toString()); // 2025-02-23T11:06:41.898

const newDateTime = new Temporal.PlainDateTime(1999, 8, 11, 12, 35);
console.log(newDateTime.toString()); // 1999-08-11T12:35:00

const newDateTime1 = Temporal.PlainDateTime.from(newDateTime);
console.log(newDateTime1.toString()); // 1999-08-11T12:35:00

const newDateTime2 = Temporal.PlainDateTime.from('1999-08-11T12:35');
console.log(newDateTime2.toString()); // 1999-08-11T12:35:00

const newDateTime3 = Temporal.PlainDateTime.from({
  year: 1999,
  month: 8,
  day: 11,
  hour: 12,
  minute: 35,
});
console.log(newDateTime3.toString()); // 1999-08-11T12:35:00

const newDate = new Date('1999-08-11T12:35');
const instant = newDate.toTemporalInstant();
const zoned = instant.toZonedDateTimeISO('Europe/Berlin');
const newDateTime4 = zoned.toPlainDateTime();
console.log(newDateTime4.toString()); // 1999-08-11T12:35:00

Listing 1: Creating new instances of the PlainDateTime class

For the current time, the Temporal API provides the Temporal.Now object with a number of methods. The plainDateTimeISO method creates a PlainDateTime object.

There are different variants for instances that represent a fixed point in time. The first is via the constructor of the PlainDateTime class, which accepts a number of parameters that represent the individual parts of the time. Of these, the year, month and day are mandatory. All other information has the value 0 by default. The static method from is much more flexible and therefore recommended. It accepts either a PlainDateTime object, of which it creates a copy, an ISO string that represents the date, or an object with the information about the date in the form of property values.

Converting a JavaScript Date object into a PlainDateTime object is somewhat more complicated, but still possible. The Date API will provide the toTemporalInstant method in the future. The Instant instance must be converted into a ZoneDateTime, which can then be converted into a PlainDateTime object. This detour also makes it possible to integrate the Temporal API into existing applications.

The creation of date objects was already possible with the previous means of JavaScript, albeit in an inconsistent manner. The really interesting

extensions are the new operations that the Temporal API enables.

For formatting date and time values, the Temporal API relies on the Intl interface and its DateTimeFormat class. This allows developers to specify the various aspects of date formatting, for example that the month and day should be formatted with two digits. A locale containing the formatting of a date can also be selected. All formatting specifications that are omitted during the call are also omitted in the output. Listing 2 ensures that JavaScript outputs the passed object PlainDateTime in the format "day.month.year, hour:minute".

const dateTime = Temporal.PlainDateTime.from('1999-08-11T12:35');

const formatter = new Intl.DateTimeFormat('de-DE', {
  day: '2-digit',
  month: '2-digit',
  year: 'numeric',
  hour: '2-digit',
  minute: '2-digit',
});

const formattedDateTime = formatter.format(dateTime);
console.log(formattedDateTime); // 11.08.1999, 12:35

Listing 2: Formatting a PlainDateTime object with Intl.DateTimeFormat

The Temporal API makes it easy to calculate with dates and times. A simple use case is the planning of three dates four weeks apart. The code in Listing 3 first defines the first date and then uses the add method to add four weeks in each case.

const startDate = Temporal.PlainDateTime.from('2025-02-23T10:00:00');

const numberOfAppointments = 3;

const appointments = [];

for (let i = 0; i < numberOfAppointments; i++) {
  const appointment = startDate.add({ weeks: -4 * i });
  appointments.push(appointment);
}

appointments.forEach((appointment, index) => {
  console.log(`Appointment ${index + 1}: ${appointment.toString()}`);
});

Listing 3: Calculation of date and time values

Both the add and subtract methods create new objects and accept either a string, an object or a Duration instance that describes the value to be added or subtracted. In the example, the second variant, an object with the weeks property, is used. With the add and substract methods, other date values such as years, months, days or time values such as hours or minutes are also permitted.

The equals method compares two temporal objects with each other. This works not only within a class, but also across classes. It is therefore possible to check whether a PlainDateTime object matches a ZonedDateTime object or a PlainTime. The available information must be the same for different classes.

There are use cases in which the details of a date or time specification are not relevant. For such cases, the temporal classes offer a round method. It rounds a temporal instance to different units such as days, hours or minutes and uses different rounding strategies for this. An example could be an application for time bookings that records the project effort with the specification to round the times to quarter hours (Listing 4).

const currentTime = Temporal.Now.plainDateTimeISO(); 
  // 2025-02-23T13:30:25.425

const roundedTime = currentTime.round({
  smallestUnit: 'minute',
  roundingIncrement: 15,
  roundingMode: 'ceil',
});

console.log('Rounded time:', roundedTime.toString()); 
  // Rounded time: 2025-02-23T13:45:00

Listing 4: Rounding date and time values with round

The only mandatory value of this method is the smallest unit that the rounded object should contain. All values that are less than or equal to day are possible. Months and years cannot be rounded. With roundingIncrement you can specify an increment for the rounding, in Listing 4 for example it is a quarter of an hour.

The default value for the increment is 1. The roundingMode specifies how rounding is performed. The value ceil stands for rounding up, the default value halfExpand rounds commercially and floor rounds down. There are also a number of other rounding strategies that the Temporal API takes from the NumberFormat class of the Intl API.

The Temporal API provides the Duration class for the representation of time spans. As with the other classes, its objects can either be created using a constructor or, better still, using the from method. In addition, the since and until methods of the date and time classes also produce Duration instances to represent the time span between two time specifications. The code in Listing 5 shows two use cases of the Duration class. The script first outputs how many weeks lie between 1.1.25 and 1.6.25 and adds 5 weeks to 1.6.25 in the second part.

const start = Temporal.PlainDate.from('2025-01-01');
const end = Temporal.PlainDate.from('2025-06-01');

const duration = start.until(end);

const weeks = duration.total({ unit: 'week', relativeTo: start });

console.log(weeks); // 21.571428571428573

const newEnd = end.add({ weeks: 5 });

console.log(newEnd.toString()); // 2025-07-06

Listing 5: Working with time spans

A special feature is the total method of the Duration object. It returns the value of a time span. In the example, this is the weeks between the start and end date. If a Duration object is about the time span between two calendar values, the method requires the start date, otherwise it returns a RangeException. The rest of the code behaves very similarly to the other Temporal interfaces.

A major advantage of the new time API is that it fully supports time zones. This addresses one of the biggest problems of the previous Date API. A typical use case is the conversion of date and time values into different time zones.

One example could be the Super Bowl. In 2025, the game took place on 09.02.2025 at 17:30 in New Orleans. The ZonedDateTime class of the Temporal API is used for the conversion to Central European Standard Time. Listing 6 shows the source code for this example.

const start = Temporal.PlainDateTime.from('2025-02-09T17:30');

const startZoned = start.toZonedDateTime('America/Chicago');
console.log(startZoned.toString()); // 2025-02-09T17:30:00-06:00[America/Chicago]
const germanStart = startZoned.withTimeZone('Europe/Berlin');
console.log(germanStart.toString()); // 2025-02-10T00:30:00+01:00[Europe/Berlin]

Listing 6: Time conversion between time zones

The basis is a PlainDateTime object that provides the toZonedDateTime with the specification "America/Chicago" of the North American central time zone. This does not adjust the time and date value. The start of the game remains at 17:30 on 09.02.2025. A call to withTimeZone for "Europe/Berlin" produces a new object with the value 00:30 on 10.02.2025.

A web application often saves such time and date values in the neutral UTC time zone and converts the values based on the desired time zone. This minimizes the potential for errors caused by the wrong time zone.

Formatting remains a weakness. Unfortunately, a format method is not available in the Temporal API. With its format function, date-fns offers a convenient and flexible solution for formatting a value with a format string. But solutions are also emerging here.

The established libraries will probably support the Temporal API as soon as it is widespread enough in common browsers. Until then, there is unfortunately only a somewhat cumbersome detour as in Listing 7.

import { format } from 'date-fns';

const start = Temporal.PlainDateTime.from('2025-02-25T10:00');

const startZoned = start.toZonedDateTime('UTC');

const startInstant = startZoned.toInstant();
const date = new Date(startInstant.epochMilliseconds);

const formattedDateTime = format(date, 'yyyy-MM-dd HH:mm:ss');
console.log(formattedDateTime); // 2025-02-25 11:00:00

Listing 7: Using date-fns with Temporal objects

With the Temporal API, almost everything is getting better in the JavaScript world. At least January is no longer month 0 of the year, which has often led to problems. The interfaces of the various classes are structured much more consistently, meaning that developers rarely have to consult the documentation only to discover that the use case they are looking for cannot be mapped with the Date interface, but requires an additional library.

The new API primarily improves calculations with time and date. The interface allows calculations and comparisons and is able to work with time spans with and without date reference. Consistent support for time zones also makes working in international applications much easier.

The Date class in JavaScript can create new instances with a timestamp. It is therefore necessary to convert a temporal instance into a timestamp. Starting from a PlainDateTime object in the Temporal API, the first step is to create a ZonedDateTime object, which is then converted into an Instant instance. The epochMilliseconds property of this object provides the timestamp. The Date object created with this can be used as usual with the existing libraries, as in the example with the format function of date-fns – admittedly not a nice solution, but certainly not one that will last.

The Temporal API is not yet ready for production, but the polyfill packages and the first fully-fledged reference implementation in the nightly build of Firefox provide an initial insight into the native implementation, which is now gradually finding its way into browsers.

(olb [3])

Don't miss any news – follow us on Facebook [4], LinkedIn [5] or Mastodon [6].

This article was originally published in German [7]. It was translated with technical assistance and editorially reviewed before publication.


URL dieses Artikels:
https://www.heise.de/-10310876

Links in diesem Artikel:
[1] https://www.heise.de/blog/Die-Temporal-API-besseres-Datehandling-fuer-JavaScript-6069626.html?from-en=1
[2] https://tc39.es/proposal-temporal/docs/#string-persistence-parsing-and-formatting
[3] mailto:olb@heise.de
[4] https://www.facebook.com/heiseonlineEnglish
[5] https://www.linkedin.com/company/104691972
[6] https://social.heise.de/@heiseonlineenglish
[7] https://www.heise.de/hintergrund/JavaScripts-Temporal-API-Neue-Aera-fuer-Datum-und-Zeitberechnungen-10310315.html