如何为crontab设置时区?

我已经设置了ACPI唤醒,使得我的笔记本电脑每天早上在特定时间自动唤醒。该唤醒时间的时区为UTC。我希望也能使用UTC设置我的crontab,以便与唤醒闹钟相匹配。
你应该如何操作?
我尝试编辑/etc/default/cron以包含以下内容:
TZ="UTC"

但是它不起作用。(我也尝试过 TZ=UTCTZ="UTC/GMT")有什么想法吗?

5你在编辑后执行了 sudo service cron restart 命令吗? - Rinzwind
1不...但是我尝试过了,没有任何改变。 - alj
1可能是从终端设置时区的重复问题。 - Isaac Betesh
http://superuser.com/questions/248841/how-to-run-cron-jobs-on-gmt-not-local-time - Ciro Santilli OurBigBook.com
13个回答

我在Trusty (14.04)上遇到过类似的问题。通过设置机器的时区然后重新启动 cron 服务解决了它。
1. `sudo dpkg-reconfigure tzdata` - 按照指示选择地区/国家 2. `sudo service cron restart` 3. `timedatectl` - 验证您的日期设置

1设置时区后,您可以在命令行中键入“date”来确认日期是否与您的预期相符。 - mydoghasworms
我已经重新启动了cron,但它仍然使用旧的时区(UTC)吗? - Luke
1这在我的18.10上无缝运行。 ~$ date返回正确的时间。一定要喜欢那些鲜艳的DOS样式GUI界面!谢谢。 - itsricky
可以在18.04.5上确认这个。 - kommradHomer
成功了!谢谢! - Philippe Remy
但是cron在解释计划模式时使用了吗?小时1是指UTC的1还是本地时间的1? - Cerin
也适用于Ubuntu 20.04 LTS。 - undefined

没有简单的方法来实现这个。cron使用本地时间。/etc/default/cron和crontab中的其他TZ规范只是指定了cron启动的进程应该使用什么TZ,它不影响启动时间。
我见过的大多数解决方案都涉及到一个中间工具,因此cron会启动一个工具来确定何时在UTC时间启动(例如,如果您只关心夏令时更改,可以提前2小时启动,计算时间差异,然后再启动。看看at。为此,人们经常使用perlpython或类似的脚本语言)。
如果你愿意,也有一种可怕的方式可以进行黑客攻击。cron只在系统启动时读取TZ信息。所以如果这是一个一直运行的服务器,你可以将TZ设置为UTC,重启,然后在启动后将其设置为你的本地时区。你也可以编写脚本来实现这一点。
作为另一种替代方法,还可以查看cron的@reboot语法,它应该在启动后执行脚本,听起来像是你想要的。

/etc/default/cron 在 Ubuntu 20 版本中已被弃用。 - user30994

有一个文件控制系统的时区。 我刚遇到了同样的问题,这里是解决方案:
如果你没有手动配置任何时区,运行date应该显示UTC时间。
  • 创建备份

    sudo cp /etc/localtime /etc/localtime.bkp
    
  • 删除文件:

    sudo rm /etc/localtime
    
  • 我住在芝加哥,(你可能需要更改路径,使用Tab键可以帮助)所以:

    sudo ln -s /usr/share/zoneinfo/America/Chicago /etc/localtime
    
  • 然后重启。 当系统启动时执行: date

  • 现在你的时区应该正确了,cron将会参考这个。

FYI:设置TZ变量只是一个临时解决方案,有时可能起到“掩饰”的作用。

5对于与CentOS兼容的解决方案(以及EC2 Amazon Linux),给一个赞。完全重新启动可能是个好主意,但对我来说,date命令在不重启的情况下就能正常工作,而且只需通过重新启动操作系统 sudo service crond restart 就足以修复我的定时任务时间。 - davur
@davur 谢谢你的建议。对我来说,这个方法很有效,而且不需要重新启动。 - Master.Aurora

截至2017年3月,我发现crond在每个crontab中支持CRON_TZ变量。
引用: CRON_TZ变量指定了cron表格所使用的特定时区。用户应该根据指定的时区输入时间到表格中。写入日志文件时使用的时间取自守护进程所运行的本地时区。
——摘自crontab(5)手册页
这使得我能够以本地时间指定每个cron作业的执行时间,并自动考虑夏令时,而服务器仍保持在UTC时间。
请注意,这是在CentOS 7发行版上使用cronie 1.4实现的。

