Working with Timezones using date-fns and date-fns-tz

Aug 2, 2023

Date-fns has a sibling library date-fns-tz that helps you work with timezones in JavaScript, including formatting dates in a specific timezone.

For example, the following is how you can format a given date in Tahiti time with date-fns-tz:

// 12pm UTC on August 8, 2023
const date = new Date('2023-08-02T12:00:00.000Z');

const { formatInTimeZone } = require('date-fns-tz');
// "2023-08-02 02:00AM", 10 hours behind UTC
formatInTimeZone(date, 'Pacific/Tahiti', 'yyyy-MM-dd HH:mma');

Converting to Different Timezones

Date-fns-tz also has a utcToZonedTime() helper that converts a date that would render as the correct time when printed in JavaScript.

const date = new Date('2023-08-02T12:00:00.000Z');

const { utcToZonedTime } = require('date-fns-tz');
// Returns a date where the current `getHours()` is 2 to line up
// with Tahiti time:
// "Wed Aug 02 2023 02:00:00 GMT-0400 (Eastern Daylight Time)"
utcToZonedTime(date, 'Pacific/Tahiti').toString();

However, we strongly advise against using utcToZonedTime(). Notice that utcToZonedTime() doesn't change the date's timezone, in the above example JavaScript still prints out "Eastern Daylight Time", which is the timezone my computer was in when I ran the above example. So while you'll get the correct getHours(), look at what happens when you use toISOString():

// "2023-08-02T06:00:00.000Z"
utcToZonedTime(date, 'Pacific/Tahiti').toISOString();

The actual underlying time is different. So if you use utcToZonedTime(), you need to be extremely careful to not pass the converted date via JSON, because you'll end up serializing the wrong time.

// {"date":"2023-08-02T06:00:00.000Z"}
JSON.stringify({ date: utcToZonedTime(date, 'Pacific/Tahiti') })

Instead of using utcToZonedTime(), store the time and the timezone you want to display, and use formatInTimeZone().

Vanilla JS Alternatives

While we often use date-fns for convenience, you don't need date-fns to do basic tasks like formatting dates in common timezones. In modern JavaScript runtimes, dates have a toLocaleString() function that has good support for timezones. While there is no formal specification for which timezones each runtime supports, we haven't run into a case where a JavaScript runtime doesn't support a timezone that we want to use.

For example, the following displays a given date in Ulaanbataar time.

// 8am UTC on August 8, 2023
const date = new Date('2023-08-02T08:00:00.000Z');

// "8/2/2023, 4:00:00 PM", 8 hours ahead of UTC
date.toLocaleString('en-US', { timeZone: 'Asia/Ulaanbaatar' });

Did you find this tutorial useful? Say thanks by starring our repo on GitHub!