Dealing with Dates and Timezones
How to store, display, and work with date and timezone data in your web applications
Table of contents
Since the dawn of time (pun intended), timezones have always been a confusing concept to wrap around. It's been a recurring issue at Prosple especially when new developers join our ranks.
So we've finally decided to address this once and for all.
Here are rules of thumb that serve as guidance for our engineers in determining how to handle timezones in their respective applications. I'm sharing this publicly as I feel that this can probably help in solving most of the timezone issues plaguing developers the world over.
Backend
APIs and Storage
For simplicity, backend APIs should always live and breathe in UTC: It receives dates in UTC, stores dates in UTC, and responds with dates in UTC. Backend just also simply stores any timezone data associated to the date.
No conversion logic happens in backend API request and response and during storage.
Time-Sensitive Processes
For time-sensitive backend processes, like schedules and cron jobs, the raw UTC date is treated as if it's in its associated timezone, then adjusted according to the server's local timezone.
{
"datetime": "2024-07-04T11:41:25.793Z",
"timezone": "Asia/Manila"
}
In this example, the date stored in the database is in UTC, but the stored timezone is in Manila (UTC+8). This should be treated as Thu Jul 04 2024 11:41:25 UTC+0800 (Philippine Standard Time)
before converting to the server's local timezone.
Frontend Applications
This will come down to whether we allow users to personalize their timezones or not.
If Users Are NOT Allowed to Personalize Their Timezones
These Apps should display dates in the browser's local timezone.
That said, Frontend Apps should send and receive dates in UTC to and from Backend APIs, regardless of the browser timezone.
Hence, the conversion between UTC and browser local timezone is executed in the frontend code.
If the date is received with an associated timezone, the raw date is treated as if it's in the provided timezone, then adjusted to the browser timezone accordingly.
{
"datetime": "2024-07-04T11:41:25.793Z",
"timezone": "Asia/Manila"
}
In this example, the date received from the API is in UTC, but the timezone is in Manila (UTC+8). This should be treated as Thu Jul 04 2024 11:41:25 UTC+0800 (Philippine Standard Time)
before converting to browser local timezone.
If Users Are Allowed to Personalize Their Timezones
These Apps should display dates in the user's preferred timezone.
That said, Frontend Apps should send and receive dates in UTC to and from Backend APIs, regardless of the selected timezone.
Hence, the conversion between UTC and user's personalized timezone is STILL executed in the frontend code.
If the date is received with an associated timezone, the raw date is treated as if it's in the provided timezone, then adjusted to the user's preferred timezone accordingly.
{
"datetime": "2024-07-04T11:41:25.793Z",
"timezone": "Asia/Manila"
}
In this example, the date received from the API is in UTC, but the timezone is in Manila. This should be treated as Thu Jul 04 2024 11:41:25 UTC+0800 (Philippine Standard Time)
. If the user's preferred timezone is Asia/Hanoi
(UTC+7), the time is displayed as Thu Jul 04 2024 10:41:25
, regardless of the browser timezone.
Forms that Have Date and Timezone Fields
Forms and UI with timezone-tagged dates should always display dates in UTC. But never display them without the associated timezone data. Or else, user loses the context.
For example, if we have an API response of:
{
"datetime": "2024-07-04T11:41:25.793Z",
"timezone": "Asia/Manila"
}
The date is in UTC, but the timezone is in Manila. This should be displayed in the frontend as if the raw date is in the Manila Timezone:
2024-07-04T11:41:25.793Z
-> July 4, 2024 11:41AM Manila Time
Form dates are also submitted in UTC, but should always be accompanied with a separate timezone value.
Be careful not to let the browser convert the dates into local time, or the form will end up in timezone conversion hell. For example, say user lives in Manila.
Browser receives UTC:
2024-07-04T11:41:25.793Z
Browser converts it to local time (adds 8 hours):
2024-07-04T19:41:25.793Z
Form is submitted.
Server saves it in UTC:
2024-07-04T19:41:25.793Z
User refreshes page.
Browser receives UTC:
2024-07-04T19:41:25.793Z
Browser converts it to local time (adds another 8 hours):
2024-07-05T03:41:25.793Z
Talk about time-traveling. ๐คฃ This may or may not be based on experience.
But How About Isomorphic Applications?
Isomorphic apps are frontend apps that may render both server- and/or client-side.
Same rules still hold true. Server-Side Rendering happens on the server, so things there should always be in UTC.
Timezone adjustments should always happen on the browser, so in the case of NextJS for example, this should happen after hydration. One solution is to perform the adjustment inside useEffect, making sure to only execute when the browser window object is available.
Mind Your Use Cases
As with all things in software engineering, these rules will not cover all use cases. So adopt them with care.
Summary
Whew! That was nasty. But such is the joy of working with timezones.
In conclusion, by adhering to these guidelines for handling timezones, we can ensure consistency and accuracy across our web applications. Whether dealing with backend services, user-facing frontends, or isomorphic applications, maintaining a clear strategy for timezone management will help avoid common pitfalls and improve the overall user experience. Remember, while these rules are robust, always consider the specific needs of your project to achieve the best results.
Footer Notes
Are you a Filipino aspiring to shift careers into the tech industry? Join us at https://www.techcareershifter.com.
I also host Kuya Dev Podcast: a podcast for Filipino Tech Professionals, Aspirants, and Career Shifters.