Get The Timezone Offset on Client side
One of the problems I had to solve recently involved handling Timezone and Date/Time data types. Whoever ever worked with both Timezones and Date/Time data types knows it is much much (much) harder than it looks!
For clarity, Let’s understand what is the difference between Timestamp and an Offset.
- A time zone is a place.
America/Los_angeles
is a timezone. - An offset is the number of hours or minutes a certain time zone is ahead of or behind GMT**
One of the services I worked on didn’t handle timestamp data types as expected.
- It didn’t query and/or display the right time on the UI (should display as per the user’s selected timezone and NOT as per the local machine)
- The service didn’t filter timestamp values as expected (it cares only for the date part and not the date and time)
- And the service didn’t care about Daytime concept (for example, on PST time it should calculate the time as -7 offset where on PDT time it needs to calculate as -8 offset).
The Database
Date/time types were stored in a UTC time. This is a great practice as it gives us one single truth and all you need to do is get those values and convert them to any timezone you’d like.
First thing I was needed to do was to change the query it made and get the timestamp columns in the user selected timezone.
That was easy enough and was needed some modifications to the query code.
The Backend
The backend uses a package for get requests that expects to get a timestamp value as a UTC format (i.e 2020-01-08T12:00:00Z
) in the get URL param. I couldn’t change it as if I did, I was needed to change the whole infrastructure of the service. When getting this value, it is impossible to convert it time to a different time zone as it refers to it as a UTC time. It is also hard to manipulate the value itself (and it is also weird to do it).
What I was needed to do is to send the timestamp from the client as a UTC format but with indication on the offset.
For example 2020-01-08T12:00:00-08:00
. With that, the Java code can convert this timestamp into a UTC-8 timezone.
The Frontend
With the backend limitations, I had to find a way on how to send a UTC timestamp (with the offset) to the back from the front.
Currently, all the front does is getting a timestamp from the server (the UTC time as it is - before the database query change), creates a new Date()
(while using JavaScript) and converts it to a readable format using moment package.
The front also has some limitations of its own.
- Although we were using
moment
library, we used a very old version - We didn’t use any npm so upgrading version created new problems and was impossible.
- Creating a date while using
new Date()
object, gets you to local time (your current machine time) and not a time in a specific timezone/area.
I could have solve it pretty easily if I was able to upgrade
moment
to the newest version and use moment-timezone
Displaying the correct time
That part was easy enough, after changing the DB query to get timestamp in a specific timezone, all I had to do was to use moment
to display the date in a giving format (no need to create any Date
object).
Filter and Query date and time
As you remember, I need to send a UTC time with an offset to the back. Which means I need somehow to get the date and time of a specific timezone that it is not the user local time (machine time).
I can have my machine set to America/Los_angeles
time but my dashboard would be set to Asia/Calcutta
time.
In addition, I must care about the daylight saving time concept.
While on March 8th the offset is -7, on Nov 1st the offset is -8.
Since I couldn’t use moment-timezone and couldn’t find any lightweight package to handle it, I was needed to come up with something on my own.
After digging around google and stackoverflow I came up with a working code to get a timestamp and its offset in a giving timezone using Javascript’s Date
object and some calculations and modifications.
- We need to have two values, the date and the timezone we want to find the offset of.
Offset Class
I created a class to handle the timezoneOffset calculations and modifications.
And this is how we can use the class with the values before.
getTimezoneOffset() — gets the offset time in hours. for our example, the offset in hours will be 5.5
convertNumberToTime()- this method gets the number getTimezoneOffset() generated, and convert it to a time format. So 5.5
will be 05:30
.
The time I get from the convertNumberToTime() function, I then add it to the date time I will send to the server.
The only thing left is to format the giving date value 01/08/2021 05:00:00 PM
to a UTC format. I used moment because I have already had this package, you can convert it using different options.
The final
variable is the one I am sending to the server, it will look like that 2021-01-08[T]17:00:00-05:30
.