Linuxでシェルのタイムゾーンを確認・設定する方法

シェルのタイムゾーンを一時変更するときは、TZの値だけでなく「変数がsetかunsetか」を保存します。元がsetなら同じ値をexportし直し、元がunsetならunsetへ戻します。system timezoneは変更せず、shell表示のzoneとUTC offsetまで復旧条件にします。

目次

set状態とexact valueを保存する

${TZ-<unset>}の表示文字列をbaseline値として使うと、本当の文字列とunsetを区別できません。Bashの[[ -v TZ ]]で状態を保存し、値、%Z:%z、timedatectlのsystem zoneを別fieldとして記録します。4ブロックは同じshellで実行します。

set -Eeuo pipefail
if [[ -v TZ ]]; then
  tz_was_set=1
  tz_saved=$TZ
else
  tz_was_set=0
  tz_saved=''
fi
tz_saved_zone=$(date '+%Z:%z')
system_zone_before=$(timedatectl show --property=Timezone --value)
printf 'TZ_was_set=%s TZ_value=%q shell_zone=%s system_zone=%s\n' "$tz_was_set" "$tz_saved" "$tz_saved_zone" "$system_zone_before"

現在のshellだけを一時変更する

export TZ=Asia/Tokyoは現在shellとそこから起動する子processだけに作用します。JST:+0900を確認し、timedatectlの値がbaselineから変わっていないことを必須にします。

export TZ=Asia/Tokyo
test "$TZ" = 'Asia/Tokyo'
test "$(date '+%Z:%z')" = 'JST:+0900'
test "$(timedatectl show --property=Timezone --value)" = "$system_zone_before"
printf 'temporary_TZ=%s display=%s system_unchanged=%s\n' "$TZ" "$(date --iso-8601=seconds)" "$system_zone_before"

unsetとUTCの2 fixtureを検証する

subshell内で初期unsetと初期TZ=UTCの両方を作り、一時変更後にset状態、exact value、dateのzone/offsetがbaselineへ戻ることを自動検証します。subshellなので外側のTZは変更しません。

verify_restore_case() (
  case $1 in
    unset) unset TZ ;;
    UTC) export TZ=UTC ;;
    *) return 90 ;;
  esac
  if [[ -v TZ ]]; then saved_set=1; saved_value=$TZ; else saved_set=0; saved_value=''; fi
  saved_zone=$(date '+%Z:%z')
  export TZ=Asia/Tokyo
  if test "$saved_set" -eq 1; then export TZ="$saved_value"; else unset TZ; fi
  if test "$saved_set" -eq 1; then [[ -v TZ ]] && test "$TZ" = "$saved_value"; else [[ ! -v TZ ]]; fi
  test "$(date '+%Z:%z')" = "$saved_zone"
)
verify_restore_case unset
verify_restore_case UTC
printf 'fixture_restore=pass cases=unset,UTC\n'

実shellをexact restoreする

保存したstateに従い、setなら空文字を含む同値をexportし、unsetならunsetします。値だけでなく[[ -v TZ ]]、%Z:%z、system timezoneが一致した場合だけ復旧完了です。

if test "$tz_was_set" -eq 1; then
  export TZ="$tz_saved"
else
  unset TZ
fi
if test "$tz_was_set" -eq 1; then
  [[ -v TZ ]] && test "$TZ" = "$tz_saved"
else
  [[ ! -v TZ ]]
fi
test "$(date '+%Z:%z')" = "$tz_saved_zone"
test "$(timedatectl show --property=Timezone --value)" = "$system_zone_before"
printf 'restored TZ_set=%s TZ_value=%q shell_zone=%s system_zone=%s\n' "$tz_was_set" "$tz_saved" "$(date '+%Z:%z')" "$system_zone_before"

受入条件

初期unsetでは復旧後も[[ ! -v TZ ]]、初期UTCではTZ=UTCかつUTC:+0000です。実環境では保存した任意値とzone/offsetへ戻り、timedatectlは全工程で不変です。

system設定と混同しない

対話shellのexportはcron、既存service、別terminalを変更しません。system timezone変更が要件なら、影響範囲、DST、service restartを別の承認作業として設計し、この一時表示手順へ混ぜないでください。

one-command scopeで子processへの継承を切り分ける

TZ=値 commandの形式なら、親shellのTZを変更せず、そのcommandと子processだけにtimezoneを渡せます。比較時刻は各commandの実行時刻ではなく同じepoch秒へ固定し、UTCとAsia/Tokyoの表示差だけを測ります。これにより処理時間の差をtimezone差と誤認しません。実行前後には親のset/unset状態、exact value、timedatectlのsystem timezoneを再照合し、shell scopeの検証をsystem変更の証跡として扱わないことが重要です。

epoch=$(date +%s)
if [[ -v TZ ]]; then parent_tz_set=1; parent_tz_value=$TZ; else parent_tz_set=0; parent_tz_value=''; fi
parent_system_zone=$(timedatectl show --property=Timezone --value)
for zone in UTC Asia/Tokyo; do
  test -e "/usr/share/zoneinfo/$zone"
  TZ="$zone" date --date="@$epoch" '+scope=child epoch=%s zone=%Z offset=%z iso=%Y-%m-%dT%H:%M:%S%:z'
done
if test "$parent_tz_set" -eq 1; then [[ -v TZ ]] && test "$TZ" = "$parent_tz_value"; else [[ ! -v TZ ]]; fi
test "$(timedatectl show --property=Timezone --value)" = "$parent_system_zone"
printf 'parent_TZ_set=%s parent_TZ_value=%q system_zone=%s
' "$parent_tz_set" "$parent_tz_value" "$parent_system_zone"

DST境界は略称ではなくoffsetとepochで判定する

地域timezoneには夏時間や過去の規則が含まれるため、JSTのような固定offsetの例だけで地域timezone全般を判定できません。運用対象の地域は、切替前後を含む既知のepoch秒を入力にして、%zまたはISO 8601の数値offsetと日時を記録します。%Zの略称は表示用とし、同じ略称が別地域で使われる可能性を考慮します。将来時刻の検証では、そのhostに入っているtimezone databaseの版も作業記録へ残します。

zone=America/New_York
test -e "/usr/share/zoneinfo/$zone"
for instant in 2026-01-15T12:00:00Z 2026-07-15T12:00:00Z; do
  epoch=$(date --date="$instant" +%s)
  TZ="$zone" date --date="@$epoch" '+input_epoch=%s local=%Y-%m-%dT%H:%M:%S%:z label=%Z'
done

serviceやsystem全体の変更とは作業票を分ける

export TZは現在のshellと、その後に起動した子processへ継承されます。すでに起動済みのservice、別login session、container、system timezoneが同時に変わるわけではありません。常駐serviceへ適用する場合は、そのservice managerの環境設定、再起動可否、影響範囲、rollbackを別の承認作業として設計します。本手順の合格条件は親shellのexact restoreとsystem timezone不変であり、serviceの変更完了ではありません。unsetだった状態と空文字を含むset状態は別物なので、値だけでなくset/unsetも保存します。

公式情報・参考資料

シェルのタイムゾーン確認・設定の構文と制約は、本文末の一次資料と対象環境のlocal helpで照合します。シェルのタイムゾーン確認・設定の記事確認日は2026年7月17日で、版が異なる場合はoption、default、終了statusの差を先に確認してください。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次