I found the solution to this issue.
The essential part of this solution is saving every user’s time zone in a text field on their thing when they sign up. This can be done using various plugins out there that retrieve the time zone. You can also simply custom format the current date/time with Z to get the time zone.
When you run a backend workflow, add a step that calculates the difference between current date/time (user’s time zone) and current date/time (dynamic time zone). Set the dynamic time zone to be the time zone you saved for the user. Subtract the first from the second formatted as hours for a resulting “offset”.
This step will result in two outcomes:
If the backend workflow is using the correct time zone already, then the offset will be 0.
If the backend workflow has decided to use UTC time or some other time zone (which happens unpredictably) then the offset will be a positive number.
Add the resulting “offset” from the above step to whatever date you are working with, this will adjust the date to always be the same time of day for the time zone you’ve saved for the user.
Let’s look at an example:
You have Backend Workflow A with a step that schedules Backend Workflow B. You want Backend Workflow B to always run at 10am in the user’s local time zone. Furthermore, you want this time zone to be a static setting for the user (aka if the user is temporarily on vacation and accessing your app in a different time zone, this shouldn’t effect what time zone is used for scheduling Backend Workflow B).
Without the above solution, Backend Workflow A might schedule Backend Workflow B unpredictably for 10am in a number of different time zones:
A. 10am in the user’s local time zone (the correct time zone).
B. 10am in a different time zone if the user is currently using your app while on vacation in a different time zone.
C. 10am UTC if the workflow runs completely independently of your app’s frontend, for instance as a result of a database change trigger.
With the above solution, the “offset” hour amount will correctly adjust the date used to ensure that it is always 10am in the time zone assigned to the user, regardless of what time zone Bubble thinks it should be using as context for the workflow.
Hopefully this helps someone else struggling with this, it is a bit of a weird edge case.