Comparing Dates in Conditions, and Accounting for Timezones

You can also convert times to UTC every time you save them (or to another timezone for that matter).

Note - by “converting” I mean calculate the offset so it if you were saving at 2pm Eastern that it’d instead save it as 2pm UTC. (which is different than storing 2pm Eastern in UTC which is 6pm UTC).

1 Like

So I get that. But in order to convert, I will need a reference, right? I mean I need to know what timezone I am converting from and the difference between that and my target timezone. Is javascript the only way to do that?

Or to put it another way, in Bubble all dates are stored as UTC and calculated/displayed as local, so there is no way to specify one or the other to work with, right? If I want to work with UTC, I have to work outside of Bubble, because all Bubble calculations are converted to local first.

There are a few ways to make it work within Bubble. I believe there’s a plugin or two. Additionally, we stood up an API that enables these timezone conversion calculations.

1 Like

Ok great.

Sometimes I get stuck trying to understand the why of Bubble instead of only looking for a solution. Like I can’t understand why if UTC is what I want and UTC is what is in the database, why can’t I just use UTC only in my workflow. I still may be stating the issue wrong, but I’m going to stop now and look at those plugins are figure out the javascript.

Thanks for the help!

1 Like

Yes, most likely, @subtlemonsters. I’ll read this thread more carefully in a short bit and advise.

A couple of fast facts that may help you:

  1. Note that date objects (as I’ve said many many times here) represent unique moments in time. These are accurate down to the millisecond, so unless you’ve constructed them yourself (setting the time parts – HH:mm:ss:ms – to zero or some other reference time, a strict comparison will almost never match).

  2. Two things are “on the same date” if they both happen on the same day with respect to ONE date object’s time zones. Consider:

2a. As I write this, my local time is 6/25/2019 7:24 PM in timezone ID America/Los Angeles (I am in San Francisco, but this is what the timezone is called – bastards!!!)… Let’s call this date “2a”.

2b. In UTC, it is 6/26/2019 at 2:24 AM. Let’s call this date “2b”.

On the face of it… “NOW” is not the same calendar day in these two timezones! Whoa, mind blown, right? These dates (date/times) are exactly the same but they “happen on different days” . WTF, right? Well, the WTF part is we would be doing it wrong to compare them that way…

2c. Clearly, to determine if two dates share the same day part, we must transform both dates into ONE consistent timezone. In a Bubble page (in fact in any web page), we would do this as comparing the day parts of date “2a” and date “2b” this way:

We would probably give primacy to the User and compare. If we take my current time as an example, the following boolean (“yes/no”) expression is true (“yes”) if both moments in time happen on the same day from my perspective:

2a:formatted as MM/DD/YYYY [in timezone User's timezone] is 2b:formatted as MM/DD/YYYY [in timezone User's timezone]

^^^ this is shorthand, but you should know what I’m getting at.

What this will yield is a comparison of “6/25/2019” and “6/25/2019” and these are the same, right? So the expression is true.

If our workflow is a server-side workflow (API Workflow), we would likely compare UTC time. You can also see that if we did:

2a:formatted as MM/DD/YYYY [in UTC timezone] is 2b:formatted as MM/DD/YYYY [in UTC timezone]

… will also be true, but in this case the strings compared will be “6/26/2019” and “6/26/2019”.

  1. In JavaScript (and hence in Bubble) and in nodejs (which is just JavaScript that runs on a server and so hence in Bubble) dates can only be created in the browser timezone. This means that a date created by most datepickers that a user would interact with will only be created in that user’s timezone. Since there’s no browser server-side the dates get created in UTC… and not from a datepicker but from some other process, right?

(This is why there is a timezone option in Calendar Grid Pro. It allows the selection of dates in other zones if you desire.)

The Bubble server timezone is effectively “UTC” though note that what it actually reports is “UTC/Etc” – these are the same thing, though they have different timezone ID strings. (That is, representing a date as text based on UTC and UTC/Etc, we will find no differences.)

