Python 日付フォーマット・日時計算チートシート
「今日の日付がほしい」「文字列を日付に変えたい」「30日後を出したい」——目的から引ける逆引き表です。コードはすべて Python 3.12.10 で実行し、出力をそのまま載せています。
結論:日付だけなら date、時刻も要るなら datetime、期間は timedelta。文字列にするのが strftime、文字列から読むのが strptime。この4つが分かれば日付処理の大半は片づきます。早見表から必要な行へ飛んでください。
1. 逆引き早見表
よく使う順です。「結果」は 2026-09-20 に Python 3.12.10 で実行した出力(現在時刻の行は毎回変わります)。
| やりたいこと | 書くコード | 結果 |
|---|---|---|
| 今日の日付 | date.today() | 2026-09-20 |
| 今の日時 | datetime.now() | 2026-09-20 22:55:34.353069 |
| 今のUTC時刻 | datetime.now(timezone.utc) | 2026-09-20 13:55:34.353069+00:00 |
| 日付 → 文字列 | d.strftime("%Y/%m/%d") | 2026/09/20 |
| 文字列 → 日時 | datetime.strptime(s, "%Y/%m/%d") | 2026-09-20 00:00:00 |
| ISO文字列 → 日付 | date.fromisoformat("2026-09-20") | 2026-09-20 |
| 30日後 | d + timedelta(days=30) | 2026-10-20 |
| 2つの日付の差(日数) | (d2 - d1).days | 102 |
| その月の日数(末日) | calendar.monthrange(2026, 9)[1] | 30 |
| 曜日(月=0〜日=6) | d.weekday() | 6 |
| うるう年かどうか | calendar.isleap(2028) | True |
| 日本時間つきの現在時刻 | datetime.now(ZoneInfo("Asia/Tokyo")) | 2026-09-20 22:55:34.353069+09:00 |
| Excelのシリアル値 → 日時 | datetime(1899, 12, 30) + timedelta(days=45000) | 2023-03-15 00:00:00 |
import は from datetime import datetime, date, timedelta, timezone/import calendar/from zoneinfo import ZoneInfo の3行。すべて標準ライブラリですが、タイムゾーンだけ Windows に例外があります(7章)。
2. date・datetime・time・timedelta の違い
datetime はモジュール名でもクラス名でもあるため、from datetime import datetime という import になります。
| 型 | 持っている情報 | 使いどころ |
|---|---|---|
date | 年・月・日 | 誕生日・締切日・家計簿。時刻が不要なときの既定 |
datetime | 年月日+時分秒+マイクロ秒 | ログの記録時刻・予約時刻・計測の開始と終了 |
time | 時分秒だけ(日付なし) | 「毎日9:00」のような時刻だけの設定値 |
timedelta | 期間(日・秒・マイクロ秒) | N日後の計算・2点間の差・タイマーの残り |
関係は「日付 − 日付 = 期間」「日付 + 期間 = 日付」の2本だけ。import time の time モジュールは datetime.time とは別物で、待機や経過秒の計測は前者が担当します。
3. 今日の日付と現在時刻(utcnow は非推奨)
from datetime import datetime, date, timezone
print(datetime.now()) # 例: 2026-09-20 23:58:12.345678
print(date.today()) # 例: 2026-09-20
print(datetime.now(timezone.utc)) # 例: 2026-09-20 14:58:12.345678+00:00
マイクロ秒が邪魔なら .replace(microsecond=0) を付けます。古い記事で見る datetime.utcnow() は3.12 で非推奨になりました。
datetime.utcnow() # 3.12 以降は DeprecationWarning が出る
datetime.now(timezone.utc) # 置き換え先(UTC だと分かる値が返る)
DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).
返り値が「UTCなのにUTCだという情報を持たない」ためです。astimezone() に渡すとローカル時刻と解釈され、時差の分ずれます。3.14.7 でも警告のまま残っていました。
4. 文字列 ⇄ 日付の変換
f が format(日付→文字列)、p が parse(文字列→日付)と覚えると取り違えが減ります。
日付 → 文字列(strftime)
d = datetime(2026, 9, 20, 7, 5, 3)
print(d.strftime("%Y-%m-%d %H:%M:%S")) # → 2026-09-20 07:05:03
print(d.strftime("%Y年%m月%d日")) # → 2026年09月20日
print(d.strftime("%#m/%#d")) # → 9/20(Windows。Linux・macOS は %-m/%-d)
ゼロ埋めを外す書き方はOSで違います。Windows は %#m、Linux・macOS は %-m(Windows で %-m は ValueError: Invalid format string)。配布するなら f"{d.month}/{d.day}" が安全です。
文字列 → 日時(strptime)
s = "2026/09/20 07:05"
print(datetime.strptime(s, "%Y/%m/%d %H:%M")) # → 2026-09-20 07:05:00
print(datetime.strptime(s, "%Y/%m/%d %H:%M").date()) # → 2026-09-20
strptime は datetime を返すので、日付だけ要るなら .date() を付けます。書式が1文字でも違うとエラーです(8章)。
ISO 8601 形式なら書式指定は不要
ISO 8601 形式は、書式を書かずに読めます。
print(date.fromisoformat("2026-09-20")) # → 2026-09-20
print(datetime.fromisoformat("2026-09-20T07:05:03+09:00")) # → 2026-09-20 07:05:03+09:00
print(datetime(2026, 9, 20, 7, 5, 3).isoformat()) # → 2026-09-20T07:05:03
3.11 で守備範囲が広がり、末尾の Z(UTCの意味)や区切りなしの 20260920 も読めます。3.12.10 では 2026-09-20T07:05:03Z が 2026-09-20 07:05:03+00:00 でした。CSVやJSONの日付列は、まず fromisoformat を試すのが近道です。
5. 書式コード早見表
よく使う15個です。出力は datetime(2026, 9, 20, 7, 5, 3, 123456) に ZoneInfo("Asia/Tokyo") を付けて通した結果。
| コード | 意味 | 出力 |
|---|---|---|
%Y / %y | 西暦4桁 / 下2桁 | 2026 / 26 |
%m / %d | 月 / 日(ゼロ埋め2桁) | 09 / 20 |
%H / %M / %S | 時(24時間制)/ 分 / 秒 | 07 / 05 / 03 |
%f | マイクロ秒(6桁) | 123456 |
%a / %A | 曜日の略称 / 正式名 | Sun / Sunday |
%b / %B | 月の略称 / 正式名 | Sep / September |
%j | 年始からの通算日 | 263 |
%z / %Z | UTCとの時差 / タイムゾーン名 | +0900 / JST |
組むと d.strftime("%Y/%m/%d(%a) %H時%M分") で 2026/09/20(Sun) 07時05分。曜日や月名が英語なのは strftime が既定でCロケールを使うためで、日本語にするならロケール設定より "月火水木金土日"[d.weekday()] と自分で当てるほうがぶれません(6章)。和暦は標準では扱えません。
6. 日付の計算(N日後・差分・月末・曜日)
N日後と、2つの日付の差
from datetime import timedelta
d = date(2026, 9, 20)
print(d + timedelta(days=30)) # → 2026-10-20
print((date(2026, 12, 31) - d).days) # → 102
timedelta には weeks・hours・minutes・seconds も渡せます。日数は .days、総秒数は .total_seconds()。.seconds は日を除いた端数の秒なので、総秒数のつもりで使うとずれます。
月末を出す
import calendar
print(calendar.monthrange(2026, 9)) # → (calendar.TUESDAY, 30)
print(date(2026, 9, calendar.monthrange(2026, 9)[1])) # → 2026-09-30
monthrange は「1日の曜日」と「日数」を返します。1つめは 3.12 から calendar.Day 列挙型で表示されますが中身は整数です。うるう年も考慮されます。
1か月後(標準ライブラリだけでやる)
timedelta に months はありません。1か月は28〜31日と長さが変わり、期間として表せないためです。
def add_months(d, n):
y, m = divmod(d.year * 12 + d.month - 1 + n, 12)
return date(y, m + 1, min(d.day, calendar.monthrange(y, m + 1)[1]))
print(add_months(date(2026, 1, 31), 1)) # → 2026-02-28(末日で丸める)
1月31日の1か月後を2月28日にするか3月3日にするかは、決めるべき仕様です。python-dateutil なら1行で書けます(pip はインストールと環境構築へ)。
曜日を出す
print(d.weekday(), d.isoweekday()) # → 6 7(月=0・日=6 と 月=1・日=7)
print("月火水木金土日"[d.weekday()]) # → 日
起点が2種類あるのでどちらを使うか統一してください。土日判定は d.weekday() >= 5 が定番です。
N営業日後(祝日は考えない簡易版)
def add_business_days(d, n):
while n > 0:
d += timedelta(days=1)
if d.weekday() < 5: # 5=土・6=日 は数えない(祝日は判定していない)
n -= 1
return d
print(add_business_days(date(2026, 9, 18), 3)) # → 2026-09-23
見ているのは曜日だけです。2026年9月21日〜23日には祝日が含まれるため、祝日まで数えるならこの結果は使えません。内閣府が公開する祝日CSVなどの外部データが要ります。
7. タイムゾーン:naive と aware、zoneinfo
日付処理で最後まで残る難所です。日時には2種類あります。
- naive: タイムゾーン情報を持たない。
datetime.now()が返すのはこちら - aware:
tzinfoを持ち、UTCとの時差が確定している(公式はutcoffset()が値を返すものと定義)
この2つは混ぜて計算できません。国内で完結する家計簿なら naive、海外の時刻やUTCログを扱うなら aware、と先に決めてください。
zoneinfo で日本時間を扱う
タイムゾーンは 3.9 で標準ライブラリに入った zoneinfo を使います。pytz を勧める記事も残っていますが、新規のコードはこちらです。
from zoneinfo import ZoneInfo
jst = ZoneInfo("Asia/Tokyo")
t = datetime(2026, 9, 20, 22, 0, tzinfo=jst)
print(t) # → 2026-09-20 22:00:00+09:00
print(t.astimezone(ZoneInfo("UTC"))) # → 2026-09-20 13:00:00+00:00
名前は "JST" ではなく IANA の識別子 "Asia/Tokyo"。astimezone() は時刻そのものを変換します(22:00 JST → 13:00 UTC)。
naive に後から付ける方法は2つあり、意味が違います。replace(tzinfo=jst) は時刻を動かさずラベルを貼るだけ、astimezone(jst) は「PCのローカル時刻だ」と仮定して変換します。日本時間のPCでは同じ値ですが、UTC設定のサーバーでは後者だけ変わります。明示するだけなら replace です。
Windows では tzdata が要る(実測)
zoneinfo はOSのタイムゾーンデータベースを読みますが、Windows にはそれがありません(zoneinfo.TZPATH は空のタプル ())。データ無しで作ると、こうなります。
zoneinfo._common.ZoneInfoNotFoundError: 'No time zone found with key Asia/Tokyo'
新しく作った仮想環境(Python 3.12.10 / Windows 11)での実行結果です。名前の綴りより先にデータの有無を疑ってください。
解決策は、公式も案内するフォールバック用パッケージです。
pip install tzdata
同じ環境に入れたところ(tzdata 2026.4)、先ほどのコードが 2026-09-20 22:00:00+09:00 を返しました(TZPATH は空のままです)。Windows 向けに配るなら tzdata も必要なパッケージとして案内します。Linux・macOS はOS側にあります。
8. よくあるエラー5つ
すべて 3.12.10 で実際に起こした文面です。
① 書式が文字列と合っていない
datetime.strptime("2026/09/20", "%Y-%m-%d")
# ValueError: time data '2026/09/20' does not match format '%Y-%m-%d'
区切りが / なのに書式が - です。実データと指定書式が両方出るので1文字ずつ見比べるのが最短。CSV由来なら末尾の改行や全角スペースも疑ってください(s.strip())。読み方はエラー辞典の ValueErrorへ。
② strftime と strptime の取り違え
datetime.strftime("2026-09-20", "%Y")
# TypeError: descriptor 'strftime' for 'datetime.date' objects doesn't apply to a 'str' object
文字列を日付にしたいのに、日付を文字列にする側を呼んでいます。文字列から読むのは strptime(p = parse)。「'str' object」が渡した値の型を教えています。
③ naive と aware を混ぜた
datetime.now() - datetime.now(timezone.utc)
# TypeError: can't subtract offset-naive and offset-aware datetimes
片方だけタイムゾーンを持っています。7章のとおり、どちらかに揃えてから計算します。DBの値とAPIの値を比べるときに起きがちです。
④ 日付に整数を足した
date(2026, 9, 20) + 1
# TypeError: unsupported operand type(s) for +: 'datetime.date' and 'int'
「1日後」は + 1 ではなく + timedelta(days=1)。日付に足せるのは期間だけです。
⑤ 存在しない日になった
date(2026, 1, 31).replace(month=2)
# ValueError: day is out of range for month
2月31日は存在しません。replace で月だけ変えるやり方は月末で壊れます。6章の add_months のように末日を丸めてから組み立ててください。
⑤の文面は 3.12.10 のものです。3.14.7 では ValueError: day 31 must be in range 1..28 for month 2 in year 2026 と詳しくなりました。検索で見た文面と手元の表示が違っても、原因が別とは限りません。
9. 日付を使っているアプリで見る
日付の扱いが主役のアプリです(コードは各記事に全文あり)。
| アプリ | 日付の使われ方 |
|---|---|
| 年齢計算アプリ | 誕生日と今日の差分。2月29日生まれの扱いが論点 |
| 誕生日カウントダウン | fromisoformat で読み戻して残り日数を数える |
| カウントダウンタイマー | strptime で目標時刻を解析し残り時間を更新 |
| デジタル時計 | strftime で1秒ごとに整形して表示する最小例 |
| カレンダー表示アプリ | calendar で月間カレンダーを組み立てる |
| 習慣トラッカー | 過去7日の日付を timedelta で作る |
| 通知スケジューラ | 指定時刻と比較して通知。繰り返し間隔も日付計算 |
| プロジェクト管理ツール | 開始日と終了日からガントチャートのバー長を計算 |
| バックアップツール | strftime で世代管理用のタイムスタンプを作る |
| 時間追跡アプリ | 開始・終了から作業時間を日次で合計 |
配当カレンダー生成ツールは calendar を継承して月間カレンダーを描き、株価データの定期取得は毎回「直近5営業日」を取り直して重複を潰します。一覧は初心者向け・中級者向けへ。
10. よくある質問(FAQ)
Q. pytz と zoneinfo はどちらを使えばいいですか?
新しく書くコードは zoneinfo です。3.9 から標準ライブラリに入っており(Windows は tzdata が要ります)、datetime と自然に組み合わさります。pytz は localize() を忘れると日本時間が19分ずれます。既存コードの書き換えは急ぎません。
Q. datetime.utcnow() を使っているコードはどう直せばいいですか?
datetime.now(timezone.utc) に置き換えます。戻り値が naive から aware に変わるため、naive な値と引き算すると TypeError です。相手も aware に揃えるか、.replace(tzinfo=None) で落としてください。
Q. 「1か月後」を1行で書く方法はありますか?
標準ライブラリだけではありません。6章の add_months を持つか python-dateutil を導入します。どちらにしても「1月31日の1か月後をいつにするか」は決める必要があります。
Q. 日付を保存するとき、どの形式が無難ですか?
ISO 8601(2026-09-20T07:05:03)です。isoformat() で書いて fromisoformat() で読めば書式指定が要らず、文字列のまま並べ替えても日付順になります。
Q. 曜日を日本語で表示したいのですが、ロケールを変えるべきですか?
"月火水木金土日"[d.weekday()] と自分で当てるほうが安定します。locale.setlocale() は指定できる名前がOSで異なり、環境を移した途端に動かなくなることがあります。
本記事は、生成AIを活用して下書きし、運営者が内容を確認・編集したうえで公開しています。AIの利用方針は免責事項をご覧ください。
11. まとめと次の一歩
要点は4つです。
- 日付だけなら
date、時刻も要るならdatetime、期間はtimedelta - 変換は f = format(出力)、p = parse(入力)。ISO形式なら書式指定が要らない
- 月単位の加算は標準にない。末日の丸め方は自分で決める
- タイムゾーンは
zoneinfo。Windows では tzdata が別途必要。naive と aware は混ぜない
表を眺めるより手を動かすほうが定着します。デジタル時計で書式を差し替えるところから。標準ライブラリの全体像はPythonライブラリ一覧、エラーで止まったらPythonエラー辞典、次に作るものに迷ったらPythonで作れるもの一覧が入口です。
土台から固めたい方は書籍を1冊通すのも手です。このページを毎回開かずに書けるようになりたい方向け。候補はPython入門書のおすすめ2冊にまとめています(書籍紹介ページにはアフィリエイト広告を含みます)。