Timers and Timezones
If there is one feature of OutSystems that I love, it’s Timers. They do something which other systems can do, but they need external help (like cron) which feels hack-ish and gets managed outside of code, which makes it hard to manage and maintain. If there is one thing I do not love about Timers, it is the way scheduling works. You pick times… but the times are in the server timezone… and if you use the OutSystems cloud the server timezone is UTC which does not observe Daylight Savings so twice a year you need to go in and change the time. Even worse, what happens when you need the Timer to execute only once per day but you have a multitenant application and tenants could be in different timezones? Now things go quite badly. Luckily, we can overcome all of this with only a small bit of code.
Let’s say that we have a timer that needs to start at 16:00 daily, your application needs to behave in Eastern US time, and the servers are in UTC. Your initial reaction may be to set the time on the Timer to 21:00 and this will all work out. but when Daylight Savings switches you will need to flip that time to 20:00. This is the kind of manual process that does not work out so well in my experience.
Something I always recommend in an OutSystems application is to have a configuration setting that tells your application what timezone the servers are in, another one for what timezone you want to use for display purposes (which should be per-tenant in a multitenant application), and a pair of functions to convert between server time and display time. In the Application Framework, these configuration settings and functions are built-in and ready to use.
These configuration settings are the key to getting your timers to start when you need them to. Add another configuration setting (for the application or for the tenant, depending on the timer’s needs) for “when should this start?” Next, assuming the timer needs to run on a daily basis, set its schedule to run daily, every 15 minutes. (The reason for using 15 minutes instead of every hour is that some timezones, like India Standard Time, are offset from UTC by fractions of an hour.) You will also want configuration settings that allow you to store a “last run timestamp” for the timer.
Finally, at the beginning of the timer, before anything else is done, you will need code that does the following:
- Convert the current date/time to the application’s timezone or the tenant’s timezone, depending on the timer’s needs.
- Compare the converted time to the configuration setting for “when should this run?” and compare to the “last run timestamp” setting to determine if the “last run timestamp is older than “when should this run?” The outcome lets you decide if it is actually time to run the timer. If it is not the right time to run the timer, immediately exit. If it is the right time for execution, update that configuration setting (you will likely want to do a CommitTransaction immediately after so that no matter what, it has been marked as run and not attempt execution every 15 minutes), then put in your usual logic.
There isn’t much work here, but this little bit of logic will get your needs met. the downside is that your schedule is now hardcoded in, but it should not be a tough task to create screens to administer schedules that meet your needs.
J.Ja