26 March 2021
Solving Timezones With Custom Elements
High on the list of every developer’s favorite things to work on are timezone issues. It’s an issue that seems to come up in some form on almost every project. On my current project, I tried an approach using Custom Elements. It seemed like such a simple way to solve the problem that I extracted it into an npm: datetime-utc-elements.
The basic approach
- Store times as UTC.
- Display them in the user’s time zone
- Profit!
The idea here is hopefully pretty simple. We store our dates in UTC, and use custom elements to display dates and times to the user in their browser’s time zone. This means that the server never sends or receives anything other than UTC. We leverage the Intl.DateTimeFormat
api to get the user’s time zone, and the excellent date-fns
library to convert to UTC when we send and receive it. Finally, we use the built in date time editing of our browser by using an <input type="datetime-local">
.
Two custom elements work together to implement our solution:
<datetime-utc-input>
This is a custom element which renders a datetime-local input and hidden field which is kept in sync and stores the date as UTC. It takes 2 attributes:
- name - used as the name attribute for the hidden field
- value - an initial value, if desired, in ISO format
<datetime-utc-output>
This element is responsible for taking a UTC datetime and displaying it in the browser timezone. It takes 2 attributes as well:
- datetime - string in ISO format
- format - string specifying format. Uses the format specified in
date-fns
here.
Usage
npm install datetime-utc-elements
In your javascript
import 'datetime-utc-elements';
Lastly, here is a video of me describing the motivations around it and showing an early version of the code:
Update!
Last minute update as I wrapped this post up: I hadn’t realized that form associated custom elements were as far along as they are until I read this post about it. It seems like there is a reasonable polyfill, and it would make a lot of sense to rework this element to be a proper honest to goodness form element. Look for that in the next version :)