Ditch date-fns & momentjs: Use Temporal Date API Instead
Tags: webdev, javascript, programming, tutorial
Published: 2023-02-18 09:36:10

We all know the pain of working with dates in Javascript. It needs to be more explicit, has almost no method, and could not be more clunky. For example, to create the Date **January 1, 2023**, you have to write a `new Date (2023, 0, 1)`, which can be confusing for beginners, and overall just not that clear. And because of these reasons, the community has made many libraries that attempt to make Date easier to work with over the past years. Like [momentjs](https://momentjs.com/) or [Date-fns](https://date-fns.org/). But the good news is that you won't need these third-party libraries any longer. The Temporal Date API in Javascript attempts to completely replace the Date object and fix all of the issues we generally face when working with dates.

🧭 **Jump to**
- [Introduction of Temporal Date API](#introduction-of-temporal-date-api)
  - [Bito AI](#bito-ai)
- [Temporal API Data Types](#temporal-api-data-types)
  - [Temporal.Instant](#temporalinstant)
  - [Temporal.ZonedDateTime](#temporalzoneddatetime)
  - [Temporal.PlainDate](#temporalplaindate)
  - [Temporal.PlainTime](#temporalplaintime)
  - [Temporal.PlainDateTime](#temporalplaindatetime)
  - [Temporal.PlainMonthDay](#temporalplainmonthday)
  - [Temporal.PlainYearMonth](#temporalplainyearmonth)
  - [Temporal.Duration](#temporalduration)
  - [Temporal.TimeZone](#temporaltimezone)
  - [Temporal.Calendar](#temporalcalendar)
- [Temporal API Helper Methods](#temporal-api-helper-methods)
  - [add and subtract](#add-and-subtract)
  - [since and until](#since-and-until)
  - [equals](#equals)
  - [with](#with)
  - [round](#round)
- [Browser Support](#browser-support)
- [Conclusion](#conclusion)

---

## Introduction of Temporal Date API

Temporal API brings **TONS** of new data types and methods for handling various date-based concerns. The API has a unique global object called `Temporal` that allows you to have an easy-to-use API for date and time computations. The main goal of the temporal API is to provide more support for things like dates without times, times without dates, timezones, PlainDate, PlainTime, and PlainDateTime objects which don't have an association with a time zone. In this article, I will cover the essential parts of the API. However, I can’t go through everything about the API as It is massive. So if you want to go more in-depth on the API, you can read the [full docs](https://tc39.es/proposal-temporal/docs).

> 💡 **NOTE:** Throughout the article, I've used a lot of examples. But I needed help to come up with these examples. So instead, I've used an AI platform called [Bito AI](https://bito.co/).

### Bito AI

We all know the effectiveness of ChatGPT and its usefulness in programming. However, to use chatGPT, we need to visit their website. It can be frustrating when coding because it destroys momentum. What if you could add ChatGPT directly in your code editor? [Bito AI](https://bito.co/) does just that. It uses ChatGPT in the background to generate code, helps to debug, write test cases, generate code comments, create code explanations, and more. Bito AI even contains a lot of shortcut options and keyboard shortcuts. They also do a lot of on-the-fly engineering to give you the best answer without any work on your part. In general, it's ChatGPT, but specifically for coding purposes. I recently started using it and love it!

## Temporal API Data Types

The Temporal API has different data types, divided into **plain** and **zoned** versions. Plain date/time helps represent a date/time without caring about the timezone. In contrast, a zoned date and time type are helpful when dealing with the exact time in a particular time zone.

### Temporal.Instant

A `Temporal.Instant` represents a specific point in time and does not consider any particular calendar or location.

```jsx
const today = Temporal.Now.instant()
console.log(today.toString())
// 2023-02-07T20:17:35.306655305Z

const date = Temporal.Instant.from("2023-02-07-06:00")
console.log(date.toString())
// 2022-01-01T06:00:00Z
```

### Temporal.ZonedDateTime

A `Temporal.ZonedDateTime` is a date/time object that contains all timezone-related information. It represents an actual event that has happened (or will happen) at a particular exact time from the perspective of a specific region on Earth.

```jsx
const today = Temporal.Now.zonedDateTimeISO()
console.log(today.toString())
// 2023-02-07T14:17:35.306655305[America/Chicago]

const persian = Temporal.Now.ZonedDateTime("persian")
console.log(persian.toString())
// 2022-02-21T14:17:35.306655305[America/Chicago][u-ca=persian]

const date1 = Temporal.ZonedDateTime.from("2022-01-01")
console.log(date1.toString())
// 2022-01-01T00:00:00-06:00[America/Chicago]
const date2 = Temporal.ZonedDateTime.from({ year: 2022, month: 1, day: 1 })
console.log(date2.toString())
// 2022-01-01T00:00:00-06:00[America/Chicago]

const zonedDateTime = Temporal.ZonedDateTime.from({
  timeZone: 'America/Los_Angeles',
  year: 1995,
  month: 12,
  day: 7,
  hour: 3,
  minute: 24,
  second: 30,
  millisecond: 0,
  microsecond: 3,
  nanosecond: 500
}); // => 1995-12-07T03:24:30.0000035-08:00[America/Los_Angeles]
```

### Temporal.PlainDate

A `Temporal.PlainDate` object represents a date with no other information. It is not associated with a particular time or time zone.

```jsx
const today = Temporal.Now.plainDateISO()
console.log(today.toString())
// 2023-02-07

const date = Temporal.PlainDate.from({ year: 2023, month: 2, day: 7 });
date.year; // => 2023
date.toString(); // => 2023-02-07
```

### Temporal.PlainTime

A `Temporal.PlainTime` object represents a time that is not associated with any timezone and date.

```jsx
const today = Temporal.Now.plainTimeISO()
console.log(today.toString())
// 2023-02-07T14:17:35.306655305

const time1 = Temporal.PlainTime.from("04:03:25")
console.log(time1.toString())
// 04:03:25
const time2 = Temporal.PlainTime.from({ hour: 4, minute: 3, second: 25 })
console.log(time2.toString())
// 04:03:25
```

### Temporal.PlainDateTime

The `Temporal.PlainDateTime` object represents a date and time with no timezone information. You can create a new PlainDateTime by using the `Temporal.Now.plainDateTimeISO` method.

```jsx
const today = Temporal.Now.plainDateTimeISO()
console.log(today.toString())
// 2023-02-07T14:17:35.306655305
```

If you are working with a different calendar system than ISO 8601 then you can do the following

```jsx
const today = Temporal.Now.plainDateTime("persian")
console.log(today.toString())
// 2023-02-07T14:17:35.306655305[u-ca=persian]
```

If you want to create a new `PlainDateTime` with a custom date instead of just using the current time, there are two ways to do so.

(1) The first way is to give the method a date by specifying the **year**, **month,** and **date**. It can even have an **hour**, **minute**, **second**, **millisecond**, **microsecond**, **nanosecond**, and **calendar.**

```jsx
const date = new Temporal.PlainDateTime(2023, 4, 1)
console.log(date.toString())
// 2023-04-01T00:00:00
```

(2) Alternatively, you can use `from` method on the `PlainDateTime` object instead. This method takes either a string that matches a date or an object with keys for each part of the date.

```jsx
const date1 = Temporal.PlainDateTime.from("2022-05-06")
console.log(date1.toString())
// 2022-05-06T00:00:00
const date2 = Temporal.PlainDateTime.from({ year: 2022, month: 4, day: 1 })
console.log(date2.toString())
// 2022-04-01T00:00:00
```

### Temporal.PlainMonthDay

`Temporal.PlainMonthDate` works like a  `PlainDate`, However, It excludes any year information.

```jsx
const date1 = Temporal.PlainMonthDay.from("01-01")
console.log(date1.toString())
// 01-01
const date2 = Temporal.PlainMonthDay.from({ month: 1, day: 1 })
console.log(date2.toString())
// 01-01
```

### Temporal.PlainYearMonth

`Temporal.PlainYearMonth` excludes any day information.

```jsx
const date1 = Temporal.PlainYearMonth.from("2023-01")
console.log(date1.toString())
// 2022-01
const date2 = Temporal.PlainYearMonth.from({ year: 2023, month: 1 })
console.log(date2.toString())
// 2022-01
```

### Temporal.Duration

`Temporal.Duration` represents a duration of time. It is helpful for date/time arithmetic.

```jsx
const duration = Temporal.Duration.from({
  hours: 130,
  minutes: 20
});

duration.total({ unit: 'second' }); // => 469200
```

You can even use arithmetic like `add`, `subtract`, `with`, and `round` (I explained them later in the article) methods on durations. There are even a few additional helper methods that you should know.

```jsx
const duration = Temporal.Duration.from({ hours: 200, minutes: 17 })
console.log(duration.negated().toString())
// -PT200H17M
console.log(duration.negated().abs().toString())
// PT200H17M
console.log(duration.total("minutes"))
// 12017
```

### Temporal.TimeZone

The `Temporal.TimeZone` represents a particular timezone. You use this with the `from` method or with the `Temporal.Now.timeZone` method.

```jsx
const timeZone = Temporal.TimeZone.from('Africa/Cairo')
console.log(timeZone.toString())
// Africa/Cairo

const localTimeZone = Temporal.Now.timeZone()
console.log(localTimeZone.toString())
// America/Chicago
```

### Temporal.Calendar

`Temporal.Calendar` represents a calendar system. You can create a calendar using the `from` method.

```jsx
const cal = Temporal.Calendar.from('iso8601');
const date = cal.dateFromFields({ year: 1999, month: 12, day: 31 }, {});
date.monthsInYear; // => 12
date.daysInYear; // => 365
```

## Temporal API Helper Methods

By now, we've seen a lot of data types. However, there are also a bunch of helper functions you can use to compare dates, use arithmetic with dates like add/subtract, convert types, and much more.

### add and subtract

As It sounds, these two methods let you do addition and subtraction with two or more dates.

```jsx
const today = Temporal.Now.plainDateISO() // 2022-02-07
console.log(today.add({ days: 4, months: 2 }).toString())
// 2022-04-11
```

It also deals with overflow. For example, if the current date is `February 7th, 2023`, and you want to add one month to it, the resulting date should have been `March 7th, 2023`. However, the month of March doesn’t yet exist. Therefore, these results default to the nearest valid date, which would return **February 28th**. You can disable this behavior, though, with a second options argument.

```jsx
const date = Temporal.PlainDate.from("2022-01-31")
console.log(date.add({ months: 1 }).toString())
// 2022-01-28
date.add({ months: 1 }, { overflow: "restrict" })
// Uncaught RangeError: value out of range: 1 <= 31 <= 28
```

### since and until

The `since` and `until` methods determine the distance between two temporal date objects.

```jsx
const today = Temporal.Now.plainDateISO()
const yesterday = today.subtract({ days: 1 })
console.log(today.since(yesterday).toString())
// P1D
```

The value returned by these methods is `Temporal.Duration` object. You can even pass options to these methods to fine-tune how you want the duration calculated.
If you specify the `largestUnit`, then the duration will be determined using that unit as the most significant value instead of the default value.

```jsx
const today = Temporal.Now.plainDateISO()
const lastMonth = today.subtract({ months: 1, days: 4 })
console.log(today.since(lastMonth).toString())
// P35D
console.log(today.since(lastMonth, { largestUnit: "months" }).toString())
// P1M4D
```

In the same way, the `smallestUnit` determines the duration by that unit as the smallest value instead of the default value. However, it could result in rounding, which you can further customize with the `roundingIncrement` and `roundingMode` options.

```jsx
const today = Temporal.Now.plainDateISO()
const lastMonth = today.subtract({ months: 3, days: 4 })
console.log(today.since(lastMonth).toString())
// P96D
console.log(today.since(lastMonth, { smallestUnit: "months" }).toString())
// P3M
console.log(today.since(lastMonth, { smallestUnit: "months", roundingIncrement: 2 }).toString())
// P2M
console.log(today.since(lastMonth, { smallestUnit: "months", roundingMode: "ceil" }).toString())
// P4M
```

### equals

The `equals` method returns true only if the two **temporal date objects** have the same fields. Using `==` or `===` will return false unless the two objects are the same instance.

```jsx
const today = Temporal.Now.plainDateISO()
const today2 = Temporal.Now.plainDateISO()
console.log(today === today2)
// false. Because they are two different instances
console.log(today.equals(today2))
// true
```

### with

The `with` method takes an object of fields to overwrite the current temporal date object. However, it doesn't overwrite the original date object. Instead, It returns a new temporal date object with the new value specified.

```jsx
const today = Temporal.Now.plainDateISO()
console.log(today.with({ year: 2023, month: 3 }).toString())
// 2023-03-21
```

### round

This method rounds a temporal date to a specific unit.

```jsx
const today = Temporal.Now.plainDateTimeISO()
console.log(today.round("hour").toString())
// 2022-02-22T14:00:00
```

To modify the performance of the round method, you can pass an object that takes `smallestUnit`, `roundingIncrement`, and `roundingMode`.

```jsx
const today = Temporal.Now.plainDateTimeISO()
console.log(today.round({ smallestUnit: "hour" }).toString())
// 2022-02-22T14:00:00
console.log(today.round({ smallestUnit: "hour", roundingMode: "ceil" }).toString())
// 2022-02-22T15:00:00
console.log(today.round({ smallestUnit: "hour", roundingIncrement: 6 }).toString())
// 2022-02-22T12:00:00
```

## Browser Support

I love Temporal Date API. However, this API has yet to be available as it is still in [proposal stage 3](https://blogs.igalia.com/compilers/2020/06/23/dates-and-times-in-javascript/). No browsers currently support this API, but you can use a polyfill if you want to start using this API today. Multiple polyfills are available for this API, but my favorite is [@js-temporal/polyfill](https://www.npmjs.com/package/@js-temporal/polyfill). Once you install this library, you can immediately start using the temporal API.

---

## Conclusion

Everyone used to hate working with Dates in JavaScript, but with the introduction of the temporal API working with dates will be something you can enjoy doing.