As you can see from the above, you don’t necessarily need JavaScript to do a “on the same day” comparison of dates in Bubble.

But you do need to do it the way we would do it in JavaScript, which is to (thoughtfully) convert significant parts of the dates in question to strings and compare them that way.

Libraries like moment and moment-timezone are really only necessary when you need to construct date objects. (Which is a thing one might need to do in advanced applications that handle dates.)

  1. Believe it or not, a lot of advanced applications handle dates in a pretty damn hand-wavey way. And this is where UTC in part comes from and comes into play. Let us consider a vacation rental booking app that:
  • Allows a user to book a vacation rental property at some time in the future. and such property may be anywhere in the world.

  • I am the user and I want to book a property in London (which is sort of in UTC timezone). But I live in San Francisco.

  • I book the property for July 4th through July 8th 2019.

  • I use a date picker to select check in of July 4 and check out of July 8.

  • Most date pickers (and in fact the one I’m using on stupid vacation rental site X) can only understand that I am indicating July 4 and July 8 in my time zone.

  • So what stupid vacation rental app does is just assumes that I mean July 4 there – in London – and, at the end of the day, just stores that as July 4 hour zero (start of day) in UTC… NOT because London is in the same timezone as UTC, but because that’s a convenient way to store dates. But dates are never separate from their time parts because dates are distinct moment in time.

But that’s typically how that works. Using Bubble and a clever plugin like Calendar Grid Pro, you can actually store the REAL TIME (the real date) that the user is selecting. (Because I actually construct the check in/check out dates in the target property’s timezone.) But I don’t think there’s many real life apps that do it this way.

When we examine iCal feeds from booking sites, we see that what they do is just store “July 4 at zero hours in UTC” and then conform all selections to UTC.

It’s like a way of saying, “Look, I can’t get what this date looks like to YOU, user. But we both understand that you will arrive IN LONDON on July 4… even if the REAL July 4 hour zero in London is some other time on July 3 or July 5 FOR YOU.”

Does that make sense?

3 Likes

I get it.

Here’s the missing link with time (or at least it was for me). Time is stored as a number. It’s the number of seconds since Jan 1st 1970, 12:00am in the morning UTC (or some date like that).

So, the time stored doesn’t have a timezone, but Bubble needs a timezone when input so that it can calculate the number of seconds since that date. If it’s server side it uses UTC. If it’s client side, it uses the user’s timezone.

Don’t know if this helps, but it helped me.

1 Like

Yeah, at the end of the day, @sridharan.s, a JavaScript date is a number of ms either after or before the UNIX Epoch. They are timezone-less. But that’s not how human beings think about time. And thereby arise the problems.

3 Likes

I’ve read all your other posts on date @keith and I was eagerly anticipating your reply when I saw the little “replying” notice on this thread. So thanks. I think I remember you saying that the date can only be in local time in another thread, but it didn’t sink in till you said it this time.

I’m sitting here thinking, “But I don’t care about your time. UTC is the only time I care about. Doesn’t that make it simpler?” Obviously not :frowning:

I honestly don’t have too much trouble with the concept of time, I just was thinking I don’t need to do calculations because only one time matters to me.

So that’s fine, I’ll read thru this a couple more times and see if I can get my head around it. I know I’m not the first one to struggle with this, but it sure has made me feel stupid

1 Like

OK, so, reading through your original post, @subtlemonsters, I see that what you’re trying to do is track the number of interactions with an element.

First, you don’t need to know that (we are going to call this thing you think you want to know “the thing”). Second, if you think you need to know that (“the thing”), there are better solutions than tracking that in Bubble. Third, you don’t need to know that (again, you don’t need to know “the thing”).

But, if you REALLY think you need to know that, see “second”. How, in Bubble, would we go about knowing “the thing”?

