How to group time zones

Intro

In the following paragraphs I will discuss how to effectively group similar time zones. First I will introduce a definition of what is meant with “similar” time zones and then present the approach that me and my team came up with in the end.

Recap

In my last article, I presented our approach to rebuild the time zone picker that our customers are using. I started with a short competitor analysis / discovery and from that I derived the final solution that is now live in production:

Our new approach to show grouped timezones.

The “LMGTF” approach

Now, given that our designer presented us the above version, we were not sure how to calculate the grouped time zones. 🤔

Off we were back to square one.

Though it felt a little bit like having the NIH syndrome, we had to come up with an own solution to the problem.

Definition of “Similarity”

Before we started, we first had to zoom out and define by which rules we actually want to group time zones. Only then we could come back to the task and create the algorithm for this:

  1. are on the same continent (🤨)
  2. have the same support of daylight saving time (🤯)
tz1 = pop(all_tz)
current_group = [tz1]
while(is_not_empty(all_tz)) {
tz2 = get_first(all_tz)
if (tz1.currentTime == tz2.currentTime) {
if (tz1.prefix == tz2.prefix) {
if (tz1.dateOfDSChange == tz2.dateOfDSChange) {
current_group.push(pop(all_tz))
continue_with_loop()
}
}
}
}

The script

Achieving the above sketched algorithm is actually quite straight forward, as the “hard” part of making the basic data accessible was already done by the great people that built and maintain the momentJS library. 👏 👏 👏

Example

Given the interval between 2020-01-01 and 2020-01-04, we can represent this in the following manner:

More specific

Once we have this representation, the algorithm then only has to compare each with every time zone, resulting in a runtime of O(n^2).

timezones = [....] // put list of timezones here
START_DATE = 2020-01-01
END_DATE = 2025-01-01
GROUPS = []foreach (tz in timezones) {
timezones.remove(tz)
currentGroup = [ tz ]
dateTimeArray = []
for (i between START_DATE && END_DATE) {
dateTimeArray.push(convertWithTZ(i, tz.label))
}
foreach (tz2 in timezones) {
if (tz.continent != tz2.continent) {
next();
}
dateTimeArray2 = []
for (i between START_DATE && END_DATE) {
dateTimeArray2.push(convertWithTZ(i, tz2.label))
}
if (dateTimeArray.equals(dateTimeArray2)) {
currentGroup.push(tz2)
timezones.remove(tz2)
breakLoop();
}
}
GROUPS.push(currentGroup);
}

Running the script today (05.03.2020), we calculated 107 groups.

You can find the complete script on Github under the MIT License:

Remarks

The general algorithm is quite easy and in fact the first iteration was written within 2 hours. However, as always, the devil is in the details: Dealing with lots of copies of momentJS objects was something that we had to optimize to deal with a longer timerange. We also had to fine-tune the list of continents (using an allowlist) and the list of cities (using a denylist), as some of the labels cannot be used directly. One example is that Europe/Istanbul was listed, as well as Asia/Istanbul—which we simply mapped to Europe.

Last step(s)

In order to use the output in our system, we also had to generate a representative for each group. This could basically be any time zone of each list, but we wanted this to be the most-prominent one. Accordingly, we added a count field for each time zone — which was in our case the number of users that have already chosen this time zone. We have not shared this information on Github, but kept the sorting part of the algorithm. Feel free to use it with any number of your choice that you’d like it to be sorted by.

Long story short

I presented an algorithm to group timezones into buckets based on three simple rules that define the similarity between time zones. The algorithm is based on a brute-force approach, representing each time zone as an array of days which are then compared against.

Discussion

I am very interested to hear your thoughts and experiences regarding this or other approaches.

  • Do you have another resource that I could look at?
  • What would you have done different in my position?

Product Manager, Creator of Software, Gen-Y — 😍 to build!

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store