DevToolBox

cronのタイムゾーンの罠 - サーバー時刻と日本時間のズレ

最終更新日: 2026-07-22公開日: 2026-07-22執筆: DevToolBox編集部

cronは通常、OS(システム)に設定されたタイムゾーンを基準にスケジュールを解釈します。それが利用者の期待するタイムゾーンとは限らないため、式が正しくても実行時刻がずれることがあります。

Cron normally interprets schedules in the system timezone, which may differ from the timezone you expect. UTC defaults in servers and containers are a common reason a job runs nine hours late in Japan.

1. UTCサーバーではJSTのつもりの式が9時間ずれる

# 毎日9:00(cronが解釈するタイムゾーン)
0 9 * * * /path/to/job.sh

クラウド環境、最小構成のLinuxイメージ、Dockerコンテナなどは、デフォルトがUTCであることが多いです。上の式を「日本時間の9時」のつもりで書いても、サーバーがUTCならUTC 9:00、つまりJST 18:00に実行されます。

2. システムのタイムゾーンを確認する

# systemd環境
timedatectl

cat /etc/timezone
date

timedatectl の「Time zone」、/etc/timezone の地域名、date の出力に含まれるUTCやJSTなどを確認します。環境によっては /etc/timezone が存在しないため、複数の情報を照合してください。

3. CRON_TZでスケジュールの解釈を変える

CRON_TZ=Asia/Tokyo
0 9 * * * /path/to/job.sh

Vixie cron系やcronieなどには、CRON_TZ=Asia/Tokyo をcrontabの先頭やジョブの前に指定し、そのジョブまたは以降の行のスケジュール解釈を変更できる実装があります。ただしCRON_TZはPOSIX標準ではない実装依存の拡張です。利用中の環境で man 5 crontab を確認してください。

4. システム全体のタイムゾーンを変更する

sudo timedatectl set-timezone Asia/Tokyo
timedatectl

systemd環境ではシステム全体をJSTへ変更できます。cron以外のログやアプリケーションにも影響するため、運用方針を確認してから変更します。UTCで統一する方針なら、式をUTCへ換算する方法もあります。

5. DockerではtzdataとTZ設定を確認する

# Dockerfileの例(Debian/Ubuntu系)
RUN apt-get update && apt-get install -y --no-install-recommends tzdata
ENV TZ=Asia/Tokyo

# ホスト設定を使う例
docker run -v /etc/localtime:/etc/localtime:ro ...

コンテナは素の状態ではtzdataがなく、UTCのままになることがあります。ベースイメージに合ったtzdataパッケージの導入と TZ 環境変数の設定、または /etc/localtime のマウントが必要になる場合があります。イメージやcron実装ごとに挙動を確認してください。

6. クラウド・コンテナスケジューラを比較する

次は2026年7月の執筆時点における代表例です。サービスの世代やバージョンで仕様が異なるため、利用中の公式ドキュメントを最終確認してください。

サービスタイムゾーンの扱い確認ポイント
AWS EventBridge scheduled rule(従来機能)UTC基準EventBridge Schedulerとは別機能
AWS EventBridge SchedulerUTCまたはIANA名を指定可能--schedule-expression-timezone と夏時間
GitHub Actions on.scheduleUTC基準高負荷時の遅延にも注意
Kubernetes CronJobv1.27以降は .spec.timeZone がstable未指定時はcontroller側のローカル時刻
Google Cloud SchedulerIANA名を指定可能、既定UTC夏時間による重複・欠落

クラウドのcron構文はLinuxの5フィールド形式と一致するとは限りません。AWSの一部機能は年フィールドや ? を使います。Linux用の式をそのまま貼らず、サービスが表示する次回実行予定も確認します。

AWS EventBridgeなどのクラウドスケジューラでは、cron式がUTC基準であることが一般的です。一方、タイムゾーンを指定できる機能や対象サービスもあり、構文もLinux cronとは異なる場合があります。利用サービスのドキュメントで、基準時刻と夏時間の扱いを確認してください。

7. 9時間ずれをログから切り分ける実例

「JST 9:00の集計が18:00に届いた」場合、まず設定変更をせず、予定時刻、cronの起動記録、ジョブ自身のログを同じ基準へ変換して並べます。

date -Is
TZ=UTC date -Is
TZ=Asia/Tokyo date -Is
journalctl -u cron --since '2026-07-22 00:00:00'
printf 'job_start=%s epoch=%s
' "$(date -Is)" "$(date +%s)"
  1. crontabが 0 9 * * * であることを確認します。
  2. timedatectl がUTCなら、予定はUTC 9:00だと仮説を立てます。
  3. システムログとジョブログのUNIX時刻を照合します。
  4. UTC 9:00がJST 18:00になることで差を説明できるか確認します。
  5. CRON_TZ、UTC換算、システム変更から運用方針に合う方法を選びます。

ログ表示だけがUTCで、実行自体は予定どおりの場合もあります。UNIX時刻はタイムゾーンに依存しない比較軸になるため、ISO形式と併記すると誤認を減らせます。

8. systemd timerを代替として使う

systemd環境では、cronの代わりにtimerユニットの OnCalendar= で定期処理を起動できます。依存関係、実行ユーザー、journalへの記録をユニットとして管理でき、次回時刻を確認できる点が便利です。

# daily-report.timer の概念例
[Timer]
OnCalendar=*-*-* 09:00:00 Asia/Tokyo
Persistent=true

systemd-analyze calendar '*-*-* 09:00:00 Asia/Tokyo'

対応構文やタイムゾーン指定はsystemdのバージョンで差があり得ます。man systemd.timesystemd-analyze calendar で確認してください。停止中に逃した実行の補完を使う場合はジョブの冪等性も検討します。

9. 次回実行時刻を事前に確認する

設定後はCron Parserで次回実行予定を確認し、表示と実行環境のタイムゾーンが一致しているかも確認します。UTCとJSTの対応はTimezone Converterで変換できます。

よくある間違い

English summary

Cron usually evaluates schedules in the system timezone. On a UTC server, 0 9 * * * runs at 18:00 JST. Check the host with timedatectl, cat /etc/timezone, or date. Some Vixie-cron-derived implementations support CRON_TZ=Asia/Tokyo, but it is not POSIX and must be verified in man 5 crontab. Containers may also need tzdata and explicit timezone configuration.

関連ツール / Related tools

関連ガイド / Related guides