Let’s assume for a minute that the data you seek to collect is interesting or important (it is not). (But, if it were) How would we do that in Bubble?

Well, every time we create and/or store something in the database (even “the thing”) we will (1) create a new Thing (custom data type – note, please confuse the “thing” you think you want to know with a generic “Thing” – AKA a specific instance of a custom data type) or MODIFY the Thing and (2) that new (or modified) Thing will have a Created Date (or Modified Date) that is new.

OK.

Let’s say you want to know how many times “per day” a certain button is clicked. First, what do we mean by “per day”? Well, we don’t literally mean how many times a certain button was clicked ON A SPECIFIC CALENDAR DATE.

NO. We mean, over a certain timeframe, how many times was a certain button clicked, PER [some other timeframe], ON AVERAGE.

See the difference?

It matters not how many times the button was clicked last Tuesday. We desire to know “over the past 30 days” how many times was the button clicked per day, on average.

Still, this is NOT SMART to track IN BUBBLE, [MORE]

1 Like

[CONTINUED…]

But why? Here’s why: To do this, we need to create some object in the Bubble database. Let’s call it an ITERACTION.

You can, on button click (or whatever), create a new Interaction, but this will slow us down. The blue bar of death will appear as we wait for the Interaction to be created or modified.

But let’s say you want to continue anyway (did I already mention that this is pointless?). Well, you can create or modify an Interaction thing.

THIS IS WHERE WE GET INTO THE DATE STUFF…

The Created or Modified date of the Interaction thing will be constructed in the server timezone, because that is where it happens.

So, you’ll get a new Interaction created (or an existing Interaction modified) in the server timezone. For reasons previously explained, these may not be the same as the User’s calendar date.

Again, none of this is helpful.

If you want to track stuff like this, offload it to Google. Google Analytics will tell you about these sorts of interactions… and they can get crazy detailed by use of Google Tag Manager (and GTM will warn you that tracking interactions in the DOM like this is high overhead – but not as high overhead as writing them to Bubble).

So, I guess what I’m saying is, “Your use case here has nothing to do with dates.” And further, you’re focusing in the wrong direction.

Just go build some new functionality for your site. Leave click-stream analysis to some intern once you get to the point where you can afford interns,

I’m really NOT being snarky. There’s just NO POINT in what you are trying to do vis-a-vis other ways you could be spending your time.

(But the reasons this gets confusing are due to the hows and whys of where dates are constructed. Your question just has nothing to do with that. Just please please please go work on your app and forget about this nonsense about click tracking on specific buttons.)

1 Like

Ok, so I really do appreciate you telling me I don’t need what I need, so keep it up. I’ve known from the beginning that there must be something wrong with my thinking.

Part of the problem with asking a question on the forum is that a person is necessarily down the rabbit hole quite a ways before they realize they need to ask a question. And at that point it gets more difficult to ask a good one.

Now, a defense of my use case:
I am building an audio streaming site and “the thing” I think I need to track is plays per song over time. I simplified it to user interaction for the sake of asking a question and perhaps that was a mistake.

This is why I think I need this data:

  1. I have to pay song owners per play
  2. I have to deliver this data to admins via admin view and csv so that they can process those payments
  3. Song owners need to know how their songs are performing

This is why I think I need this data in Bubble:

  1. I don’t know how to do it another way

I’m prepared to be wrong about all this. @keith do you still think I’m barking up the wrong tree for this use case?

I’m also not exactly clear why tracking plays on my songs would be treated differently than say, tracking ratings on them (meaning store them in the database). Seems like that kind of functionality is typical in many of the tutorials I viewed.

So all along the solution was right in font of me. When you use :extract on a time and date, you can specify the timezone. I read thru everything and totally missed this. Now I can create a year, week, or day field, and fill it with :extract in my own timezone. Easy. I thought is would be—thought it should be—and it was.

Hi there, we just released two features giving you more control over handling timezones. Learn more here: New features to override timezones