我还发现这个链接很有帮助:https://serverfault.com/questions/848829/how-to-use-timezone-with-cron-tab。为了找到我需要的时区选项,我输入了`ls /usr/share/zoneinfo/America`来查看可用选项。 - cheevahagadog
你是在哪个操作系统上阅读这个 manpage 的?我在 Ubuntu 18 上没看到它。 - John Bachir
1Ubuntu 20.04 LTS的crontab(5)手册页中没有CRON_TZ。它仍然说:“目前不支持每个用户的时区。” - xpt
1这个答案不适用于任何版本的Ubuntu。 - muru

好的,我花了一些时间在Ubuntu Natty上弄清楚如何做到这一点,以下是我是如何使其工作的。可能有更优雅的方法,但这种方法有效。

首先,我们需要将cron可执行文件包装在一个设置TZ变量的shell中。具体步骤如下:

cd /usr/sbin
mv cron cron.real

然后,创建一个新的 `/usr/sbin/cron` 文件。我用的是 vim,但你可以使用任何编辑器,只要让文件看起来像这样:
#!/bin/bash
export TZ=UTC
/usr/sbin/cron.real

使新的 cron 文件可执行:
chmod ugo+rx cron

现在,重新启动cron守护进程:
service cron restart

你的定时任务现在将按照基于UTC的时间表运行 - 但是,尽管它们执行的时间将是UTC,但当它们运行时,它们的时区将设置为系统定义的时区。要更改这一点,请在任何命令之前将以下内容放入你的crontab中:
TZ=UTC

所以你的crontab将看起来像这样:
# Edit this file to introduce tasks to be run by cron.
# 
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
# 
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').# 
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
# 
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
# 
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
# 
# For more information see the manual pages of crontab(5) and cron(8)
# 
# m h  dom mon dow   command
TZ=UTC
00 19 * * * date > /tmp/date.log

1在两个地方设置TZ=UTC有什么意义呢?你不能只把它放在crontab文件中吗? - Phương Nguyễn
不。在crontab文件中设置TZ=UTC只会将其应用于cron作业,而不是cron本身。它不会影响作业执行的时间。 - Mark Reed
我花了一个多小时才弄清楚 cron 表现得很疯狂并且“不尊重”小时设置,因为它仍然处于错误的时区。几天前我改变了系统时区并忘记了。我只需要重新启动 cron,谢谢! - msb

  1. 请查看 /etc/default/cron。你可以在这里设置 -所有- crontab 的 TZ,应该是 TZ=UTC。所以你的方法应该是有效的。

  2. 看一下fcron。你可以在不同的时区设置单独的 crontab:

    timezone-name '系统的时区'

    在给定的时区运行任务。timezone-name 是一个字符串,对于环境变量 TZ 是有效的:请参考您的系统文档获取更多详细信息。例如,在 Linux 系统上,“Europe/Paris” 是有效的。此选项可以正确处理夏令时的变化。当运行定义了此选项的作业时,TZ 环境变量将被设置为 timezone 的值。

    请注意,如果你提供了错误的 timezone-name 参数,它将被静默忽略,并且作业将在系统的时区中运行。


我检查了一下,只有当我将触发时间设置为本地时间时,crontab才起作用。将时间设置为UTC就不起作用。 - alj
四年过去了,我查看了/etc/default/cron文件,现在它已经正式弃用了。 - Randy L
四年后还有人踩?是的,现在已经无效了,但过去并非如此。不过,希望现在没有人再使用11.04这个用户名了。 - Rinzwind
4如果这个答案是无效的,你应该删除它;在StackExchange上故意保留错误信息是没有意义的。对于那些寻找正确信息的访问者来说,它曾经是相关和/或正确的几乎是无关紧要的。 - Quuxplusone

