Following on from my hard and easy way of getting timezone from an IP address, having the timezone (as text) is one thing, now finding the actual offset is entirely a different problem.
TL:DR; jump to the spoiler if you can't be bothered to read/listen to me ramble!
The problem isn't timezones, it's day light saving
It's all very well knowing what timezone a particularly location is sitting on. We can show the user the UTC time, but when it doesn't match the wall clock because they're currently observing DST, then it's just…weird.
So now we need to know if the location is observing DST, or not. Or if perhaps they never observe DST (like Hawaii).
The long hard way
There is the IANA timezone dataset which has custom data structures that describe the location and how time is observed in that location for that particular date. Which is very cool because you can say: for the Ukraine, in 1921 on Thursday 5th July - were they observing DST or not.
There's a library in Python that does read this data straight off the shelf, but I couldn't find anything for JavaScript, so I went about parsing it myself.
The documentation is generally pretty useful, describing the structures:
From the source file
#Rule NAME FROM TO - IN ON AT SAVE LETTER
Rule Chicago 1920 only - Jun 13 2:00 1:00 D
Rule Chicago 1920 1921 - Oct lastSun 2:00 0 S
Rule Chicago 1921 only - Mar lastSun 2:00 1:00 D
Rule Chicago 1922 1966 - Apr lastSun 2:00 1:00 D
Rule Chicago 1922 1954 - Sep lastSun 2:00 0 S
Rule Chicago 1955 1966 - Oct lastSun 2:00 0 S
Reformatted
From | To | On | At | Action | |
---|---|---|---|---|---|
1920 only | June 13th | 02:00 local | go to daylight saving time | ||
1920 | 1921 | last Sunday | in October | return to standard time | |
1921 only | in March | go to daylight saving time | |||
1922 | 1966 | in April | |||
1954 | in September | return to standard time | |||
1955 | 1966 | in October |
I got fairly far, but hadn't implemented the lastSun
, firstMon
, Sun>=8
syntax (do drop a comment if you think this library might be useful).
The reason I stopped was because I remembered there was a way in literally a single line of code: Temporals.
Temporal API: working with dates and times
The JavaScript Date
API is, in my own opinion, one of the worst parts of JavaScript. The temporal API does a massive overhaul of date and time processing, and, it so happens, it can give me whether a datetime is in DST for a given timezone.
Temporal.Now.instant().toZonedDateTimeISO("Europe/London").offset;
// => "+01:00"
Just like that, I've got my timezone offset lookup. Although, since both Node and Deno (since I was using Netlify Edge functions which use Deno) doesn't have the API natively, I need to load the polyfill first:
import { Temporal } from 'https://esm.sh/@js-temporal/polyfill';
And that was it. Two extra lines gave me the timezone offset: days-to-xmas (source).