Python標準ライブラリで時間を扱う:datetime完全攻略
シリーズ 03 – 日付/時間演算、タイムゾーン、フォーマット変換まで一挙に
時間は単なる「文字列」ではありません。日が変わり、月が変わり、サマータイムが入り、地域ごとに基準が異なります。 そのため、日付/時間を扱う際は「表示用文字列」と「計算可能な時間値」を区別し、タイムゾーンまで含めて扱う習慣が重要です。

この記事では datetime モジュールを中心に次を整理します。
- 現在時刻と日付の作成
- 期間計算(
timedelta) - 文字列フォーマット/パース(
strftime,strptime) - タイムゾーン処理(
timezone,zoneinfo) - よく直面する 注意点 と安定したパターン
1. datetime は何を提供するか?
datetime には似ているようで役割が異なる型があります。
date: 年-月-日だけが必要なときtime: 時:分:秒だけが必要なときdatetime: 日付+時間(最も頻繁に使用)timedelta: 時間の「差」(期間)timezone: 固定オフセットタイムゾーン(例:UTC+9のようにオフセットが変わらない場合)
そして Python 3.9+ では標準ライブラリに zoneinfo が追加され、地域タイムゾーン(例:Asia/Tokyo)を扱いやすくなりました。
2. 「今」を得る方法:naive vs aware から整理
2.1 naive / aware とは?
datetime オブジェクトは大きく二つのカテゴリに分かれます。
- naive datetime: タイムゾーン情報がない
- aware datetime: タイムゾーン情報(
tzinfo)がある
これらを混在させて演算/比較するとエラーが出ることもありますし、エラーが出なくても結果が意図と異なることがあります。
2.2 推奨されるデフォルト:UTC aware で始める
保存/計算基準を UTC に統一すると、コードがきれいになるケースが多いです。
from datetime import datetime, timezone
utc_now = datetime.now(timezone.utc) # aware (UTC)
print(utc_now)
ローカル時刻が必要な場合は「表示段階」で変換します。
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
utc_now = datetime.now(timezone.utc)
tokyo_now = utc_now.astimezone(ZoneInfo("Asia/Tokyo"))
print(utc_now)
print(tokyo_now)
3. 日付/時間計算:timedelta が中心
3.1 加算/減算
from datetime import datetime, timedelta, timezone
now = datetime.now(timezone.utc)
print(now + timedelta(days=3))
print(now - timedelta(hours=2))
3.2 二つの時刻の差
from datetime import datetime, timezone
a = datetime(2026, 1, 1, tzinfo=timezone.utc)
b = datetime(2026, 1, 10, tzinfo=timezone.utc)
delta = b - a
print(delta.days) # 9
print(delta.total_seconds()) # 777600.0
3.3 timedelta で「期間」を表現する感覚
timedelta は 日/秒/マイクロ秒 単位で動作します。
「一か月後」のように月の長さが変わる表現は timedelta(days=30) で大まかに合わせることはできますが、カレンダー基準の「次の月同じ日」は別のアプローチが必要です(この部分は標準ライブラリの範囲外で dateutil などがよく使われます)。
4. フォーマットとパース:strftime / strptime
4.1 datetime → 文字列(strftime)
from datetime import datetime, timezone
dt = datetime(2026, 1, 30, 14, 5, 0, tzinfo=timezone.utc)
print(dt.strftime("%Y-%m-%d %H:%M:%S %z"))
よく使うフォーマットパターン:
%Y-%m-%d: 2026-01-30%H:%M:%S: 14:05:00%z: +0000 (UTCオフセット)
4.2 文字列 → datetime(strptime)
from datetime import datetime
s = "2026-01-30 14:05:00"
dt = datetime.strptime(s, "%Y-%m-%d %H:%M:%S")
print(dt)
ここで生成された dt は naive です。タイムゾーンを明確にしたい場合は tzinfo を付ける必要があります。
from datetime import datetime, timezone
s = "2026-01-30 14:05:00"
dt = datetime.strptime(s, "%Y-%m-%d %H:%M:%S").replace(tzinfo=timezone.utc)
print(dt)
replace(tzinfo=...)は「時間値を変換」するのではなく その時刻にタイムゾーンラベルを付ける 動作です。 変換が必要ならastimezone()を使用します(次節参照)。
5. タイムゾーン:timezone と zoneinfo を分けて使う
5.1 固定オフセットなら timezone
例:UTC、UTC+9 のようにオフセットが固定の場合
from datetime import datetime, timezone, timedelta
kst_fixed = timezone(timedelta(hours=9))
dt = datetime(2026, 1, 30, 12, 0, tzinfo=kst_fixed)
print(dt)
5.2 地域タイムゾーンなら zoneinfo
サマータイムのようにオフセットが変わる地域は zoneinfo が適しています。
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
utc_now = datetime.now(timezone.utc)
ny_now = utc_now.astimezone(ZoneInfo("America/New_York"))
print(ny_now)
5.3 replace(tzinfo=...) vs astimezone(...) の違い
replace(tzinfo=...): 時刻値はそのまま、タイムゾーンだけ「ラベリング」astimezone(...): 同じ瞬間を別のタイムゾーンの時刻に「変換」
この違いを知っておくと、タイムゾーン関連のバグを大幅に減らせます。
6. よく直面する注意点まとめ
6.1 naive/aware 混用
- 内部計算用時刻は aware(UTC) に合わせると安定します。
- 外部入力は受け取った瞬間にタイムゾーンを決定し、統一するのが良いです。
6.2 「ローカル時間」は環境によって変わることがある
datetime.now() は実行環境のローカル設定を参照します。コンテナ/サーバ環境ではローカルが UTC である場合もありますし、そうでない場合もあります。
環境差を減らすには datetime.now(timezone.utc) のような方法が望ましいです。
6.3 文字列パースのフォーマット不一致
strptime はフォーマットが 1 文字でも違うと失敗します。入力フォーマットが複数ある場合は「前処理」やフォーマット候補を段階的に試すコードが必要です(可能なら入力フォーマットを一つに限定する方が良いです)。
7. よく使うパターン 3 つ
7.1 ISO 8601 形式で保存する
標準的な文字列表現が必要なときは isoformat() が便利です。
from datetime import datetime, timezone
dt = datetime.now(timezone.utc)
print(dt.isoformat()) # 例: 2026-01-30T05:12:34.567890+00:00
7.2 「今日の日付」でファイル名を作る
from datetime import datetime
stamp = datetime.now().strftime("%Y%m%d")
filename = f"report_{stamp}.json"
print(filename)
7.3 特定時刻まで残り時間を計算する
from datetime import datetime, timezone
target = datetime(2026, 2, 1, 0, 0, tzinfo=timezone.utc)
now = datetime.now(timezone.utc)
remaining = target - now
print(remaining)
print(remaining.total_seconds())
8. まとめ
datetime は「日付文字列を作る」だけでなく、時間を 演算可能な値 として扱えるようにする核心ツールです。
タイムゾーン(timezone, zoneinfo) を含めることで、実行環境が変わっても結果が揺らぐことのないコードを作りやすくなります。
次回は random を別に取り上げ、乱数生成/サンプリング/シャッフル/シード、そしてセキュリティ用乱数(secrets)までまとめて解説します。
関連記事 :
前回シリーズを見る