The Time.here function in elm/time has the following note:
[…] This means the Zone you get from this function will act weird if (1) an application stays open across a Daylight Saving Time boundary or (2) you try to use it on historical data.
I assume this applies to future dates as well? Time.here calculates the offset using -(new Date().getTimezoneOffset()) which means that you get the current offset. To get the offset of a timestamp in the future, I believe I need to provide new Date with the timestamp like this:
-(new Date(1638313199).getTimezoneOffset())
First question: Is my assumption correct?
Second question: Have you solved this problem in another way?
If you need to model something like “this should happen exactly 24 hours from now” (an absolute amount of time after a past point) then you can calculate the Unix timestamp (seconds since 1970 or whatever) and store that.
If you need to model something like “15:00 on 2023-02-20” (a certain wall clock time in the future) then you also need to think about where in addition to when. Let’s say this is in Stockholm, Sweden. Then you could store “15:00 on 2023-02-20 in Stockholm/Sweden”. You can’t, however, store “15:00 on 2023-02-20 at UTC+1”. Well you could, but there has been talk about switching to summer time all year around in Sweden, which would be UTC+2. You can’t know what time zone will be used at a certain place in the future, so it’s better to store the place, I’d say.
Also don’t forget that some countries have multiple time zones, so it’s important to save a city as well.
I’m not sure if this helps, but those were some things I thought of!
In the ellie app, I simulate Time.here of today, 2021-10-14, in Sweden (GMT+2 or 120 minutes).
I want to display the month “Nov” from 1638313199 (Tue Nov 30 2021 23:59:59 GMT+0100).
This fails since Time.toMonth uses the current offset of 120 instead of the correct 60 (It’s wintertime on 2021-11-30 Sweden)
Now, one way to solve this is to have a Time.hereFromTimestamp function that takes my timestamp into account. I was hoping that more people would have had this problem before and could give me some input on how solve this problem.
As far as I know there is no time zone data in the browser. Just the current time zone and UTC. (There might be some API coming, but I don’t think there’s any as of now.)
You can try using timezone-data 5.1.0 which contains all time zones in the IANA Database.
If you just need to support Sweden you could try to calculate when summer time starts and ends each year. I did that in SQL quite recently and it was doable but a bit fiddly.
The Time.customZone function you are using accepts a list of offsets along with timestamps for when the that offset takes effect. These can be for both historical or future changes.
For example you might do:
swedishTime : Time.Zone
swedishTime =
Time.customZone 120
[ { start = 27261180, offset = 60 } -- after Oct 31, 2021
, { start = 27036180, offset = 120 } -- after May 28, 2021
]
Do note that the values for future time are subject to change at any moment (e.g. the government might decide to skip daylight savings time this year, or it might decide to change timezones).
Note though that the rule in Sweden is that summer time starts the last Sunday of March and ends the last Sunday of October. So the dates in your example are not correct, and would have to be calculated anyway.
I don’t think I need to calculate the future offset.
I might be missing something but wouldn’t this be sufficient? The first line is basically what Time.here does. I can use ports in order to run the later one but I wonder if there is something I am missing?
Good find! This issue is spot on, Time.here is indeed actually Time.hereAndNow.
I’ve pondered this issue for a few days and there are a few options from what I can understand:
1. Let the backend provide the timezone offset and every change reasonably far from now(), both future and past. Feed it to Time.customZone.
Doable but fiddly as you say. Could use the min and max timestamp from the database result to know what a reasonable timeframe is. Not the most attractive solution in my opinion. The request must include a timezone (i.e. “Europe/Stockholm”), a logged-in user setting, or a fallback. Intl.DateTimeFormat().resolvedOptions().timeZone is supported in all evergreen browsers.
2. Let the backend respond with a tuple of timestamp and offset instead of just the timestamp.
Maybe a bit simpler at the first glance. Again, the request must include a timezone (i.e. “Europe/Stockholm”), a logged-in user setting, or a fallback.
3. Let a port calculate the correct offset for every timestamp
Doable but it seems like too much work, I would prefer to have the offset included in the decoded response instead of running every entry through a port as an afterthought.
4. Hand the timestamp off to a custom element like github/time-elements
The most attractive option to me right now. Intl has enough support for my use case and I like the idea of letting the browser do the hard part. The backend can stay completely unchanged. Unfortunately, github/time-elements only seem to handle ISO 8601 timestamps. The first thing they do though is to transform the string into a UNIX timestamp. Most probably their backend returns timestamps as ISO 8601.