Time zone ID to Zulu Time (ISO z suffix) - bug or intended?

Looking for some help from any Bubble date wizards out there.

When I extract the z suffix (Zulu time) of a Bubble date value I get 2 different values for a single time zone (Tested with Tokyo & Bali and both had this issue, I am sure there are others):

Editor view which shows the result I expect to get using the z suffix of GMT+0900:

Run time view of what actually happens:
Screenshot_021021_092352_AM

GMT returns properly when the :Formatted as time zone setting is ‘User’s current time zone’, but it returns the abbreviated code when ‘Time zone selection’ it is a dynamic or static value.

Additionally, for a time zone like CST timezone, it shows both z values as ‘CST’, instead of GMT-0600 and CST in the editor:

And in Run mode both show up as this:
Screenshot_020921_062841_PM

There must be a bug with the first values not being consistent for certain time zones. But there also seems to be an issue with the abbreviation being returned in some instances instead of Zulu time that is expected by the z suffix value.

Am I crazy or does there seem to be a bug here?

Or even better for my specific eventual use case, does someone know how to consistently get the Zulu time zone (offset) of a Bubble date for a specific Time zone ID (not just current browser) without the use of an API?

*Tagging @keith because I know you have dug into this more than anybody else and also @josh @emmanuel in case there are some skeletons in the closet around ISO Date parsing

Are you ultimately just trying to construct what I call a parallel date?

I am using Javascript to create a Date/Time, and time slots/ranges, in a date aware (dst aware) timezone

Most basic example which actually works fine for CST, but not the JST example above:
Screenshot_020921_073124_PM

Also, Z is not “Zulu time” it’s a formatting token for what would be best described as the “abbreviated named offset”.

So if I format a date (let’s say it’s today) in Timezone America/Los_Angeles, that Z token will read PST.

And I am in that zone right now and so my editor will show me the formatting preview as “PST” because that corresponds to my browser zone. It’s just like with any formatting tokens - Bubble doesn’t know (in the editor) what your dynamic date value will be at runtime, so it will almost ALWAYS use current date/time as the sample to give you the preview.

When we render the date at runtime, the formatting token appears as we specify, get it?

NOW, Timezones are not offsets and offsets are not timezones.

Some IANA Timezones (like Etc/GMT-#) are FIXED OFFSET Timezones (they are computer type Timezones where there’s never adjustments for daylight savings tine and such). They are just like any other zone, but the dates within them are always the same offset from UTC.

Further reading; Time Zones vs. Offsets – What's the Difference? Which Is Best?

Also: Manual | Luxon ← Timezone docs from Luxon, full of helpful commentary.

2 Likes

Got it.

Do you know of a way to convert the ‘abbreviated named offset’ to the actual offset value within Bubble or Javascript?

Since Bubble and the date picker are smart enough to know when it’s PST versus PDT they are already doing the heavy lifting for me, I just need the value formatted differently. Now I could add in the entire ‘PST/PDT to offset’ database in the app to do that but it seems excessive - plus presents the need to be updated should laws be changed that adjust a local time

What you are trying to do will never work correctly, sorry to say. You can’t trick vanilla JavaScript into parsing a date “in zone” via new Date().

And, what you are trying to do is construct what I call a “parallel date”. You have a date like “The Start of Some Calendar Day in PST” and you want, from that, to create “The Start of That Same Calendar Day in Some Other Zone”.

Right?

You can try that using Date.parse() (go read the docs), but the string to parse should be in ISO 8601 format (which looks like this).

Which is to say, you must still figure out the correct offset and then specify it in a non-ambiguous way at the end of your ISO 8601 string (like, “+06:00” where 06 :00 is the offset).

You can’t Bubble-format your way out of this one because (as I said in my earlier post) the “Z” token is not what you think it is.

So, to create a parallel date, you really do need the help of a library (unless you want to go read the source for Luxon or Moment and go see how they reliably compute offsets, but that way lies madness. Just load the library – Luxon is sufficient in this case).

Then, what you do is you take your JavaScript date (Bubble date), use the library to wrap it and then use the library to convert the date to an unambiguous string representation of the date as it would appear in your specified input zone, via the library’s formatting features. THEN, you use the parsing features of the same library to parse the date “in zone” using the “target” or “output” zone.

In Luxon, that would look something like:

function getParallelDate(luxon_date, in_zone, out_zone) {
        // returns a parallel date
        // luxon_date is a Luxon DateTime object
        // if luxon_date is not yet a luxon date, it will be turned into one
        // in_zone and out_zone are valid IANA Timezone names
        if (!DateTime.isDateTime(luxon_date)) luxon_date = DateTime.fromJSDate(luxon_date)
        return luxon_date ? DateTime.fromFormat(luxon_date.setZone(in_zone).toFormat('MM/dd/yyyy HH:mm:ss SSS'), 'MM/dd/yyyy HH:mm:ss SSS', { zone: out_zone}) : null
  }

It is working great for North America and UK locations, but broke once I tested in Asia locations. I was shocked to surprised to see Bubble take the javascript I posted above and give me a date but it worked!

Just need to figure out these other ones. As always thanks for the details (and homework) :+1:

BTW, @gf_wolfer, since you have this problem, would you be interested in testing a plugin for exactly your use case? I’m working on one right now, but in typical fashion I keep adding features and so it’s not released yet. (It’s won’t be free.)

The problem you’re running into is that you’re trying to do this without a library. You’ll never get the right answer unless you dig into how Luxon does it (which digs into certain features of the Intl API found in modern browsers).

Further, YOU might get the right answer, but if you’re trying to do this in the page, you are at the mercy of the various browsers’ implementations of things.

More dedicated people than you or I have solved all these problems. Use their libs. Luxon, in particular, is very lightweight (because it’s mostly just a wrapper on APIs that already exist in the browser, but that are very hard to use).

1 Like

To really put a hard point on this: That one-liner you’re writing cannot do what you’re trying to do reliably across all zones and across all devices. Even if you’re running it server-side on the Bubble server. All the information needed to do that transform properly is not contained within that line of code.

Please note that someday node and/or all the major browsers will have APIs that will make this transform possible, but it is not possible today. (And the syntax will surely not be what you are using at the moment.)

BTW, if your reticence to use a library is because (as I think we may have discussed in the past) that to do this with moment.js (for example) is that you have to load a huge timezone library as well, just know that Luxon (basically the replacement for moment, which continues to be maintained, but will never have new feature updates) does not require an external timezone library, because node (including the version of node Bubble is running currently) and all modern browsers now actually have the needed information shipped within them.

The bundle size for Luxon is just 21k, all-in. Like, it’s smaller than my typical forum reply. There’s absolutely no reason not to use it.

1 Like

:rofl: I might dig into the plugin you can DM the info needed to check it out, but what started as a template project is turning into a monster haha

See my link to the Luxon docs in previous reply. Not trying to be a dick, but I pointed you to the right answer and even included sample code and you’re like, “oh, whatever, I’ll keep flailing over here.”

1 Like

This topic was automatically closed after 70 days. New replies are no longer allowed.