Navigating the timezone nightmare in product development
getlago.com
getlago.com
DST was once supposed to save energy, but my own personal frustration with it alone could warm the Earth's atmosphere by a whole degree Celsius.
It involved:
- the day of the week (office closed on weekends)
- day of the year, with leap years (office closed during holidays)
- Easter day (some holidays are based on Easter)
- DST and timezones (office hours are in local time, timestamps are UTC)
Thankfully, no Julian calendar or leap seconds to deal with.
- Instant - a point in monotonously increasing time (Unix timestamp is usually a good enough approximation for most cases)
- Calendar
- Wallclock - non-monotonous human-readable clock
Being precise about which entity is used is enough to resolve most of the confusions.
For example, scheduling a doctor appointment is always Calender + Wallclock in a location of doctor's office. No Instant should be used to record this, and changing of DST rules for this location shouldn't affect the appointment. DST rules only matter if we want to convert from one Calendar and Wallclock to the other, then Instant may be used internally in calculations.
Back to the article: if we are talking about subscriptions, then we should specify, if subscription is valid for time interval of 365*24*60*60 seconds or the expiry is tied to Calendar+Wallclock, but in this case Calendar+Wallclock should have a specific location. The first option is much easier to implement, and to avoid any timezone/DST frustration adding an extra day of subscription (366 instead of 365) will be enough.
My anecdote: when I was working for a B2C startup we had to ensure we billed customers on the correct date, like OP. Timezones are hard; dates are easy (or so we thought). When we billed a customer on their billing date we had to attempt to take payment at a time, which meant that our naive date handling converted that date into midnight UTC on that date, causing many western European customers to be billed at 23:00 or earlier on the previous day from their perspective.
Furthermore, from the operations side we were often dealing things that happened "on a date". I was pushing for at least our internal customer service systems to present two timestamps to agents: the date and time at which the thing occurred in the place that event occurred and also the date and time at which the thing occurred in the customer's location. For example, something being changed about a customer's account at 23:55 in London on a Monday actually happened at 00:55 on Tuesday for the customer in France. However, the timezone information was either not stored or not presented, interfaces were not consistent, and the result was pot luck whether the customer or a member of the customer service team would see Monday or Tuesday.
Timezones are hard. Presenting that information in a contextually appropriate way to your own employees and customers can be just as hard.
I like that the authors of the article have reached similar conclusions, especially around "dates have timezones". I think datetime capture and presentation is a fantastic UX topic.
For easier math let's say your business is in GMT tz. People in the Line Islands (Pacific/Kiritimati) will have access to the sale 14 hours before yourself. Then the sale-time occurs in GMT, 24 hours pass, and the sale ends in GMT. But people in American Somoa (Pacific/Midway) will still have the sale active for 11 hours. (Technically someone using satellite internet in the open ocean east of Samoa has 12 hours, but the UTC+12 timezone is completely uninhabited).
Such a sale is kind of a farfetched example, but I've encountered this issue when trying to do analytics reports looking at user data that happens on specific global holidays.
It was quite surreal, although time wise I think the LA person was up early on Tuesday and I was up late.
It's also funny how some of the group is having coffee and breakfast while other members are getting drunk and having midnight snacks.
I now have an app that runs continuously in my menu bar to track all the different time zones that I care about. Tel Aviv and Tokyo also figure into the equation sometimes.
New Zealand would like a word.
Timezones are not immutable, and timezone database updates happen every year. Only if you track dates that happen in the past UTC makes sense.
In some cases/jurisdictions they change DST quite late so you'll only know with certainty what UTC time corresponds with what local time a few weeks in advance.
To be specific, it's "whenever the desk-calendars and wall-clocks in that jurisdiction will say X because the local government says so."
The government of Bizarro São Paulo could decide to pause the clocks at 1:00PM, wait for one sunset and one sunrise, then set their clocks to 12:00PM, and then advance it by one "minute" every time a rooster crows until it reaches 12:10pm at which point they skip straight to 3:00pm.
When is your schedule your 2PM wall-clock meeting? Probably around the tenth rooster-crow. If you had reason to distrust the clock-culture of Bizarro São Paulo, you shoulda made it a different timezone. :P
When the event happens you record the TAI. You may also wish to record the context sensitive date for auditing purposes, but it is not strictly necessary. You can rederive the occurred date if the event occurred in the past.
For example, if there's a lunchtime event in Bizarro São Paulo you record "Noon in Bizarro Brazil Time" or even ("Noon in whatever timezone that office building will exist in") because it really does depend on the rhythm of the city. In contrast, if it's an international video-conference, you might record it as a time in UTC or the timezone/city of the most-critical participants.
In both cases, users of the system should be able to see the "contract" along with the predicted moment in a probably-useful local representation. (I might not be in Bizarro São Paulo while I'm looking at the event, but I might know I'll be flying there later...)
If you're afraid a Bizarro-govt is going to do something weird at the last second and cause all sorts of customer complaints for missed events, you might code a system that keeps track of when predicted-times (in something safer like UTC or TAI) suddenly change for events in a way that might catch users by surprise, and then send out notices.
Whenever you get new rules, you need to look at at least all future events and see if their UTC offset changed and then decide what to do about it. Often the right thing to do is just adjust the UTC offset based on the new rules; but sometimes you might want to ask the user, or maybe just notify the user: hey, we got new DST rules, please confirm these modified events: [list]. Users don't always input times accurately[1], so a heads up lets them review the modified dates and update the events that were modified in a way that doesn't reflect their actual intent.
You might also want to look at past events and maybe also notify users that the rules changed, and you're sorry about any inconvenience because you didn't get the rules or didn't process them until after the event.
[1] If I'm planning to watch a sporting event on TV, I'm most likely to input it into my calendar in my local time, but the event is most likely scheduled in local time at the event. But not necessarily. IMHO, the closer to the time change the event is, the more important it is to get user feedback.
Counterintuitively, this is not true for the past and present. A specific second is unique. As long as you know the second you can derive the exact date (in the past) it occurred in whatever civil time standard you are using. The past and present should always be stored in TAI. The future should usually be stored as “pattern-matching conditions” (though you can use TAI if you are recording a elapsed time/seconds until the event).
For example - 5 days notice for a DST change.
In my opinion, it is better to just store UTC when you can't possibly make the date right in advance for all users in all timezones anyway.
And if everyone does this, hopefully it discourages government from changing the timezone DB frivolously and without spending a lot of money broadcasting the changes to anyone that may be affected.
Continent/City are not friendly names, they are political boundaries that gice more precision. For example, CET covers many countries that might decide to stop applying DST at different points in time. If you store CET in your database you won't know if you need to apply CEST or not. This is why you always need the Continent/City form if you want to be future proof (and past proof)
You can’t always be future proof.
There's quite a few other non-slash-having names out there:
ls -pL /usr/share/zoneinfo | grep -v '/'
"Eire" is in there, for instance, to deal with software that assumes that the "is_dst" half of the year is during the (northern) summer, but Ireland technically does it the other way around -- a distinction relevant only to computers.https://github.com/eggert/tz/blob/c3e966c59b02b1f47f0b7b0e4a...
The only other timezone that currently has a non-1h offset for DST -- Ireland's is -1 hours -- is Australia/Lord_Howe, which has a 30-min positive leap.
Edit: there are also tzdb entries of the form "a/b/c" -- America/Kentucky/Louisville --- though they are not commonly used in practice.
New Zealand users are now mad at you :D
I happen to be traveling currently.
When I log into the forum from my location, which is one hour away time zone wise from the country the forum is from, and I make a post, I then see the timestamp for my own post presented as “in 59 minutes”.
I reported the bug, but they didn’t fix it yet. I still find it hilarious.
I happen to know that the owner of the forum is planning to go abroad sometime in January. If he does he will surely see this weirdness himself firsthand when he posts to his forum. Maybe then, once he gets to see it himself, a fix will be prioritised :p
JS has the ability to see system time zone offset.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
It’s not difficult to send the time zone in UTC, and convert it client side to local time zone.
And since they do “x minutes ago” kind of things they are certainly using a library. They are probably passing in “naive” timestamps without TZ info into a library that is perfectly able to handle it correctly for them, had they just read the docs for the library they used and taken a moment to make sure that they include TZ info.
And if everything was done server side it would likewise be similarly easy to get it right because then my own time zone does not matter.
Early on there was a bug due to timezone handling where the job would close an hour too early.
No big deal one would think - the job is open for weeks, maybe months, so who cares if it closes at 11pm on the last day instead of midnight?
It turns out that a lot of people live their lives by the "last minute" principle. They want to do things at the very last minute, and they get furious when the last minute comes too soon.
Also working with dates, times and timezones inspired me to get an ISO8601 vanity plate for my car.
2) All events will trigger at UTC+0 time. Notify users on expiring events 24 hours before the event is triggered. Specify in contracts & EULAs that all events will occur on UTC+0 time.
3) "Soft expiry / leniency periods", wherein X amount of time is given after the event trigger in the "rare" cases where customers are late to respond to events. Do be warned though that customers will eventually treat this leniency period as if the expiry didn't happen, and some will inevitably complain when they can't do Y because they delayed well past the leniency period.
1. Store all dates/times in UTC. This way, you know at least know exactly what point in time the data represents.
2. Display in the user timezone as needed
3. Delegate handling of time manipulation to an external library (like Lumen). This way you don't have to deal with all the intricacies of understanding international law and geopolitics required to turn timestamps into actual real life event
https://en.wikipedia.org/wiki/Tz_database
https://www.iana.org/time-zones
I think of this as "difficulty snap back": Things can only get so difficult before everyone punts and uses some external library.
For example, carefully consider when events need to happen at a fixed time relative to server time (utc) vs user local time. Consider how you handle changes to the timezone database. A timezone change can cause the scheduled time of an event (such as billing) to not exist in that time zone, or for a scheduled time to occur twice. A user changing their timezone setting can cause a similar effect.
Bada bing, bada boom.
AWS, do. fucking. better. I know you have the resources for it.