Announcing Bito’s free open-source sponsorship program. Apply now

Get high quality AI code reviews

Ditch date-fns & momentjs: Use Temporal Date API Instead

50

Table of Contents

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 or Date-fns. 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.

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.

💡 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.

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 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.

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.

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.

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.

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.

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

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.

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.

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.

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.Duration

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

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

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

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

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.

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.

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.

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.

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.

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.

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.

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

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

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.

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.

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.

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.

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. 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. 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.

Picture of Anand Das

Anand Das

Anand is Co-founder and CTO of Bito. He leads technical strategy and engineering, and is our biggest user! Formerly, Anand was CTO of Eyeota, a data company acquired by Dun & Bradstreet. He is co-founder of PubMatic, where he led the building of an ad exchange system that handles over 1 Trillion bids per day.

Picture of Amar Goel

Amar Goel

Amar is the Co-founder and CEO of Bito. With a background in software engineering and economics, Amar is a serial entrepreneur and has founded multiple companies including the publicly traded PubMatic and Komli Media.

Written by developers for developers

This article was handcrafted with by the Bito team.

Latest posts

9 Best Code Quality Tools Every Developer Should Know

11 Best SonarQube Alternatives in 2025

Recent releases: Pick your AI model, create PR from IDE, integrated Linter feedback, and more

PEER REVIEW: Shubham Gupta, Chief Technology Officer at ToolJet

Ultimate Java Code Review Checklist

Top posts

9 Best Code Quality Tools Every Developer Should Know

11 Best SonarQube Alternatives in 2025

Recent releases: Pick your AI model, create PR from IDE, integrated Linter feedback, and more

PEER REVIEW: Shubham Gupta, Chief Technology Officer at ToolJet

Ultimate Java Code Review Checklist

From the blog

The latest industry news, interviews, technologies, and resources.

Get Bito for IDE of your choice