For something that we wear on our wrists and constantly keep track of in our daily lives, time can sure be a headache to work with sometimes.
It should be pretty easy, right? Anything that happens in this universe we call our home happens at a specific point in space and a specific point in time, and we observe that predictable pattern every day. For beginners, Bubble doesn’t seem to share the notion that time should be an everyday thing that we can all easily make sense of. It can sometimes feel like it takes the concept we thought we knew, throws it into a grinder and then hands you its mangled remains. “Here.”
I keep seeing threads pop up in the Bubble forum and elsewhere that “I think there’s a bug here…”. Most likely, you’re not seeing a bug, but one of the challenges for new Bubble users is that it’s not made clear out of the box how exactly Bubble treats the date field. There are rules of course. They make sense. They’re predictable. But they’re not very well explained.
In their defense, time is actually pretty complex. Any framework or programming language will have to draw a line somewhere of just how much they’ll invest to automate datetime algorithms and maintaining a system that’s kept up to date with no room for error or delays in deployment. For now, Bubble seems to prefer to leave out that job to plugin developers and external libraries and API’s.
Time is one of those things that technology has made so easy for us that we don’t really think about the calculations going on under the hood. Time Zones, Daylight Savings Time, Leap Years – it can make anyone’s head spin. Globalization would have been a nightmare to implement if it weren’t for our digital devices making collaboration easier.
What time is it?
Easy question. Sure. But what time is it in Samoa? Or Seoul? I’ve lived abroad for about five years, with a +3 hour time difference from my home town of Oslo. If I need to think about the local time back home I still look like a question mark for a few seconds before Googling “Oslo local time”…. You know…. Just to be sure I don’t mess it up.
It’s like a double negative: it should be so easy to know the answer, but somehow it’s always tricky. So let’s split it up into its smaller parts, and look at why time is complex in the first place:
Why do we have time zones? Well, the reason is pretty simple: when morning hits New York, the sun is setting in New Delhi, and both Mary and Abhinav want to get up at 08:00 AM.
Time Zones were invented to keep track of the local time as compared to a set standard time. Originally, the standard time was set way back in 1675 as what you know as GMT, or Greenwich Meantime, to help sailors determine longitude at sea. Colonialism and the later rise of global travel and commerce has implemented the system in every corner of the world. Most zones follow a predictable pattern that resembles that of the sunrise and sunset, but countries are free to pick one or more zones as they see fit. China, for example, one of the biggest countries in the world, follows a single time zone, leading to strange wakeup times in some regions. Others, like Samoa, used to have the time zone UTC-10:00, but changed it to UTC+14:00 because the big time difference between their main trade partners of New Zealand and Australia was hurting their GDP.
To further complicate things, there’s also…
Daylight Savings Time (DST)
As the name suggests, DST is a system that a few countries like my home country of Norway use to provide an extra hour of sunlight during the dark winter months (believe me, we need it). Typically, clocks are advanced one hour during springtime, and then returned to their regular time during autumn, resulting in a 23-hour day in the spring and a 25-hour day during fall.
Software-based clocks adjust that time automatically these days, but I can tell you that the system has caused confusion ever since its implementation more than a hundred years ago. Missed meetings, flights and accidentally sleeping an hour longer before work is just the beginning (somehow, people never seem to come in an hour earlier when the change goes the other way).
Ok, surely we have complicated time enough now, right? No, it turns out that we have another way of messing with it:
Leap years occurs usually every four years (I won’t explain the caveats, as they’ll give you a headache, but Wikipedia is at your disposal should you be interested in further self-torture. Oh, there’s also leap seconds, if you really want to ruin your day), and add an extra day to the month of February, giving the year a total of 366 days. The system of leap years was introduced because seasons actually don’t correspond perfectly with the length of one day. Over time the discrepancy can cause a calendar and its seasons to slowly drift apart. Adding an extra day at regular intervals corrects for that drift.
Every time zone is measured in + or – a set number of hours, right? But from what exactly?
UTC, often called Universal Time is the baseline from which every other time zone is calculated. It’s the successor to (though not exactly the same as) the Greenwich Meantime (GMT), and doesn’t observe Daylight Saving Time. It’s not actually a time zone in itself, but a standard.
Whenever you read a time zone being +3 hours, it’s three hours ahead of UTC time. The time difference between UTC and a time zone is called offset, and ranges from −12:00 to +14:00 hours, usually measured in whole hours, but some countries are using other values: Australia uses +08:45 in some regions and North Korea uses +08:30.
Now, all of this is likely not new to you. You knew about time zones, leap years and probably even DST. But even armed with that knowledge, Bubble can be confusing. So let’s go over a few more things and try to get a better understanding of it.
How Bubble saves dates and time
It’s reasonable to assume that Bubble saves a datetime pretty much like you do: January 1st 02:00 am. But to understand how this is not the case, we need to split Bubble’s time handling into two separate categories:
Saved Time is how Bubble actually stores the datetime you enter. Knowing how this works is key to understanding the later points. The current time as I’m writing this is 1609336641913.
Uhmm… Thanks. What the hell is that?
That, my friends, is Unix time. What may look like a random sequence of numbers is actually the exact number of milliseconds that have passed since January 1st 1970 00:00 UTC . This is how Bubble, and many other frameworks, saves datetime.
Displayed time is how Bubble shows you a given datetime. If you think about it, you can’t display the current time without knowing the time zone, right? So Bubble takes 1609336641913 and formats it as a string of text on the screen as 30 Dec 2020, 17:57 using the time zone Asia/Dubai. That conversion also implies that Bubble has converted your date into text, no longer easily editable.
Knowing that Bubble stores a static number instead of the actual month, day and time tells us a few things:
Bubble doesn’t save a time zone
If Bubble takes a constant datetime (January 1st 1970 00:00) in a constant time zone (UTC) and adds 1609336641913 milliseconds to it to find a specific point in time and then saves that value, it follows that Bubble doesn’t care what time zone you want to work in. Many-a-time have I seen the question “Yeah, but how do I make Bubble save the time in timezone X?” asked online, and the answer is – you don’t. You can display a timestamp formatted in a specific time zone, but the saved value remains an absolute number.
There is no date and time – only time
Knowing that we’re looking at an exact amount of milliseconds from a particular time also makes another fact suddenly obvious: Bubble doesn’t save a date and/or a time – it always saves both (or none of them, depending on how you see it). You may choose to only display a date or a time, but they’re both saved no matter what you do.
How Bubble ruins birthday surprise parties
Albert Einstein was on to something as he realized that time is relative. An unexpected challenge that developers run into with Bubble becomes apparent when you save a user’s birthday. If you only provide a date (which is usually the case for date pickers), then Bubble will save that date as 00:00 in the time zone the user is currently in. In other words, you don’t need to move more than one time zone away before Bubble starts displaying the ‘wrong’ date. Which isn’t really wrong, of course. Your birthday can be on a different date in another time zone after all. That fact is obvious, but yet we’re all surprised when we learn about it.
Bubble and time zones
How time zones are formatted in Bubble
Time zones come in a format that usually combines a region with a city, such as America/Los_Angeles and Asia/Tokyo. Whenever you ask Bubble to format a timestamp in a specific time zone, this is the format you will be using. The entire list of time zones is available as a downloadable csv on https://timezonedb.com.
How Bubble knows your time zone
Your OS (Windows, MacOS, Linux, Android, etc) has a time zone setting. This tells the computer how to format dates and times correctly for you in apps across your computer. Your browser reveals this setting to websites, helping all apps from Calendly to booking.com provide calendars in the correct format.
Bubble automatically fetches the browser’s time zone and displays all datetimes in that format by default.
That approach can be incredibly helpful of course: setting up a booking calendar shared between colleagues on different continents will simply work, with each user seeing time in their own zone. Bubble also does do a lot of the heavy lifting for you in other aspects. You can ask it to display timestamps in any time zone you want. It takes care of DST (Daylight Saving Time) for you, and you don’t need to keep track of leap years. You never have to worry that the current date/time shows a value that doesn’t take these calculations into account. You can trust it’ll always be correct. These are calculations that would otherwise be frustratingly complex.
The challenges start to arise when you want to work with a bit more specific scenarios.
Searching, sorting and grouping based on time:
To understand why searching for records based on datetimes in Bubble can present some challenges, we need to return to how Bubble saves time – as an integer, or number. In other words, if you search for a record with a date earlier than the current date/time, then years, months and days never enter the equation. It’s a simple arithmetic of the current unix time being a bigger number than the unix time you’re searching for.
So for example, let’s say you’re searching for any of the following:
- Records in the same year as year X
- Records in the same month as month X
- Records in the same month/year as year X and month Y
- Records on a Thursday
- Records from today
Bubble struggles to handle that query, since it doesn’t know what weekday, day, month and year your records are in before it has converted the record’s Unix timestamp into a readable format, which requires a time zone.
Many users then resort to adding a :filter and going with Advanced filtering on the query, and find the search to be frustratingly slow. This is because you’ve forced Bubble to download the entire list, and then perform the filtering client-side. In effect, you’re asking Bubble to convert the Unix timestamp on every record to a readable value, and then check if that value matches the one you’re trying to filter by. It will work, but as a search, it’s not very efficient and you’ll find that as you get to more than a few hundred records, it’s going to start slowing down.
Splitting up the data into different fields
A more efficient approach here would be to save the data into separate fields. For example, if you need to search for and/or sort Users by their birthday, it makes sense to set up fields for day, month, and year where each of them simply stores a short integer. From a database perspective it may feel a bit unintuitive – after all, you’re storing the same data in several different ways, but it’s an example of how Bubble can force you to do things a bit differently than what traditional database best practice teaches:
It gives you flexibility in several ways:
- You can work with partial information: for example, you can search for all users born in January, without having to supply a day or year
- Searches will be performed very quickly, as the fields are light and requires no client-side filtering
- You can work with flexible queries (such as Month > 3 and Month < 6 or Month > 3 and Year > 1990)
Remember that one of your jobs as you are structuring your database is not only to think about what your users will see – it’s also to help Bubble find and calculate your information quickly and efficiently. Don’t be afraid to set up fields that are there only to perform searches or sorting and place the heavy lifting on the server instead of the user’s device.
Working with absolute time
Bubble’s time zone display flexibility is great, but what if you want to work with an absolute time? Say for example that you run a tourist operation in Paris and tourists from all over the world can book your city tour. The tour starts at 10:00 AM Paris time no matter where it’s booked from.
Displaying the time is no challenge, but the minute you bring Bubble’s date and time pickers into it, you’re in trouble. Since Bubble defaults to the browser time zone, customers will book the trip at 10:00 am in their local time zone, with an offset that could be as much as a full day off the time you intended.
This is usually where the question comes in: how do I save it in another time zone? And the answer, to many Bubbler’s frustration, is… you can’t. Without any custom code or plugins, manipulating Bubble into saving 10:00 am in a different time zone than the one you’re in is incredibly difficult. Adding or subtracting the offset between two timezones may seem like a possible solution, but since time zones change over the course of a year, it’s bound to be frequently imprecise.
Luckily, over time a number of useful plugins that can help you out with datetimes and time zones have been published in the Bubble plugin store. We’ll do a more thorough list of several of them in a separate article and link to it from here when ready.
For now, one of the most versatile and useful ones that I’ve recommended repeatedly is the CalendarGrid Pro plugin made by Keith from the Bubble forum. It’s on the pricier side at currently $10 per month or $100 for a one-time purchase (per app), but out of the box you’ll be able to set up multi-timezone booking systems, flexible date ranges, converting time between zones, block certain days of the week and compute time differences. To solve simple challenges there may be free or cheaper plugins that can get the job done, but for advanced booking solutions, especially covering more than one time zone, I warmly recommend this one.
Bubble saves time in a format called Unix time. This is actually a number (integer) representing a snapshot of an exact time, as measured by milliseconds since January 1st 00:00 UTC. What you see as a date in a given month and year and/or at a specific time of day is simply a textual representation of that value.
Bubble fetches the time zone from your browser, which gets it from the operating system on your device. This information is available even if the user has restricted Current Geographic Location access or is concealing his IP address, as it’s stored in the browser.