DEV Community

Kana
Kana

Posted on

Handle timezone with JavaScript

Date problem with JavaScript

When you handle with date, you use the Date() constructor.

You can get the current local time with this code.


const now = new Date()
console.log(now)
// Thu Feb 01 2024 14:29:03 GMT-0800 (Pacific Standard Time)

Enter fullscreen mode Exit fullscreen mode

It is not dangerous if you use it with your local machine.

However, we store the date in the database and display the date for users.

Date type from the database

So, let's compare these dates stored in the database to handle with JavaScript.

There are some date(and time) types in PostgreSQL.

1. date / DATE ex:'2024-01-01'
2. timestamp / TIMESTAMP ex: '2024-01-01T14:00:00'
3. timestamp with timezone / TIMESTAMPTZ ex: '2024-01-01T14:00:00+00:00'
Enter fullscreen mode Exit fullscreen mode

NOTE: I'll demonstrate everything based in Vancouver Canada, Pacific Standard Time (GMT-0800).

Convert into Date object.

const date = "2024-01-01"
const timestamp = "2024-01-01T14:00:00"
const timestamptz = "2024-01-01T14:00:00+00:00"

console.log(new Date(date))
// Sun Dec 31 2023 16:00:00 GMT-0800 (Pacific Standard Time)
console.log(new Date(timestamp))
// Mon Jan 01 2024 14:00:00 GMT-0800 (Pacific Standard Time)
console.log(new Date(timestamptz))
// Mon Jan 01 2024 06:00:00 GMT-0800 (Pacific Standard Time)

Enter fullscreen mode Exit fullscreen mode

They are very different! Let's see one by one.

date / DATE

const date = "2024-01-01"
console.log(new Date(date))
// Sun Dec 31 2023 16:00:00 GMT-0800 (Pacific Standard Time)
Enter fullscreen mode Exit fullscreen mode

This one is no time included. In this case, JavaScript interprets it as midnight in the local time zone, which is Pacific Standard Time (GMT-0800). 2024-01-01 is equal to 2024-01-01T00:00:00+00:00 in JavaScript Date.

timestamp / TIMESTAMP

const timestamp = "2024-01-01T14:00:00"
console.log(new Date(timestamp))
// Mon Jan 01 2024 14:00:00 GMT-0800 (Pacific Standard Time)
Enter fullscreen mode Exit fullscreen mode

There is no time zone in this case, so JavaScript interprets it as 14:00 PM in the local time zone.

timestamp with timezone / TIMESTAMPTZ

const timestamptz = "2024-01-01T14:00:00+00:00"
console.log(new Date(timestamptz))
// Mon Jan 01 2024 06:00:00 GMT-0800 (Pacific Standard Time)
Enter fullscreen mode Exit fullscreen mode

You pass the timezone in this case. JavaScript interprets it as 14:00 in the UTC time zone. The output shows the date and time in the local time zone, but the initial time zone information is considered, resulting in a difference.

So, in the database, timestamp with timezone will be the safer option because JavaScript automatically uses UTC(+00:00) to calculate the time to display for users (1) or convert it into a local timezone even though it's a different timezone (2).

How about a trip schedule app?

The above example with ISO8601 string of UTC offset (timezone) solves the problem if you want to show it with the user's local time. However, let's imagine a trip schedule app. You don't want to show the scheduled date depending on the user's location. You want to show the absolute scheduled date to users.

For example, this is the scenario.

  1. A user inputs date from as 2024/01/01 for a Paris Trip in a Trip Schedule app when the user is located in Japan.
  2. The user arrives in Paris and opens the app in Paris. The user wants to see the exact same date as she/he inputs before in Japan, which is 2024/1/1.

However, JavaScript Date always converts into the time depending on the user's browser's timezone.

We don't want that to happen obviously.

Use date-fns-tz library

So, to solve this problem, I used the date-fns-tz library.

const timestamptzJapan = "2024-01-01T00:00:00+09:00"
const dateObject = new Date(timestamptzJapan)

const userTimeZone = 'Asia/Tokyo';

const zonedDateTime = utcToZonedTime(dateObject, userTimeZone);

console.log(zonedDateTime)
// Mon Jan 01 2024 00:00:00 GMT-0800 (Pacific Standard Time)
Enter fullscreen mode Exit fullscreen mode

Even though I tried in Vancouver, I get the time in the Japan timezone. You can get the same date anywhere in the world.

If you actually get the date from a database, the time is already converted into your local zone. But no worries, it is the same. You can get Japan time if you use utcToZonedTime and pass the timezone.

// A user input 2024/1/1 00:00, and the value below was sent to the server.
const timestamptzJapan = "2024-01-01T00:00:00+09:00"

// You get the below date from DB if you're in Vancouver.
const dateData = database.date
// 2023-12-31T15:00:00+00:00

const dateObject = new Date(dateData)

const userTimeZone = 'Asia/Tokyo';

const zonedDateTime = utcToZonedTime(dateObject, userTimeZone);

console.log(zonedDateTime)
// Mon Jan 01 2024 00:00:00 GMT-0800 (Pacific Standard Time)
Enter fullscreen mode Exit fullscreen mode

Just be careful, you need to pass the same timezone UTC offset and timezone as the second argument. In this case, +09:00 and Asia/Tokyo.

Conclusion

I actually didn't have any critical issues with Date handling before, but this time, I struggled with timezone handling for the worldwide app. Even if you use date-fns or some other libraries, when you try to convert into a Date object with new Date(), you may see a different result from what you expect.

  • For the server, timestamp with the timezone is better and store ISO string with UTC offset.
  • If you want to convert into a specific timezone, date-fns-tz library is helpful

Top comments (0)