Setting CRON in a different time zone

If you are in a different time zone to some of your clients, or have a server that uses UTC to avoid daylight saving changes, it can be tricky to set a CRON script running at the correct time in a different time zone. Here we explore a couple of solutions.

CRON before midnight

As a starting point, let’s consider the requirement to run a CRON script at midnight to generate an accurate report on the days activities.

# m h dom mon dow command 0 0 * * * www-data /usr/bin/php $CRONSCRIPT

Here the script $CRONSCRIPT
(and yes, we do have some CRON scripts using PHP) will be called every date at midnight
server time

.

A few seconds either way may not matter, but when working across time zones with different daylight saving regimes (especially between hemispheres) you might find your script running any time between 10PM and 2AM during the year.

Specifying a CRON time zone

The obvious solution is to specify a time zone for CRON:

# m h dom mon dow command TZ=Australia/Sydney 0 0 * * * www-data /usr/bin/php $CRONSCRIPT

Unfortunately, setting the time zone here has no effect on when the CRON script is triggered. What it does instead is set an environment variable inside the shell in which the script is called. The script itself may then use the TZ time zone.

We can see that by running the following test:

# m h dom mon dow command MAILTO=root 0 * * * * www-data /usr/bin/php -r 'echo date("Y-m-d H:i:sn");' TZ=Australia/Sydney 0 * * * * www-data /usr/bin/php -r 'echo date("Y-m-d H:i:sn");' TZ=America/New_York 0 * * * * www-data /usr/bin/php -r 'echo date("Y-m-d H:i:sn");'

In this case both the PHP ‘echo’ commands are run on the hour. The first will output current server time, the second the current time in Sydney, and the third the time in New York.

An intelligent script

The above results present one simple solution. Rather than trying to trigger our CRON script in a different time zone, we can have it triggered every hour and then within the script itself check whether it is midnight in the specified time zone (TZ).

<?PHP if(date('Hi') == "0000") { ... it's midnight - run the report ... } ?>

While this works, it’s not the most efficient approach as it requires executing the PHP script (with all associated overheads) every hour rather than just once each day (or week, or month, depending on your requirements). It also makes testing difficult.

Making CRON conditional

A better approach is to have CRON decide whether it’s time to run the PHP script. While we’ve ruled out the possibility of doing this with CRON settings, there are more ways to skin the cat.

Using the command line we can string commands together using a logical operator, and make calling the PHP script conditional on a command-line date calculation.

For example, the following
bash

command will result in the PHP command being executed only if it is run exactly at midnight:

$ [ "$(date +%H%M)" == "0000" ] && php -r 'echo date("Y-m-d H:i:sn");'

So let’s try plugging this into our CRON file:

# m h dom mon dow command TZ=Australia/Sydney 0 * * * * www-data [ "$(date +%H%M)" == "0000" ] && /usr/bin/php -r 'echo date("Y-m-d H:i:sn");'

This is where we have a problem. Instead of working as intended, what we get is an error:

/bin/sh: 1: Syntax error: end of file unexpected (expecting ")")

Thankfully, there is a clue there. CRON runs under /bin/sh
which these days tends to resolve to /bin/dash
. The simplest solution, short of re-writing the conditional in
dash

, is to force
kindly ask CRON to use
bash

instead:

# m h dom mon dow command SHELL=/bin/bash TZ=Australia/Sydney 0 * * * * www-data [ "$(date +%H%M)" == "0000" ] && /usr/bin/php -r 'echo date("Y-m-d H:i:sn");'

But we still get errors:

/bin/bash: -c: line 0: unexpected EOF while looking for matching `)' /bin/bash: -c: line 1: syntax error: unexpected end of file

After some searching it appears the problem is that we need to escape our %
characters:

# m h dom mon dow command SHELL=/bin/bash TZ=Australia/Sydney 0 * * * * www-data [ "$(date +%H%M)" == "0000" ] && /usr/bin/php -r 'echo date("Y-m-d H:i:sn");'

Success! We now have a means of triggering a script at midnight in any time zone. The CRON command will be triggered every hour, but only continue to running the PHP script if it’s midnight in the target time zone.

End of month CRON in another time zone

This is a slightly more complicated requirement, for a script to run only at midnight on the 1 st
of the month. Using the previous script as a starting point, we come up with the following:

# m h dom mon dow command SHELL=/bin/bash TZ=Australia/Sydney 0 * 28-31 * * www-data [ "$(date +%d%H)" == "0100" ] && /usr/bin/php -r 'echo date("Y-m-d H:i:sn");'

Note that we have made the assumption that the time in Sydney will always be ahead
of server time. So we trigger the CRON as we approach the end of each month (dates 28-31) and use bash to check whether Sydney has moved into the next month.

For a more generic solution you need to use 1,28-31
to cover the situation where the server time is ahead of the target time zone (TZ).

责编内容来自:The Art of Web (源链) | 更多关于

阅读提示:酷辣虫无法对本内容的真实性提供任何保证,请自行验证并承担相关的风险与后果!
本站遵循[CC BY-NC-SA 4.0]。如您有版权、意见投诉等问题,请通过eMail联系我们处理。
酷辣虫 » 综合编程 » Setting CRON in a different time zone

喜欢 (0)or分享给?

专业 x 专注 x 聚合 x 分享 CC BY-NC-SA 4.0

使用声明 | 英豪名录