This is a story of how I automated a boring mental task.
The other day, I was trying to arrange four different 30-minute calls with people in four different timezones.
Each person was free at a different time of day (in their timezone), and my building has a free meeting room about 25% of the time.
Result - a lot of time spent thinking:
- Alice wants to talk after 1700 and she’s in GMT+8.
- I’m in GMT+1, that’s a 7-hour difference…do I add or subtract from 1700?
- Subtract? …Yeah. Subtract.
- Is there a meeting room free at that time?
- Wait…does Bob also want to talk then? He’s in GMT-4 and he’s free at 1100, this time I add 5…
- Why hasn’t someone automated this?!
At Anvil, whenever we need to automate something, we knock out a quick Anvil app. So I spent 15 minutes building an app that converts times between timezones.
I wanted something nice and simple, and I wanted to be able to make multiple conversions side-by-side to schedule my calls. And I wanted it to work on mobile, too. Here’s what I came up with:
That’s not a screenshot, it’s the actual app embedded in this blog post.
It’s online at timezone-converter.anvil.app. Bookmark that, and you’ll never have to convert timezones in your head again.
You can copy the source and play around with it yourself:
Was it fast?
Yes.
I only needed to write 16 lines of code, and most of that is setting up the dropdowns. In fact, every line I wrote is included in this blog post!
Here’s how I built it.
Making a simple converter
The first step was to build a simple form to input a time and select the timezones to convert between. I just dragged-and-dropped Dropdowns and Labels until I got this:

First, I’ll set up the Dropdowns that let the user select the time and time zones. Then I’ll write the calculation code itself.
User inputs
I want to show the user something like GMT + 4
, but get the number 4
to use in my calculation. With an Anvil Dropdown, you set the ‘displayed value’ and ‘selected value’ of each item separately, by passing it a tuple.
So I want a list of tuples like this:
timezones = [
('GMT - 12', -12),
('GMT - 11', -11),
('GMT - 10', -10),
('GMT - 9', -9),
('GMT - 8', -8),
('GMT - 7', -7),
('GMT - 6', -6),
('GMT - 5', -5),
('GMT - 4', -4),
('GMT - 3', -3),
('GMT - 2', -2),
('GMT - 1', -1),
('GMT + 0', 0),
('GMT + 1', 1),
('GMT + 2', 2),
('GMT + 3', 3),
('GMT + 4', 4),
('GMT + 5', 5),
('GMT + 6', 6),
('GMT + 7', 7),
('GMT + 8', 8),
('GMT + 9', 9),
('GMT + 10', 10),
('GMT + 11', 11),
('GMT + 12', 12),
]
Here’s a Python list comprehension that builds that data structure:
timezones = [
(
'GMT {} {}'.format('-' if x < 0 else '+', abs(x)),
x
)
for x in range(-12, 13)
]
And that’s all I need to set up my timezone Dropdowns.
self.drop_down_tz1.items = timezones
self.drop_down_tz2.items = timezones
Now to select the time to convert. The user selects a time using ‘hours’ and ‘minute’ Dropdowns:

Anvil has a calendar widget for selecting dates and times, but this is more elegant when you just want hours and minutes.
I want to pad my numbers with zeros in the display, so I used the tuple version again:
self.drop_down_h.items = [(str(x).zfill(2), x) for x in range(24)]
self.drop_down_m.items = [(str(x).zfill(2), x) for x in range(0, 60, 15)]
self.drop_down_h.selected_value = 12
Making the calculation
So I’ve set up my user inputs. Now I can make the actual calculation.
I want to know “if it’s X o’clock in timezone A, what time is it in timezone B?” This just means subtracting the difference between A and B from X. So I work out the difference between the timezones:
dt = self.drop_down_tz1.selected_value - self.drop_down_tz2.selected_value
and I subtract that from the ‘hours’ part of the time:
hours = (self.drop_down_h.selected_value - dt) % 24
The % 24
is the modulo operator - the value
wraps around again when it goes above 23 (or below 0). This prevents me getting answers like “34 o’clock” or “-1 o’clock”.

Side note: My app only supports whole-hour offsets from GMT – so the minutes never change.
It turns out, not every time zone is a whole hour away from GMT! We get a lot of enquiries from India, and Indian Standard Time (IST) is 5 hours and 30 minutes ahead of GMT. (Fun fact: if you have an analogue watch set to GMT, you can turn it upside down to see what time it is in India!)
Anyway, I haven’t included non-whole-hour time zones in my quick app. I can account for it quite easily in my head. Perhaps I’ll add it later if it gets annoying.
Meanwhile, we do the simple version:
minutes = self.drop_down_m.selected_value
So I’ve figured out what hour and minute it is in my target timezone. Now to display my answer:
self.label_ans.text = '{}:{}'.format(
str(hours).zfill(2), str(minutes).zfill(2)
)
Multiple converters
That’s got us a single converter card, but I want to schedule multiple calls simultaneously. How do I add more to the page?
I built the converter in its own Form, and I can designate it as a ‘Custom Component’. That means I can literally drag-and-drop them into another Form:

I’ll add the first one like that, but I want the user to add their own at runtime. So I’ll create an ‘add’ Button:

And I’ll write an event handler in Python: every time the ‘add’ button is clicked, I’ll add a new instance of Converter
to the page:
def button_add_click(self, **event_args):
self.linear_panel_converters.add_component(Converter())
In case the user wants to remove converter cards, I added a “delete” button to each one:

When the delete button is clicked, the Converter removes itself from its parent panel:
def button_delete_click(self, **event_args):
self.remove_from_parent()
All done.
And that’s it! I’ve automated something that was causing me a small amount of pain a large amount of the time.
We’re always doing this at Anvil Towers. We’ve got a tool that makes it really cheap to automate stuff – so any time we find ourselves doing repetitive brain-work, we just build an app!
I wanted to embed it in this blog post. That’s easy:

And here’s the live app, embedded again in case you missed it:
Sharing it with the world
I published this app using Anvil’s one-click deployment system - it’s at timezone-converter.anvil.app. If you’re sick of making time zone conversions in your head, bookmark that URL and save yourself the bother!

And if it’s not quite how you want it, you can copy the source and modify it however you like:
If you’re not an Anvil user yet, have a play with the app builder (it’s free!). What are you sick of doing manually? Try automating it!