A project team is managing a site for people to see events in their local community. The client asks the team to make a (seemingly) pretty simple feature; they want logged-in users to be able to make their own events. The site already lets admins do this, so it shouldn’t be too bad. The team agrees it should take about two days of dev work, assign it, and move on. Cut to two weeks later but the work still isn’t done. The client is getting impatient, the project manager is burning good will, and the dev is in a corner still working on the feature and muttering to themselves about time zones and unix.
If you’ve spent an appreciable amount of time in this industry then you’ve almost certainly run into a situation like this. So why is it so common? Time is an essential part of daily life so ordinary that we humans hardly give it a second thought. However, for computers, time is an arbitrary exception-filled mess. There is a huge disconnect between how humans and computers interact with time, and that disconnect causes us to massively underestimate the complexity of time-related features. Unfortunately, this complexity isn’t going to change, so we have to learn to deal with it. This first post of a two-part series will explain why programming for time is so complex. The second post will be a summary of how time works in Drupal and the best practices for working with it.
Try it at home
I want to try a thought experiment to simulate programming around time. Your task is to take a provided start time and end time, and figure out the time difference between them. For example, given 7:00 am 4/12/2022 to 8:00 am 4/12/2022, you can intuit that the difference is one hour. Now do the same with the following values:
7:45 am 4/12/2022 to 8:15 am 4/12/2022
7:43 am 4/12/2022 to 8:07 am 4/13/2022
7:41 am 4/12/2022 to 3:06 pm 4/14/2022
The task ramps up in complexity but should be doable for most people considering we make these kinds of calculations all the time. You probably took different approaches for each problem which makes sense. However, what if you were asked to write down a SINGLE sequence of steps that could take ANY of these different value pairs and still give the correct result? Tricky, but still doable. Now for the final challenge. The same previous conditions apply, but you’re limited to the arithmetic that a basic calculator can do. Sure, you know that there are 30 minutes between 7:45 am and 8:15am, but how would you get a calculator to give you that result? What if one input is in am and one is in pm? Did your head explode? Well, put it back together because...how about now the times are provided in two different time zones? Oh, and one of them is in daylight savings!
So on and so forth. Welcome to programming for time.
Real world problems
So far I’ve only given you hypotheticals, but I have encountered this in the real world. I once was working on fixing some visual problems with a calendar when I noticed something strange. Each day/date pairing was off by one, for example if I was looking at Monday April 12th, 2022 this calendar would say that day was Tuesday April 12th, 2022. I started looking into this hand-coded calendar and the logic looked reasonable. In fact I knew the developer who had worked on it and I knew I could generally trust them to do good work. Furthermore, this feature had been around for years and somehow no one had noticed it the days being off. After wracking my brain it hit me. The calendar was programmed in 2017, I was looking at it in 2020. When the original dev built the calendar, they didn’t take leap-years into account. This is a totally reasonable oversight to make, and a lot of devs (myself included) would have likely done the same thing.
Fortunately for us, programmers have been wrestling with these problems since the beginning of modern computing, which means we have a broad set of tools and standards to make this easier. Even if you aren’t a developer it’s worth having a basic understanding of how computers solve time.
Unix Time and UTC
The first clever solution to the time puzzle is the magical date of January 1st, 1970. This was the date chosen to be the beginning of Unix, a system for representing a specific point in time. For example, I am writing this sentence at 1649805591 Unix time which simply means that 1,649,805,591 seconds have elapsed since January 1st, 1970. Unix time is obviously impractical for human use, but it’s great for computers. Remember that earlier problem of telling the time difference between 7:41 am 4/12/2022 and 3:06 pm 4/14/2022 and how much of a nightmare that is with just a calculator? Well with Unix, that range translates to 1649749260 and 1649948760, two numbers that you can simply subtract to get the difference in seconds (199500) and convert into minutes and hours from there. Modern programming languages have some kind of date function that can translate various human-readable strings into a unix timestamp.
Unix time does a lot of heavy lifting, but as soon as you have to calculate around multiple time zones it all becomes a nightmare again. My petition for the entire world to operate on Pacific Standard Time like I do hasn’t gained any traction, so in the meantime we have to use UTC and offsets. UTC, which stands for Coordinated Universal Time, is the time at 0° longitude/The Prime Meridian/Greenwich England. It’s the universal time that the world runs on, and has a long and storied history that predates computing and explains why the acronym doesn’t quite work. The key benefit of UTC is that you can accurately get and compare time in different places around the world by simply adding or subtracting the appropriate offset from UTC. For example, I’m in Portland Oregon, which is at UTC -7 hours (or -8 hours depending on daylight savings), whereas someone in Berlin is UTC +2. The +/- number of hours is the offset and it’s directly proportional to the distance and direction away from Prime Meridian.
Better, but not perfect
By storing time as Unix Timestamp in UTC time in the database, programmers can get around a lot of the aforementioned problems with calculating time. Then the time displayed to the actual user is adjusted based on their local timezone. Even with these tools though, there are still complexities. Unix doesn’t account for leap seconds. Time zones change and don’t line up neatly with geography. Daylight savings isn’t used consistently even within the same countries. Developers can still mess up in subtle ways like not accounting for the day being different if the offset difference is big enough (8pm on 4/1 in Portland Oregon is 3am 4/2 in UTC). The list goes on.
Next time, about time and Drupal
If you take nothing else away from this post it should be the following: when you work with time, expect the task to be more complicated and labor-intensive than you initially think. You will fare better in the task if you have an understanding of how computers deal with time. Where possible, stay away from trying to do time calculations yourself and lean on existing battle-tested libraries and functions. Stay tuned for Part 2 where I explain how to deal with time in Drupal.