The three types of time
Handling dates and times in code can be tricky. Understanding that there are three types of time, that play by different rules, can help prevent bugs and ensure your code behaves as intended.
Before I describe these three types of time, let’s warm up with a riddle.
Alice and Bob were born at the exact same moment in time, in neighbouring towns somewhere in Florida. They met in school and immediately bonded over the fact that they had existed for the exact same number of seconds. Their love — naturally — flourished, and many years later, Bob took Alice out to a fancy dinner and proposed. She thought about it for a full 30 seconds before finally saying “sure”. The waiter overheard and wasted no time in suggesting some Champagne. “I’m afraid that’s against the rules”, said Alice, “I’m 21 but Bob is only 20”.
How could this be?
If the answer isn’t obvious now, it should be by the time you’ve finished this article.
Before going any further, a quick terminology note: throughout this article I will use the word ‘time’ to refer to the fully qualified time (year, month, day, hour, minute, etc) of an event. It’s weird that English doesn’t have an unambiguous term for this.
OK, let’s look at the three types of time.
1. Instants
Imagine you’re up in the International Space Station. You take a photo looking down over Europe as the morning sun spreads across the continent. At what time was this photo taken? The event of taking the photograph happened outside the world of time zones (because you’re outside the world), so it doesn’t really make sense to speak about any particular local time.
This is an ‘instant in time’ that’s detached from any one location. When dealing with instants, the local time of the event — the time on a clock where the event originated — isn’t relevant to someone else viewing the time of the event.
Some more down-to-earth examples include the time associated with an update to a document, a post on social media, a comment on a blog, and so on.
This is probably the most common type of time dealt with in code.
Storing and displaying
Store as: UTC
Display as: Viewer’s local time zone
You should store these times as UTC. Of course, your application might also want to store where the event originated for other purposes. But that’s not information that needs to be baked into the time object that you store in a database.
When displaying an instant in some user-facing interface, you should convert to local time. Unless you want to get a bit fancy and display deltas like “2 minutes ago”. If you don’t have the opportunity to convert the times to another time zone (e.g. when looking at timestamps in a plain-text log file) then you’ll just have to display in UTC.
If you need to sort such times, this should probably be done in UTC, even when displaying in local time.
I really only mention this out of an abundance of caution. I mean, you should be able to convert all times to the local time zone and then sort, but unless you’re certain that folds of time are handled correctly (these occur when leaving daylight savings, when an hour repeats), it’s safer to sort in UTC.
By the way, the goal of this article is to give an understanding of the three types of time. For each time type I will mention some common use cases, but I won’t delve into every possible scenario. So for example if you know you’re dealing with an ‘instant’, but your use case requires converting it back to the time zone of the originating event for a specific purpose, I’m not suggesting you’re ‘doing it wrong’, I’m just not mentioning that case.
OK, that’s the easy one out of the way…
2. Local times
Let’s say you’re writing an application that will show the times of events for a chain of resorts. Surf lessons at 9 am daily at the Bahamas property, a kids puppet show at 3 pm on Sundays at the Malta property, and so on.
Each of these events start at a particular moment in time (like an instant) but unlike instants, the location of the event plays a crucial role.
When a user is viewing these times, wondering how to kill time while relaxing at one of your resorts, they’re thinking in the time zone of the resort, not the time zone where they sit at their computer.
So these times should be shown in the time zone of the event. Then the user can compare them to other activities in that same time zone (“we’ll grab some breakfast then go and fall off a surfboard quite a lot”).
Local times might describe events that can optionally be attended remotely, through the magic of the internet. Imagine you’re writing an application that shows class times for a university, and there’s the option to dial in to certain lectures for remote students.
In this case the event time in the user’s time zone becomes relevant. To allow for this, your interface should allow the user to see the time in their own time zone, since they will be comparing that time to other times in their own time zone (“I’ll dial in to the lecture after I put the kids to bed”).
So you can see there’s a blurred line between instants and local times. If you have a meeting where everyone is expected to dial in, it essentially has no location, so the start time is an ‘instant’. If at least a few people will be joining in person in a particular location, you might consider treating it as a ‘local time’.
As a general rule for working out which you’re dealing with, if you can say that the time zone of the sort of events you’re capturing is never relevant, you’ve got an instant, otherwise you’ve got a local time.
The distinction between instants and local times only matters in the case where some viewers of the time are in different time zones. So if all your users are in the same time zone, maybe you don’t need to worry.
But beware, this is a breeding ground for bugs. Applications that grow up in a single-time-zone home, then spread their wings into the wider world might soon find that all sorts of logic starts falling apart.
Storing and displaying
Store as: Event time zone
Display as: Event time zone
Local times should be stored as ‘time zone aware’ objects, with the event’s time zone embedded in the date/time object.
Yes, this goes against the usual advice of STORE ALL DATES IN UTC.
Alas, there are some big name databases that don’t support time zone aware objects. In that case you should store both the date in UTC and the time zone, and make sure your application layer does the necessary conversions (as close to the database as possible).
Front ends should ensure that they’re displaying the time in the event’s time zone, and preferably informing the user that the event’s local time is being shown (because — in case you hadn’t noticed — time zones can be confusing).
Sometimes it will be obvious just from the context, as with the 9 am surf lessons shown on a resort’s ‘activities’ page.
Care must be taken with notifications, too. Let’s say you want to send out notifications one hour before an event, to all registered participants. You might have a service running in the cloud somewhere on a machine with an unknown time zone. You’ll want to convert everything to UTC (the server’s time and the event times) to make comparisons and work out when to send events.
Your cloud-based servers should all have their time zones set to UTC, but it would be a brave move to rely on this in code that you deploy to them.
A caveat to these general recommendations: as pointed out in this excellent comment on Reddit, when you store a time with time zone component, things can get messy if something about that time zone changes (e.g. they stop doing daylight savings).
3. Glocal times
Like the concept of ‘glocalization’ from economics, this type of time has both global and local components. Unlike the other two types, glocal times aren’t related to any particular moment in time.
This one’s a bit tricky to explain, so stop thinking about how bad the name ‘glocal’ is and pay attention.
Picture yourself up in the ISS once again, watching the New Year’s fireworks going off at midnight. Looking down from space, this party is dragged out over 24 hours, rather than a single moment in time. But for any individual person (down on earth) the event starts at a specific time: midnight on the 1st of January.
Side note: there is no strong consensus on whether midnight is at the start or the end of a day. I’ll follow the majority and use it to mean the start of the day.
So, this type of time is global, in the sense that people in any time zone can experience the event, but also local, because the actual time of the event is localized to their time zone.
Another example: in 2024, Earth Hour starts at 8:30 pm on the 23rd of March (I forget when it ends). That time — 8:30 — is the same in whatever time zone you happen to be in. So it’s not an ‘instant’, because it happens at a different moment in time for each time zone. And it’s not a ‘local time’, because it doesn’t take place in a particular time zone.
I admit, these are pretty niche examples, and perhaps rarely stored in databases as date/time objects. So let’s turn to the main attraction, date of birth.
If you were born at 5 am in Sydney on the 5th of May, your birthday would be recorded as the 5th of May. Everybody with me?
But if you moved to London, you wouldn’t start celebrating your birthday on the 4th, even though it was the 4th of May in London when you popped out. That is, from the perspective of someone in London, you were born on the 4th. But you’ll continue to claim that you were born on the 5th, because only the local time where you were born matters. And that original, literal, local time applies anywhere on earth, it’s never translated into other time zones.
You might be thinking, is this really so different to local times? The answer is yes, because with glocal times, the time zone is irrelevant (and sometimes unknown) whereas with local times the time zone is a crucial component.
In practical terms, you’re not going to ask a user filling out a form to enter their date of birth and also the time zone in which they were born, right? You just want to know what date it was where/when they were born, without knowing where they were born.
Now, when it comes to knowing our birthday, we don’t give these things a second thought. But when storing this information in a database, it’s pretty easy to get wrong.
Storing and displaying
Store as: Time zone naive
Display as: Time zone naive
The ideal format for storing glocal times is a ‘time zone naive’ date/time object. That is, an object with no time zone component.
If your database, programming language, or data serialization format (e.g. JSON) doesn’t support time zone naive dates, you’ll need to pick from one of a few bad options:
- Store the date/time as an object with the time zone set to UTC, then try very hard to remember to always display the date/time in UTC, and honestly, just accept that one day someone will forget and you’ll have a bug.
- Store the date as a string or number, or even individual numbers for year, month and day.
A common trap when handling date of birth is to create a date/time object with year, month and day parts, save that date in a database as UTC, then later display the date in the viewer’s local time zone.
The end result is that if someone in a time zone to the west of the original user views the date of birth, it will show as the day before.
Here’s a step-by-step example showing how to get it wrong:
- A user in Sydney enters their date of birth into some web site as the 5th of May, 1955.
- A date object is created (in JavaScript) with just the year, month and day (hours and minutes default to zero, which means midnight). By default, the local time zone is used.
- This is serialized into JSON to send to a backend. JSON serialization converts dates to UTC, which will be 2 pm on the 4th of May, 1955. That’s midnight on the 5th, minus Sydney’s 10 hour offset.
- Later, this person’s friend in Syria looks at their profile. The date is loaded from the database, serialized to JSON for transport, and in the front end, converted to a date object in local time in Syria, which is UTC + 3 hours. That’s 5 pm on the 4th of May, 1955. The day before the true date of birth.
- Of course, the hour isn’t shown, but that’s not relevant, the end result is that anywhere with a smaller time zone offset than Sydney’s 10 hours will see the date of birth as the day before.
If this hurts your head a little bit, congratulations you’re a normal human being. Google something like “birthday shows as day before” and you’ll see a long history of bugs caused by the fact that this stuff is hard to think about. When it comes to matters of time, bugs are only a matter of time.
I have a funny feeling that this particular mistake will continue to be made for all eternity (or until everyone has read this article, whichever comes first).
What time type is this?
Now you know about the three types of time. But maybe you’re working with a time and it’s not clear which type it is. If so, perhaps this will make things easier:
Now let’s return to Alice and Bob…
The riddle, resolved
The story of Alice and Bob is a story of different time types.
The fact that Alice and Bob were born at the exact same moment is clearly a statement about Time Type 1, a single instant that can be associated with different local times based on where in the world you are.
Meanwhile, the statement about only one of them being 21 is based on dates of birth, which are Time Type 3, glocal times.
Florida has multiple time zones, which means every day there’s a period where it’s simultaneously two consecutive dates. For example 11:30 pm on a Tuesday in one town and 12:30 am on Wednesday in another.
So we can have two people born at the same moment, on two different dates, and therefore have different birth days.
Alice and Bob will just have to wait a day until they’re both 21 to legally celebrate with Champagne like the alcohol industry says they should.
Side note: I like to think of large language models as a sort of amalgamation of all human writings on a subject. So if the population at large is confused about an issue, that confusion tends to be reflected in the model’s responses.
So how does ChatGPT 4 do with the riddle of Alice and Bob? Well, it’s promising for a moment, but then the confusion sets in.
Bonus round: not so simultaneous
The following isn’t useful information, not even close, but it is interesting.
I’ve hinted at the idea that you can have an event that occurs at ‘the same time’ in multiple locations. But this is not exactly right. In practice, this is true enough, but if you want to get into the grittiest of the nitties, the concept of ‘same time, different place’ doesn’t actually make sense.
Let’s take a ride on Einstein’s train of thought…
Imagine a glass-walled train hurtling along a track, with a flood light at each end, pointing in toward the middle. The lights are turned off. Alice is standing in the middle of the train. Bob stands stationary at a station, watching Alice speed past, wondering if it was something he said. At the point where Alice and Bob are aligned — when they’re both an equal distance from each light — the lights switch on.
From Bob’s perspective, the light will travel, at the speed of itself, from each end of the train into his eyes and he will say that they turned on at the same time. In other words, he will observe the events of each light turning on to be simultaneous.
Alice, meanwhile, will have moved forwards a little teeny tiny bit between the time when the lights go on and the time when the light reaches her. She will have moved forward to meet the light from the front of the train and claim that she saw that light turn on first. In other words, she will observe the events to occur at different times.
And there’s nothing to say that Bob’s reference frame is more correct (we’re all hurtling through space, so no one in this story is ‘stationary’ in any meaningful sense).
Thus, simultaneity is relative, and the concept of absolute time doesn’t exist.
Interesting, right?
Hey, thanks for reading, have a special day.