締め切りと時刻の取り違え|明日まで・営業日・UTC・BETWEEN の落とし穴
同じ「明日」「10/20」「02:00」でも、人とサーバーで指す時刻が違うことがあります。締め切りと時刻の取り違えが起きる仕組みと、書き方の型を整理します。
「明日までにお願い」「10/20 の 02:00 に停止」。日付や時刻は、書いた人と読んだ人が同じものを思い浮かべていると思い込みやすい情報です。ところが実際には、送った時刻、休日の扱い、タイムゾーン、データベースの型によって、同じ文字列が別の瞬間を指します。食い違いはどちらかの不注意というより、言葉や仕組みに解釈の幅があることから起きます。この記事では、伝達と技術の両面から日付・時刻の落とし穴を整理し、取り違えを防ぐ書き方を紹介します。
締め切りの言葉は人によって指す日が違う
期限を表す言葉の多くは、基準となる「今日」や「休日」を前提にしています。その前提が送り手と受け手でずれると、言葉は同じでも期限が 1 日以上ずれます。よく食い違う言い方を表にまとめます。
| 言い方 | 食い違う理由 | 確かめ方の例 |
|---|---|---|
| 深夜 0 時台の「明日まで」 | 送り手はまだ前日の夜のつもりで書いている | 「本日 10/16(金)中ですね。何時まででしょうか」 |
| 「今週中」 | 金曜の終業か、土日を含むかが決まらない | 「10/23(金)の何時までですか」 |
| 「月末まで」 | 暦の最終日か、最終営業日かで変わる | 「10/30(金)と 10/31(土)のどちらですか」 |
| 「2 営業日前」 | 祝日を営業日に数えてしまう | 具体的な日付に直して共有する |
| 「EOD」「by end of day」 | 誰の終業か、どのタイムゾーンかが書かれていない | 「By 18:00 JST, Oct 20?」と返す |
深夜 0 時台の「明日」と、休日に当たる「月末」
10/16(金)の 0 時 40 分に「明日までに」と届いた場合、送った人は 10/15(木)の夜のつもりで書いている可能性が高く、期限は 10/16(金)かもしれません。暦どおり 10/17(土)と受け取ると、1 日遅れるうえに休日に当たります。「月末」も同じで、2026 年 10 月 31 日は土曜日です。経理の締めのように営業日で動く仕事では、「月末」が最終営業日の 10/30(金)を指していることがあります。
営業日は土日と祝日を飛ばして数える
「リリースの 2 営業日前」のような決め方は、祝日が挟まると数え間違えやすくなります。土日祝が休みの会社で、リリースが 11/5(木)なら、1 営業日前は 11/4(水)です。11/3(火)は文化の日なので飛ばし、2 営業日前は 11/2(月)になります。祝日を数えてしまうと 1 日遅い期限を信じて作業することになるので、営業日で決めた期限は、その場で具体的な日付に直して共有します。
日付と曜日が食い違ったら、推測せずに聞く
2026 年 10 月 16 日(金)に「来週月曜(10/20)でお願いします」と届いたとします。来週月曜は 10/19 で、10/20 は火曜日です。曜日と日付のどちらが打ち間違いかは、文面からは分かりません。片方を信じて手配すると、外れたときに作業員が来ない、立ち会いがいないといった事態になります。「10/19(月)と 10/20(火)のどちらでしょうか」と両方を書いて聞けば、1 回のやり取りで確定できます。
曜日は思い込みで書くと間違えます。自分が期限を書くときも、相手の日付を読むときも、カレンダーアプリか cal コマンドで実際の暦を確かめます。cal 10 2026 で 2026 年 10 月の暦が表示されます。
期限は「日付+曜日+時刻+タイムゾーン」で書く
取り違えを防ぐいちばん確実な方法は、解釈の幅がない形で書くことです。日付だけでは何時までか分からず、曜日を添えると日付の打ち間違いに読み手が気づけます。時刻を書けば朝と夜の食い違いがなくなり、タイムゾーンを書けば海外拠点やサーバーとの換算ができます。
× 明日までに修正をお願いします○ 10/16(金)17:00 JST までに修正をお願いします× 今週中にレビューをお願いします○ 10/16(金)18:00 JST までにレビューをお願いします× Code freeze: Oct 20 15:00○ Code freeze: 2026-10-20 15:00 UTC(10/21(水)0:00 JST)記録やチケット、ログに残す時刻は、ISO 8601 の形式にすると機械でも人でも誤読しにくくなります。2026-10-20T15:00:00Z の末尾の Z は UTC を表し、同じ瞬間を日本時間で書くと 2026-10-21T00:00:00+09:00 です。「10/20」のような書き方は国によって月と日の順序が違うので、海外とのやり取りでは年から順に書く形が安全です。
ログやクラウドの時刻は UTC であることが多い
サーバーやクラウドサービスは、時刻を UTC で記録・表示することがよくあります。AWS の CloudTrail のイベント時刻は UTC で記録され、クラウドの仮想マシンも初期設定のタイムゾーンが UTC のことが多くあります。JST は UTC+9 なので、UTC の時刻に 9 時間を足すと日本時間になります。足すか引くかを逆にすると、障害の発生時刻を 18 時間ずれて調べることになります。
date # サーバーのタイムゾーンでの現在時刻date -u # UTC での現在時刻TZ=Asia/Tokyo date # 日本時間での現在時刻timedatectl # systemd のある Linux で設定中のタイムゾーンを表示ログを調べるときは、最初に「このログの時刻はどのタイムゾーンか」を確かめます。オフセットや Z が付いていないログは特に注意が必要です。お客様からの「10 時ごろにエラーが出た」という報告は普通は日本時間なので、UTC のログでは 1:00 前後を探すことになります。
cron とスケジューラーのタイムゾーン
cron は、cron を動かしているサーバーのタイムゾーンで時刻を解釈します。告知が「10/20 02:00(JST)にメンテナンス」で、サーバーが UTC なら、0 2 20 10 * と書くと日本時間 11:00 に実行され、日中にサービスが止まります。JST 02:00 に動かすには、UTC で前日 10/19 の 17:00、つまり 0 17 19 10 * と書きます。cronie のように crontab に CRON_TZ=Asia/Tokyo を書いてタイムゾーンを指定できる実装もありますが、すべての cron が対応しているわけではないので、使う前にそのサーバーの man 5 crontab で確かめます。AWS でも、EventBridge のスケジュールルールの cron 式は UTC で評価され、EventBridge Scheduler ではタイムゾーンを指定できるというように、サービスごとに扱いが違います。
夏時間がある国とは時差が変わる
米国や欧州の多くの地域には夏時間があり、年に 2 回 UTC との差が 1 時間変わります。2026 年は、英国の夏時間が 10/25(日)に、米国の夏時間が 11/1(日)に終わります。ニューヨークは UTC-4 から UTC-5 に、ロンドンは UTC+1 から UTC+0 になり、日本との時差は 1 時間広がります。定例会議の時刻や、海外拠点との締め切りは、この時期にずれやすくなります。プログラムで扱うときは「UTC-5」のような固定のオフセットではなく、America/New_York のようなタイムゾーン名を使うと、夏時間の切り替えを自動で反映できます。
DB に保存する時刻は、型とタイムゾーンを決めておく
データベースの日時型には、タイムゾーンを考慮するものとしないものがあります。どちらを使っているかを知らないと、保存した時刻を別のタイムゾーンの時刻として読み、9 時間ずれた集計や通知が生まれます。代表的な型を整理します。
| DB と型 | タイムゾーンの扱い |
|---|---|
| PostgreSQL の timestamp with time zone(timestamptz) | オフセットの無い入力はセッションのタイムゾーンで解釈し、UTC に直して保存し、表示時にセッションのタイムゾーンへ変換する |
| PostgreSQL の timestamp without time zone | タイムゾーンを持たず、書いた値をそのまま保存する |
| MySQL の TIMESTAMP | セッションのタイムゾーンから UTC に変換して保存し、取り出すときに戻す。範囲は 2038-01-19 まで |
| MySQL の DATETIME | タイムゾーンの変換をせず、書いた値をそのまま保存する |
一般的な方針は「保存は UTC、表示するときに利用者のタイムゾーンへ変換」です。保存する時刻の基準を 1 つに決めておけば、サーバーの設定やアプリケーションの実行場所が変わっても値の意味が変わりません。既存のテーブルを触るときは、まず列の型と、アプリケーションがどのタイムゾーンで書き込んでいるかを確かめます。
日付の範囲は「開始以上、翌日未満」の半開区間で書く
「10 月分のデータ」を BETWEEN '2026-10-01' AND '2026-10-31' で絞るのは、よくある落とし穴です。BETWEEN は両端を含みますが、列に時刻まで入っていると、終端の '2026-10-31' は 10/31 の 0 時ちょうどまでしか含みません。10/31 の昼の注文は集計から漏れ、エラーも出ないので気づきにくくなります。
-- t: '2026-10-01 09:00:00', '2026-10-31 00:00:00', '2026-10-31 10:00:00', '2026-11-01 00:00:00'SELECT COUNT(*) FROM ordersWHERE t BETWEEN '2026-10-01' AND '2026-10-31'; -- 1 件(10/31 の 2 件が漏れる)SELECT COUNT(*) FROM ordersWHERE t >= '2026-10-01' AND t < '2026-11-01'; -- 3 件SQLite では文字列として比べるため、'2026-10-31 00:00:00' も '2026-10-31' より大きいと判定されて漏れます。PostgreSQL の timestamp 型なら '2026-10-31' は 10/31 の 0 時として扱われるので、0 時ちょうどの行は含まれます。どちらにしても 10/31 の残りの時間は漏れます。開始を含み終端を含まない半開区間(>= と < 翌日)で書けば、型や時刻の精度に関係なく、月や日の区切りを正しく表せます。
月末と「1 か月後」の計算
1/31 の「1 か月後」は道具によって結果が違います。SQLite の date('2026-01-31', '+1 month') は存在しない 2/31 を繰り越して '2026-03-03' を返し、Linux(GNU)の date -d '2026-01-31 +1 month' +%F も同じく 2026-03-03 になりますが、macOS(BSD)の date -j -f %Y-%m-%d -v+1m 2026-01-31 +%F は 2026-02-28 を返します。月末の日付が欲しいときは、月初に 1 か月足して 1 日戻す形にすると確実です。
SELECT date('2026-02-15', 'start of month', '+1 month', '-1 day'); -- 2026-02-28日付と時刻を扱う前のチェックリスト
- 期限に日付・曜日・時刻・タイムゾーンがそろっているか。足りなければ、具体的な日時で復唱して確かめる。
- 曜日をカレンダーや
calで確かめたか。日付と曜日が食い違っていたら、両方を書いて相手に聞く。 - 「営業日」「月末」を、土日祝を除いた具体的な日付に直したか。
- ログ、cron、クラウドのスケジュールが、どのタイムゾーンで時刻を扱うかを確かめたか。
- 海外とのやり取りで、夏時間の切り替え時期に当たっていないか。
- SQL の日付範囲を
>=開始と<翌日の半開区間で書いたか。
日付と時刻の取り違えは、知っていれば一言の確認で防げるものがほとんどです。ベテランは「何日の何時、どこの時間で」を自然に確かめていますが、それは過去に食い違いを経験して型を身につけたからです。下の問題で、締め切りや時刻のずれを見抜けるか試してみてください。
問題で確かめる
この記事の内容を、制限時間つきの問題で確かめられます。