Temporal - Date & Time in JavaScript today!
Tags: javascript, webdev, i18n, internationalization
Published: 2020-08-26 10:03:08

> **Important!**: This article as been written almost 2 years ago `Temporal` updated their API and is even more awesome now - Part two of the article coming soon!

Every developer at some point in their careers had to play with **Date** & **Time** and if you are lucky... You only had to deal with **time zones** when you are travelling.

The JavaScript community & developers have been trying to solve this in different ways, either by developing their own libraries or by using any popular solution like **moment**, **date-fns** or **DayJS** among others. There is a nice blog post about [Fixing JavaScript Date](https://maggiepint.com/2017/04/09/fixing-javascript-date-getting-started/).

### _"It's 2020... and `moment` still in my package.json"_

Not having nothing against all these folks and the community that made an awesome job with these libraries, I believe that it's time to have a solution that is part of the standards, solving this long-standing issue at once... as an alternative, we can build `moment` into the browser too.

{% twitter 1275505462797053952 %}

### "_Yeahhhh!_ **Temporal** _is here..._ & What is this ?"

Temporal is a new proposal, already at Stage 2 that brings a modern date/time API to the ECMAScript land.

> At the time of writing there is no browser implementation yet, a polyfill is available at [npm](https://www.npmjs.com/package/proposal-temporal), please give it a try and provide [feedback](https://docs.google.com/forms/d/e/1FAIpQLSeYdvnDZZS6tKn18jiomfN7u_rq-_-_BqOevTzAcfgE3J4kHA/viewform).

### Cool things about **Temporal**?

- Providing easy-to-use APIs for date and time computations
- Dealing only with immutable objects
- Parsing a strictly specified string format: ISO-8601
- Supporting non-Gregorian calendars, and time zones other than the user's local time and UTC
- Still being an experimental API, but hopefully it will eventually be a standard, built-in to JS
- Is local aware, support time zones and locales by default, no extra plugins or data are required
- It is designed to be used directly, with an easy API, as well as embedding well in other libraries

---

# Overview

This overview covers functionalities that I use most in my projects and I’d like you to know the goals & non-goals that we are trying to accomplish through this overview.

### Outline

- Review what Temporal has to offer and highlight some API's
- Compare the ergonomics and functionality with existing libraries
- Learn and understand how it works
- Provide valuable feedback from my usage and experience with `Temporal`

This post doesn’t cover all API surface, for that please refer to their [documentation](https://tc39.es/proposal-temporal/docs/) that has excellent [examples](https://tc39.es/proposal-temporal/docs/cookbook.html).It also omits any benchmarks--the polyfill may be slow, but that’s because it hasn’t been optimized yet.

### Usage

> Intentionally no configuration or extra plugins for time zone & locales are used,  this is required by some libraries and may affect results that won't be showing accordingly with my time zone(Europe/Madrid) or locale(es-ES).

#### Date of Month

```js
// Temporal
Temporal.now.date().day;

// moment
moment().date();

// dayjs
dayjs().date();

// date-fns
import { getDate } from 'date-fns';
getDate(new Date());

// => 14 (Current Day)
```

#### Day of Week

```js
// Temporal
Temporal.now.date().dayOfWeek;

// moment
moment().day();

// dayjs
dayjs().day();

// date-fns
import { getDay } from 'date-fns';
getDay(new Date());

// => 2 (Current Day of Week)
```

#### Add

```js
// Temporal
Temporal.now.absolute().plus({ days: 7 });
// => 2020-07-22T13:03:01.419163174Z

// moment
moment().add(7, 'days');
// => Wed Jul 22 2020 15:03:24 GMT+0200

// dayjs
dayjs().add(7, 'day');
// => Wed, 22 Jul 2020 13:03:52 GMT

// date-fns
import { add } from 'date-fns';
add(new Date(), { days: 7 });
// => 2020-07-22T13:04:37.366Z
```

#### Subtract

```js
// Temporal
Temporal.now.absolute().minus({ days: 7 });
// => 2020-07-08T13:07:17.807181419Z

// moment
moment().subtract(7, 'days');
// => Wed Jul 08 2020 15:08:03 GMT+0200

// dayjs
dayjs().subtract(7, 'day');
// => Wed, 08 Jul 2020 13:08:24 GMT

// date-fns
import { sub } from 'date-fns';
sub(new Date(), { days: 7 });
// => 2020-07-08T13:08:54.558Z
```

#### Difference

```js
const startDate = new Date('1986-07-1');
const endDate = new Date('2020-07-1');

// Temporal
const temporalStart = Temporal.Absolute.from(startDate.toISOString());
const temporalEnd = Temporal.Absolute.from(endDate.toISOString());
const temporalDiff = temporalEnd.difference(temporalStart, {
  largestUnit: 'days',
});
console.log(temporalDiff.toString());
// => P12419D (ISO 8601 notation)
// Or `temporalDiff.days`
// => 12419

// moment & dayjs have similar API
const momentStart = moment(startDate);
const momentEnd = moment(endDate);
const momentDiff = momentEnd.diff(momentStart, 'days');
console.log(momentDiff.toString());
// => 12419

// date-fns
import { differenceInDays } from 'date-fns';
differenceInDays(startDate, endDate); //=> -12419
differenceInDays(endDate, startDate); //=> 12419
```

#### Duration

```js
// Temporal
new Temporal.Duration(0, 0, 0, 0, 23, 59, 59);
Temporal.Duration.from({ hours: 23, minutes: 59, seconds: 59 });

// moment
moment.duration('23:59:59');
moment.duration({ hours: 23, minutes: 59, seconds: 59 });

// dayjs
// => This dependent on `Duration` plugin to work

// .toString() output
// => PT23H59M59S
// => PT23H59M59S

// date-fns
import formatISODuration from 'date-fns/formatISODuration'; // ESM export is not working
formatISODuration({ hours: 23, minutes: 59, seconds: 59 });
//=> P0Y0M0DT23H59M59S
```

#### Days in Month

```js
// Temporal
new Temporal.YearMonth(2020, 2).daysInMonth;
new Temporal.YearMonth(2021, 2).daysInMonth;

// Moment
moment('2020-02', 'YYYY-MM').daysInMonth();
moment('2021-02').daysInMonth();

// DayJS
dayjs('2020-02').daysInMonth();
dayjs('2021-02', 'YYYY-MM').daysInMonth();

// date-fns
import { getDaysInMonth } from 'date-fns';
// https://date-fns.org/v2.14.0/docs/getDaysInMonth
getDaysInMonth(new Date(2020, 1));
getDaysInMonth(new Date(2021, 1));

// Output
// => 29
// => 28
```

#### Compare

```js
// Temporal
const t1 = Temporal.Date.from('2020-02-20');
const t2 = Temporal.Date.from('2020-03-21');
Temporal.Date.compare(t1, t2); //=> `−1` if one comes before two;
Temporal.Date.compare(t2, t1); //=> `1` if one comes after two.
Temporal.Date.compare(t2, t2); //=>  `0` if one and two are the same;

// moment & dayjs have similar API
const m1 = '2020-02-20';
const m2 = '2020-03-21';
moment(m1).isBefore(m2); // => true
moment(m1).isAfter(m2); // => false
moment(m1).isSame(m1); // => true

// date-fns
import { compareAsc, compareDesc } from 'date-fns';
const fns1 = new Date('2020-02-20');
const fns2 = new Date('2020-03-21');
compareAsc(fns1, fns2); //=> `-1` if the first date is before the second
compareAsc(fns2, fns1); //=> `1` if the first date is after the second
compareAsc(fns2, fns2); //=> `0` if dates are equal.
compareDesc(fns1, fns2); //=> `1` if the first date is before the second
compareDesc(fns2, fns1); //=> `-1` if the first date is after the second
compareDesc(fns2, fns2); //=> `0` if dates are equal.
```

#### i18n

```js
// Temporal
Temporal.now.date().toLocaleString('es-ES', {
  weekday: 'long',
}); // => martes

// moment (only works loading locale strings separately - 4.04 KB)
moment().locale('es-ES').format('dddd'); //=> martes

// dayjs (only works loading locale strings separately - 1.01 KB)
dayjs().locale('es-ES').format('dddd'); //=> martes

// date-fns only works import locale strings separately - no size info)
import { format } from 'date-fns';
import { es } from 'date-fns/locale';
format(new Date(), 'cccc', { locale: es }); //=> martes
```

---

# Summing up

### First impressions

As I described before, at the time of writing the `Temporal` proposal is Stage 2, but it is already in very good shape. The functionality covers a wide spectrum of use cases, arithmetic with dates and times, work with different calendar systems, time zones and more.

The surface of the API together with all other Intl `built-in` objects play an important role in this long-standing dilemma of dealing with date/time in the browser together with the internationalization.

API is accessible and easy to use and includes good [documentation](https://tc39.es/proposal-temporal/docs/).

### Adoption

`Temporal` is part of the `standards` and follows the [TC39 process](https://tc39.es/process-document/) to become part of the ECMAScript language and be implemented in the browsers.

The **adoption** can start by including the `proposal-temporal` polyfill in your projects  [following the instructions](https://github.com/tc39/proposal-temporal/tree/main/polyfill#import-as-a-module).

**_Voilaaa!_** no more extra dependencies, no more loading locale-specific data and full functionality.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/6d9znvwyc0ky46eoxy0d.png)

Remember that a polyfill [_"...is code that implements a feature on web browsers that do not support the feature..."_](<https://en.wikipedia.org/wiki/Polyfill_(programming)>), if they do support, you won't need it, that’s the big difference from using a library.

> note: specification text, documentation and polyfill at time of writing still under development and should be understood non-production ready.


### Benefits and opportunities

**for Users**
- Simple and ergonomic API to handle date/time and time zones in the browser
- Dependency free(no extra data, no libraries)
- Works well with `Intl`, which provides high-quality date and time formatting with many languages and options
- Have multiple choices and one that is part of the `standards`

**for Libraries**

- Stable and lean API to build features on top of
- Reduce the need for loading extra data to time zones or locales
- Reduced bundle size

### Present

All those libraries `moment(12.443.725)`, `date-fns(6.499.163)` and `dayJS(1.941.696)` sum up to 20M weekly downloads, this validates the need of having a solution directly on the language, in the other hand, these figures are a clear indicator about the future impact that `Temporal` will have in the JavaScript landscape.

This new API is also paving the base for future improvements on existing ones you have the example of `Intl.DisplayNames` that would benefit from the `Temporal` calendar to provide even more options([read more here](https://github.com/tc39/proposal-intl-displaynames/issues/75#issuecomment-631744838)).
 
### Future

`Temporal`, has a marathon ahead of them before is widely accepted, this happened with most of the standards we know `_.assign()` vs `Object.assign()` etc... The transition process requires a well-defined path and then things will follow naturally.

 I don't see the end of the road for those libraries, but more likely a sensation of accomplishing a goal. Future looks promising and different synergies can come up from this new `standard`.


### Help and Feedback

Never had been so easy to have a **voice** on the standards, you can start by testing, reading the documentation and contribute by filling the [feedback form](https://docs.google.com/forms/d/e/1FAIpQLSeYdvnDZZS6tKn18jiomfN7u_rq-_-_BqOevTzAcfgE3J4kHA/viewform) or by opening [Github issues](https://github.com/tc39/proposal-temporal/issues/new) with ideas or feedback that can be helpful to make `Temporal` even better.

Overall, I have some concerns with `Temporal`, which I’ve been raising on issues in the issue tracker like [#770](https://github.com/tc39/proposal-temporal/issues/770), [#772](https://github.com/tc39/proposal-temporal/issues/772). It remains unclear to me how the transition from JS date libraries to Temporal will work exactly, and so I’ve been participating in the Temporal issue tracker to help find a direction. I hope you’ll share your thoughts as well!

---

👏  Kudos to all library authors that kept our backs during this time and to the `Temporal` team that is working hard to make it part of the language. 


---

Let me know what you think about this post on [Twitter](https://twitter.com/romulocintra) and I hope you enjoyed it. 

Thanks to all the people who helped me review this article.