请参考我的下一篇文章,以获取适用于Ubuntu的解决方案。
我知道这是一个Ubuntu论坛,但我相信答案与在Red Hat系统上执行此操作的方式非常相似。我手头没有Ubuntu系统来测试,但我已经在Red Hat上进行了测试。
您只需要在cron守护进程的初始化脚本中添加一行代码。设置并导出环境变量TZ,就像这样:
export TZ=UTC

然后重新启动您的cron守护程序。确保将此导出放在cron守护程序启动脚本中的任何其他变量设置和源代码之后 - 我认为这可能是原帖编辑/etc/default/cron脚本对他无效的原因。也许他设置了它,但随后在脚本中的其他位置被重置了。
请注意,这只会影响cron守护程序本身,而不会影响通过cron运行的作业,因此如果您想要一个cron作业使用UTC作为其时区,您还需要在作业本身中进行设置。
您可能无法直接复制此内容并使其在Ubuntu上正常工作,但以下是我用于在Red Hat上测试此功能的初始化脚本。您将在start()函数之前找到该导出语句。
#!/bin/sh
#
# crond          Start/Stop the cron clock daemon.
#
# chkconfig: 2345 90 60
# description: cron is a standard UNIX program that runs user-specified \
#              programs at periodic scheduled times. vixie cron adds a \
#              number of features to the basic UNIX cron, including better \
#              security and more powerful configuration options.

### BEGIN INIT INFO
# Provides: crond crontab
# Required-Start: $local_fs $syslog
# Required-Stop: $local_fs $syslog
# Default-Start:  2345
# Default-Stop: 90
# Short-Description: run cron daemon
# Description: cron is a standard UNIX program that runs user-specified 
#              programs at periodic scheduled times. vixie cron adds a 
#              number of features to the basic UNIX cron, including better 
#              security and more powerful configuration options.
### END INIT INFO

[ -f /etc/sysconfig/crond ] || { 
    [ "$1" = "status" ] && exit 4 || exit 6 
}

RETVAL=0
prog="crond"
exec=/usr/sbin/crond
lockfile=/var/lock/subsys/crond
config=/etc/sysconfig/crond

# Source function library.
. /etc/rc.d/init.d/functions

[ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog

export TZ=UTC
start() {
    if [ $UID -ne 0 ] ; then
        echo "User has insufficient privilege."
        exit 4
    fi
    [ -x $exec ] || exit 5
    [ -f $config ] || exit 6
    echo -n $"Starting $prog: "
    daemon $prog $CRONDARGS
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
}

stop() {
    if [ $UID -ne 0 ] ; then
        echo "User has insufficient privilege."
        exit 4
    fi
    echo -n $"Stopping $prog: "
    if [ -n "`pidfileofproc $exec`" ]; then
        killproc $exec
        RETVAL=3
    else
        failure $"Stopping $prog"
    fi
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
}

restart() {
    stop
    start
}

reload() {
    echo -n $"Reloading $prog: "
    if [ -n "`pidfileofproc $exec`" ]; then
        killproc $exec -HUP
    else
        failure $"Reloading $prog"
    fi
    retval=$?
    echo
}

force_reload() {
    # new configuration takes effect after restart
    restart
}

rh_status() {
    # run checks to determine if the service is running or use generic status
    status -p /var/run/crond.pid $prog
}

rh_status_q() {
    rh_status >/dev/null 2>&1
}


case "$1" in
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart)
        $1
        ;;
    reload)
        rh_status_q || exit 7
        $1
        ;;
    force-reload)
        force_reload
        ;;
    status)
        rh_status
        ;;
    condrestart|try-restart)
        rh_status_q || exit 0
        restart
        ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
        exit 2
esac
exit $?

你还可以使用timedatectl来查找和设置时区。(Ubuntu 18)
timedatectl list-timezones
timedatectl set-timezone America/Los_Angeles
service cron restart

添加

TZ="Europe/Warsaw"

但不在etc中!: 运行cron服务编辑器

systemctl edit cron.service

然后,在你添加和保存之后,如上所述,运行。
service cron restart

其他的有一点点樟脑球的气味,希望这个答案能够脱颖而出! - brasofilo

更新了针对较新版本 cron 的答案。

sudo systemctl edit cron.service 如果该文件不存在将创建一个。 添加 'TZ=EST'、'TZ=UTC' 等等