Handle timezone with JavaScript
Tags: javascript
Published: 2024-02-02 09:13:18

## Date problem with JavaScript

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

You can get the current local time with this code.

```javascript

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

```
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'
```

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

Convert into Date object.

```javascript
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)

```

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

① **date / DATE**

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

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

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

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

```javascript
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)
```

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.


```javascript
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)
```

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.

```javascript
// 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)
```

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