Temporal API - A new approach to managing Date and Time in JS

Necati Özmen - Aug 19 '22 - - Dev Community

Introduction

Date object is the least-fun thing and a long-standing pain point in JavaScript. That's why there're other libraries like moment.js and date-fns. Developers use these to make sense of Date object. Implementation of Date object was directly copied from Java. Java scrapped it, but it remained in JavaScript for backward compatibility. It was written a long-time ago and not updated. There're some basic issues with the current Date implementation.

  • Supports only UTC and user's local time zone
  • The Date object is mutable: a date will change as methods are applied
  • Parsing dates from strings is unreliable
  • No support for non-Gregorian calendars
  • Computation APIs are clunky

Steps we’ll cover:

What Is The Temporal API?

Temporal API, a better replacement for Date object. Temporal presents standard data types and methods for working with dates and times. It allows you to have an easy-to-use API for date and time computations. It gives support for all time zones without having to reach for another library like date-fns. It’s a way to have a better date/time API in JavaScript. It provides PlainDate, PlainTime, and PlainDateTime objects which don’t have an association with a time zone. There’s also a way to grab time associated with time zone. It supplies tools to work with time zones or without them. So, basically, Temporal provides data types that are being split into plain and zoned.

Temporal handles these issues by:

  • First-class support for all time zones
  • Handling objects available with fixed dates and times
  • Providing reliability through parsing a strict string format
  • Support for non-Gregorian calendars
  • Date and time computations by providing simple APIs

There’re several data types and methods available with Temporal and we'll get to explore most of them in this guide.

Project setup

We'll create a very basic project.

Create an empty directory for your new Temporal API project.

mkdir temporal-api
cd temporal-api
Enter fullscreen mode Exit fullscreen mode

To start working with Temporal API, you need to install the following package first:

npm init
npm install @js-temporal/polyfill
Enter fullscreen mode Exit fullscreen mode

Make sure you add Snowpack as a dev dependency.

npm install --save-dev snowpack
Enter fullscreen mode Exit fullscreen mode

Create a temporal.js file and include it as a source in the index.html file to test the Temporal API.

// index.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Temporal API</title>
        <script src="temporal.js" type="module"></script>
    </head>
    <body> 
    </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Import the following package in the temporal.js file, and you're ready to start working with Temporal API.

// temporal.js

import { Temporal } from '@js-temporal/polyfill';
Enter fullscreen mode Exit fullscreen mode

Now, we are able to inspect the browser console when testing the following cases.


github support banner

Temporal API Data Types

Temporal.Now

It'll give you a bunch of different methods that allow you to essentially get an object for the current time. Let's say you want to get a plain date and time:

const now = Temporal.Now.plainDateTimeISO()
console.log(now.toString())
// 2022-08-15T17:26:43.63340363
Enter fullscreen mode Exit fullscreen mode

This is the exact time all the way down to micro and nono-seconds. It's very specific, which you can't do with a normal Date object. If you want to get the date and time separately, you can do this:

const nowDate = Temporal.Now.plainDateISO()
const nowTime = Temporal.Now.plainTimeISO()

console.log(nowDate.toString())
// 2022-08-15
console.log(nowTime.toString())
// 17:27:51.688660566
Enter fullscreen mode Exit fullscreen mode

Adding date, month, or year using the old Date methods is a huge pain. It's very simple to do this in Temporal.

const now = Temporal.Now.plainDateISO()

console.log(now.add({ days: 1, months: 1, years: 1 }).toString())
// 2023-09-16
Enter fullscreen mode Exit fullscreen mode

You can also do subtraction like this:

const now = Temporal.Now.plainDateISO()
console.log(now.subtract({ days: 1, months: 1, years: 1 }).toString())
// 2021-07-14
Enter fullscreen mode Exit fullscreen mode

These methods return a new date instead of modifying the date you're working on. This was implemented badly in the normal Date object. Because it returns a modified object rather than a new object, if you want to compare two dates, you can do this:

const now = Temporal.Now.plainDateISO()
const now2 = Temporal.Now.plainDateISO()

console.log(now.equals(now2))
// true
Enter fullscreen mode Exit fullscreen mode

If you want to calculate duration between two dates, you can do this in following way:

const now = Temporal.Now.plainDateISO()
const now2 = new Temporal.PlainDate(2022,1,1)

console.log(now.since(now2).toString())
// P226D
console.log(now.until(now2).toString())
// -P226D
Enter fullscreen mode Exit fullscreen mode

Both helper methods since and until help in finding the duration between two dates. Helper method with allows you to set a specific value. For example:

const now = Temporal.Now.plainDateISO()

console.log(now.with({ year: 2021 }).toString())
// 2021-08-15
Enter fullscreen mode Exit fullscreen mode

