My personal idea for API backend is to force (JavaScript or mobile) client to change every date input send in form/query parameters to UTC and change it back when reading output. This way backend stays as simple as possible and everything that needs to be done in code by said client is to deal with UTC + 1 local date/time representation - such solutions should be delivered by web browser/OS.
For example in JavaScript:
(new Date('9/27/2022 9:00:00 AM UTC')).toString()
// returns date time translated (timezone name),
// formatted by current browser locale
// and converted to local timezone
'Tue Sep 27 2022 12:00:00 GMT+0300 (czas wschodnioeuropejski letni)'
// wschodnioeuropejski -> eastern european
// letni -> summer
// i.e. EEST
For non-API backend, well … Good luck.
Of course there is nothing to scare you, working with timezone is not a big deal now, but as above some clients sooner or later would ask you for date formatting, support for other calendars or similar client-specific requirements, so it would definitely not end up with “one-line solution”.
Generally it makes sense to shift tz conversion to the edge as far as possible (view layer, if not the client itself), but making everything (just) UTC within the backend is not necessarily sufficient, see UTC is not Your Saviour – Random Notes. Depending on the usecase knowing the local time of things can be just as important as knowing the UTC version of it.
As for more practical advice. Elixir core can handle datetimes quite well today. I’d rather opt for more focused libraries rather than timex. Elixir core for the data types. For timezone database tzdata or tz. For datetime parsing (if needed) date_time_parser or datix. For datetime formatting either Calendar.strftime or ex_cldr. And for storage base ecto tools of tz_datetime if the timezone needs to be retained or future datetimes are handled.
As I’m storing future datetimes, I’m using ex_cldr, tz_datetime and tz.
To help user find the correct timezone, I’m filtering the timezone select using the country were the event will be held.
@LostKobrakai Well … You did not got me this time.
I was talking about changing support everything on backend to UTC + client timezone (one but not explicitly said)… I never suggested to use UTC for multiple timezone handling. To be precise I was talking about move unnecessary logic to client which solves said problems without extra libraries (see code example).
I never worked on “1 of 10” edge cases mentioned in linked article, so I don’t have strict opinion on it. If I would work on chart in linked article most probably I would not even work on date time.
defmodule Example do
defstruct ~w[day_num inserted_at hour name points]a
end
“Main” fields (i.e. day_num, hour and points) are important for graph.
The rest two fields are optional. inserted_at would be an UTC date time and under name could be anything like Tokyo or <shop name> in <city name>. With this I could manually preview edge cases of reported points like “jet lag” or “climate shock” in first days in new place like select * … where inserted_at > … and name = 'Tokyo' limit 720 (hours in 30 days).
Honestly I don’t see why in this case we need to work with any timezone when it’s not important from very start, so for me it’s not even topic about UTC vs local time.
@enkr1 As you can see above, depending on use case the solution could be completely different. Please give us a bit more information and we can give more precise ideas!
I don’t think the example in the article is to be taken too closely at face value. Often the concrete use cases data is meant to serve may not be known when starting to gather the data. Therefore I think it’s important to be aware of the discussed issue even if it’s not (yet) applicable to ones own requirements - replacing missing awareness with hopefully explicitly taken tradeoffs.
The article raises a very good point which I’d distill to “planetary universal time” vs. “human subjective time”. The author says they don’t want to see their various metrics (health included) in UTC and always want to observe them in terms of “what was the clock showing when I was doing this, regardless of where I was on the globe?” which I believe is very fair and reminded me of the problems around storing date/time both in past and future.
If I was trying to distill these into e.g. Elixir module name I’d probably go for PlanetaryDateTime and ClockDateTime or somesuch. Would help people differentiate. I think.
But whether the frontend should convert the date/times it receives from the backend is a whole different can of worms, one that gave me gray hairs several times.
Yeah, human language is hard. Much smarter people than me said that choosing the right word enables and empowers thinking about a problem. Sadly the reverse is even truer: choosing the wrong words cripples the potentially critical thought process about a problem.
No easy solution. Hence we all try and digest things into our own brain machine micro-code.