If you want to go into details of helper methods, you can check Temporal Docs.

So, based on these different types of planeDate, plainTime and plainDateTime, you can get very specific information. Also, if you care about time zones, You can do the following for a specific time zone of your choice.

const now = Temporal.Now.zonedDateTimeISO()

console.log(now.toString())
// 2022-08-15T17:37:00.986020984+05:00[Asia/Karachi]
Enter fullscreen mode Exit fullscreen mode

It puts the time zone at the end to show time with your current time zone. It's something you can't do very easily with a normal Date object. Conversion between time zones and non-time zones was very difficult to achieve. So, this Temporal.Now
the object has functions for getting the current date time, whatever you're looking for.

Temporal.PlainDate

If you want to get the exact date without time, You can do this:

const now = new Temporal.PlainDate(2022,8,8)

console.log(now.toString())
// 2022-08-08
Enter fullscreen mode Exit fullscreen mode

Another way to get a date is by calling a method called from:

const now = Temporal.PlainDate.from("2022-08-08")

console.log(now.toString())
// 2022-08-08

Enter fullscreen mode Exit fullscreen mode

You can also pass an object in the from method. You'll get the exact same result.

const now = Temporal.PlainDate.from({
    year: 2022,
    month: 8,
    day: 8
})

console.log(now.toString())
// 2022-08-08
Enter fullscreen mode Exit fullscreen mode

All of these allow you to define the date, time, or whatever. It's possible for all different time zones as well. You can do a zoned date-time like this:

const now = Temporal.ZonedDateTime.from({
    year: 2022,
    month: 8,
    day: 8,
    timeZone: Temporal.Now.timeZone()
})

console.log(now.toString())
// 2022-08-08T00:00:00+05:00[Asia/Karachi]
Enter fullscreen mode Exit fullscreen mode

You'll get year, month, and day in your specific time zone because you mentioned it. Those are part of the main data types you're going to use. If you want to sort dates, you can do like this:

const today = Temporal.Now.plainDateISO()
const yesterday = today.subtract({ days: 1})
const tomorrow = today.add({ days: 1})
const days = [today, yesterday, tomorrow]
const sortedDays = days.sort(Temporal.PlainDate.compare)

console.log(sortedDays.map(d => d.toString()))
//  ['2022-08-14', '2022-08-15', '2022-08-16']
Enter fullscreen mode Exit fullscreen mode

Temporal.Duration

This data type conveys the length or duration of time. This helps in dealing with the comparison of dates. You can build a new Duration with the constructor or from method.

const duration = Temporal.Duration.from({ days: 2, months: 8 })

console.log(duration.toString())
// P8M2D

Enter fullscreen mode Exit fullscreen mode

You can use round, with, subtract or add helper methods on Duration. total helper method calculates the whole duration in a specific unit.

const duration = Temporal.Duration.from({ hours: 12, minutes: 30 })

console.log(duration.total("minutes"))
// 750

Enter fullscreen mode Exit fullscreen mode

Temporal.TimeZone

This data type is used to show a specific time zone. You can use this in the following two ways:

const timeZone = Temporal.TimeZone.from('America/Chicago')

console.log(timeZone.toString())
// America/Chicago

const localTimeZone = Temporal.Now.timeZone()

console.log(localTimeZone.toString())
// Asia/Karachi
Enter fullscreen mode Exit fullscreen mode

There're various data types and helper methods available with Temporal. If you want to explore them, you can do it through Temporal Docs.

Browser Support for Temporal API

Now, after reading all this, you may get excited to start trying out the Temporal API. This API isn't available yet as the proposal for this API is at stage 3. No browser supports this API at the moment, but you can use polyfill if you want to try this API. Several polyfills are available for this API, but @js-temporal/polyfill is quite useful. You can immediately use this API, once you install this library.

Conclusion

Dates in JavaScript include multiple issues with the implementation. Temporal API solves this problem with easy-to-use APIs. JavaScript developers will find it helpful once browsers start supporting this API.

Writer: Muhammed Arslan Sarwar


discord banner

Build your React-based CRUD applications without constraints

Low-code React frameworks are great for gaining development speed but they often fall short of flexibility if you need extensive styling and customization for your project.

Check out refine, if you are interested in a headless framework you can use with any custom design or UI-Kit for 100% control over styling.


refine blog logo

refine is a React-based framework for building CRUD applications without constraints.
It can speed up your development time up to 3X without compromising freedom on styling, customization and project workflow.

refine is headless by design and it connects 30+ backend services out-of-the-box including custom REST and GraphQL API’s.

Visit refine GitHub repository for more information, demos, tutorials and example projects.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .