Pythonで日付や時刻を扱うときに欠かせないのが、datetimeモジュールと書式指定です。
システムログのタイムスタンプ、ファイル名への日時付与、ユーザー画面への表示など、さまざまな場面で日時の「見せ方」を意識する必要があります。
本記事では、Pythonのdatetime書式指定の基本から、一覧・早見表、実用的なサンプルコード、よくあるミスまで、丁寧に解説します。
Pythonのdatetime書式指定とは
datetime書式指定の基本

Pythonでは、「datetimeオブジェクト」そのものと、「文字列として表現された日付・時刻」を相互に変換しながら扱います。
このときに使うのが書式指定子(format codes)です。
書式指定は、"%Y-%m-%d %H:%M:%S"のように、パーセント記号%から始まる特別な記号を組み合わせて作ります。
たとえば:
%Y→ 西暦4桁(2025)%m→ 月2桁(01〜12)%d→ 日2桁(01〜31)%H→ 24時間制の時(00〜23)
のように、1つ1つの指定子が特定の情報(年・月・日・時など)を表します。
datetime.strftimeとdatetime.strptimeの違い

Pythonのdatetimeモジュールでは、主に次の2つのメソッドで書式指定を使います。
- datetime.strftime(format)
datetimeオブジェクト → 書式指定に従った文字列に変換します。 - datetime.strptime(date_string, format)
文字列 → 書式指定に従って解析し、datetimeオブジェクトに変換します。
具体的なコードで確認してみます。
from datetime import datetime
# 現在日時の取得
now = datetime.now()
# datetime → 文字列 (strftime)
formatted = now.strftime("%Y-%m-%d %H:%M:%S")
print("formatted:", formatted)
# 文字列 → datetime (strptime)
parsed = datetime.strptime("2025-12-20 14:30:00", "%Y-%m-%d %H:%M:%S")
print("parsed:", parsed, " type:", type(parsed))
formatted: 2025-12-20 14:35:42 # 実行時の現在日時によって変わります
parsed: 2025-12-20 14:30:00 type: <class 'datetime.datetime'>
同じ書式指定子を使いつつ、「どちらに変換するか」でメソッドが異なる点が重要です。
日付・時刻フォーマットを使う場面と注意点

日時フォーマットを使う場面は、実務では非常に多いです。
たとえば、ログへの出力、ユーザー画面での表示、CSVなど外部ファイルでのやり取り、APIとの通信、バックアップファイルの命名などが挙げられます。
これらの場面では、「人にとって読みやすいフォーマット」と「機械にとって処理しやすいフォーマット」を使い分けることが重要です。
システム内部やAPIではISO8601形式などの標準的な形式を使い、画面表示では日本語混じりの“YYYY年MM月DD日”といった形式にすることがよくあります。
また、注意点としてタイムゾーン情報の有無があります。
サーバーサイドではUTC、フロント側ではローカルタイム、というように時刻の解釈が変わることがあるため、フォーマットと合わせてタイムゾーン設計も意識する必要があります。
datetime書式指定子一覧
ここからは、代表的な書式指定子をカテゴリごとに整理して解説します。
Python公式ドキュメントを基にしていますが、環境やロケールにより挙動が異なるものもあるため、特にロケール依存の指定子は実行環境での確認が重要です。
年を表す書式指定子

年を表す主な書式指定子を表にまとめます。
| 指定子 | 意味 | 出力例 | 備考 |
|---|---|---|---|
| %Y | 西暦(4桁) | 2025 | 通常はこちらを使うことが多いです |
| %y | 西暦(下2桁) | 25 | 1900〜2099年に対応する環境が多いです |
たとえば、次のように使います。
from datetime import datetime
dt = datetime(2025, 12, 20, 14, 30, 0)
print(dt.strftime("%Y-%m-%d")) # 4桁の年
print(dt.strftime("%y-%m-%d")) # 2桁の年
2025-12-20
25-12-20
システム間連携やログなど、誤解を避けたい場面では基本的に%cst-code>%Yを使うことをおすすめします。
月を表す書式指定子

月を表す指定子には、数値・英語表記など複数のバリエーションがあります。
| 指定子 | 意味 | 出力例 | 備考 |
|---|---|---|---|
| %m | 月(01〜12、ゼロ埋め2桁) | 01, 12 | 最もよく使われる形式です |
| %-m | 月(1〜12、ゼロ埋めなし) | 1, 12 | Unix系で使用可。Windowsでは非対応 |
| %b | 月名(ロケールの短縮形) | Jan, Dec | 日本語環境では「1月」などになることも |
| %B | 月名(ロケールの完全な名称) | January | ロケール依存 |
ロケール依存というのは、OSや環境の言語設定により表記が変わるという意味です。
英語環境で%Bを使うと”December”になりますが、日本語環境では”12月”のように出力される場合があります。
日を表す書式指定子

日(1〜31)にも、ゼロ埋めあり・なしの違いがあります。
| 指定子 | 意味 | 出力例 | 備考 |
|---|---|---|---|
| %d | 日(01〜31、ゼロ埋め2桁) | 01, 20 | 一般的に最も使われます |
| %-d | 日(1〜31、ゼロ埋めなし) | 1, 20 | Unix系で使用可、Windowsでは非対応 |
| %e | 日(1〜31、先頭が空白で埋められる) | ” 1″, “20” | 一部環境のみ。ログなどで古くから使われる形式 |
たとえば、画面表示で“2025年12月20日”のようにしたい場合は次のように書きます。
from datetime import datetime
dt = datetime(2025, 12, 20)
# ゼロ埋めした日付表示
print(dt.strftime("%Y年%m月%d日"))
# ゼロ埋めしない(月/日とも)
print(dt.strftime("%Y年%-m月%-d日")) # Unix系想定
2025年12月20日
2025年12月20日
Windowsでは%-mや%-dが使えないため、その場合は後から文字列処理でゼロを取り除くなど別の工夫が必要です。
時・分・秒を表す書式指定子

時刻部分は、24時間制・12時間制(AM/PM)の両方に対応しています。
| 指定子 | 意味 | 出力例 | 備考 |
|---|---|---|---|
| %H | 時(00〜23、24時間制) | 00, 14, 23 | ログやシステムにはこちらが一般的 |
| %I | 時(01〜12、12時間制) | 01, 02, 12 | AM/PMとあわせて表示する際に利用 |
| %M | 分(00〜59) | 00, 05, 59 | %m(月)と混同しないことが重要 |
| %S | 秒(00〜59) | 00, 09, 59 | 通常の秒数 |
| %f | マイクロ秒(000000〜999999) | 000123 | 後述のマイクロ秒セクションで詳細 |
| %p | ロケール依存のAM/PM | AM, PM | 日本語環境では”午前” “午後”などになることも |
簡単な例を示します。
from datetime import datetime
dt = datetime(2025, 12, 20, 14, 5, 9)
print(dt.strftime("%H:%M:%S")) # 24時間制
print(dt.strftime("%I:%M:%S %p")) # 12時間制 + AM/PM
14:05:09
02:05:09 PM
24時間制か12時間制かは、%Hと%Iで切り替えるという点を覚えておくと間違いが減ります。
マイクロ秒・タイムゾーンの書式指定子

ミリ秒やマイクロ秒まで扱いたい場合、またタイムゾーン付きの日時を扱う場合に使う指定子です。
| 指定子 | 意味 | 出力例 | 備考 |
|---|---|---|---|
| %f | マイクロ秒(6桁) | 123456 | datetimeのmicrosecond属性(0〜999999)に対応 |
| %z | UTCオフセット(±HHMM形式) | +0900, -0500 | タイムゾーン情報付きdatetimeで有効 |
| %Z | タイムゾーン名 | JST, UTC | 環境やライブラリに大きく依存 |
注意点として、標準のdatetimeはデフォルトでは「タイムゾーンなし(naive)」であることが多く、%zや%Zを使っても空文字になる場合があります。
タイムゾーン情報を正しく扱いたい場合は、datetime.timezoneやzoneinfo、あるいはpytzなどのライブラリと組み合わせる必要があります。
曜日・週番号の書式指定子

曜日や週番号を扱う場合、次のような指定子を使います。
| 指定子 | 意味 | 出力例 | 備考 |
|---|---|---|---|
| %a | 曜日名(ロケールの短縮形) | Mon, Tue | 日本語では「月」などになることも |
| %A | 曜日名(ロケールの完全な名称) | Monday | ロケール依存 |
| %w | 曜日(0〜6、0=日曜日) | 0, 1, …, 6 | 数値で曜日を扱うときに便利 |
| %j | 年内通算日(001〜366) | 001, 365 | 1月1日が001になります |
| %U | 年内週番号(日曜始まり、00〜53) | 00, 52 | アメリカ式に近い週番号 |
| %W | 年内週番号(月曜始まり、00〜53) | 00, 52 | ISO週番号とは定義が異なります |
週番号は国や業界によって定義が異なるため、「どの定義の週番号なのか」を関係者で共有しておくことが大切です。
ロケール依存の書式指定子

ロケール(locale)とは、言語や地域に応じた表示形式(曜日名、月名、日付順など)を決める設定です。
ロケールに依存する書式指定子には次のようなものがあります。
| 指定子 | 意味 | 出力例(英語ロケール) |
|---|---|---|
| %a | 曜日名(短縮) | Mon |
| %A | 曜日名(フル) | Monday |
| %b | 月名(短縮) | Jan |
| %B | 月名(フル) | January |
| %c | 日付と時刻(ロケール適当な表示形式) | Sat Dec 20 14:30:00 2025 |
| %x | 日付(ロケール適当な表示形式) | 12/20/25 など |
| %X | 時刻(ロケール適当な表示形式) | 14:30:00 など |
ロケール依存の指定子は、システム間のデータ受け渡しには基本的に使わない方が安全です。
テキストとして人に見せる用途(画面表示など)でのみ使い、機械処理には%Y-%m-%dなどロケール非依存の形式を採用するのがよい方針です。
その他の書式指定子

最後に、よく使うその他の指定子をまとめます。
| 指定子 | 意味 | 出力例 |
|---|---|---|
| %c | 日付と時刻(ロケール適当な表示形式) | Sat Dec 20 14:30:00 2025 |
| %x | 日付(ロケール適当な表示形式) | 12/20/25 など |
| %X | 時刻(ロケール適当な表示形式) | 14:30:00 など |
| %% | パーセント記号そのもの | % |
%%は少し特殊で、書式文字列の中に「%」を文字として出したいときに使うものです。
from datetime import datetime
dt = datetime(2025, 12, 20, 14, 30, 0)
print(dt.strftime("進捗は50%%、日時=%Y-%m-%d %H:%M"))
進捗は50%、日時=2025-12-20 14:30
datetime書式指定の使い方
ここからは、書式指定子を実際にどのように使うのか、具体的なコード例で解説します。
datetimeを文字列に変換する

datetimeオブジェクトから文字列に変換するには、strftimeメソッドを使います。
from datetime import datetime
dt = datetime(2025, 12, 20, 14, 30, 0)
# ベーシックな形式
s1 = dt.strftime("%Y-%m-%d %H:%M:%S")
# 日付のみ
s2 = dt.strftime("%Y/%m/%d")
# 日本語を含む形式
s3 = dt.strftime("%Y年%m月%d日(%a) %H時%M分")
print(s1)
print(s2)
print(s3)
2025-12-20 14:30:00
2025/12/20
2025年12月20日(Sat) 14時30分 # ロケールにより(Sat)部分は変化します
「表示用途」か「データ用途」かで、フォーマットを分けて定義しておくと管理がしやすくなります。
たとえば、定数として次のように定義しておく方法があります。
# 共通で使うフォーマットを定義しておく例
FORMAT_LOG = "%Y-%m-%d %H:%M:%S"
FORMAT_DATE_JP = "%Y年%m月%d日(%a)"
FORMAT_ISO = "%Y-%m-%dT%H:%M:%S%z"
文字列をdatetimeに変換する

文字列からdatetimeオブジェクトへ変換するにはstrptimeを使います。
ポイントは「文字列の見た目」と「format文字列のパターン」を完全に一致させることです。
from datetime import datetime
# "YYYY-MM-DD" 形式
s1 = "2025-12-20"
dt1 = datetime.strptime(s1, "%Y-%m-%d")
# "YYYY/MM/DD HH:MM" 形式
s2 = "2025/12/20 14:30"
dt2 = datetime.strptime(s2, "%Y/%m/%d %H:%M")
print(dt1, type(dt1))
print(dt2, type(dt2))
2025-12-20 00:00:00 <class 'datetime.datetime'>
2025-12-20 14:30:00 <class 'datetime.datetime'>
1文字でも形式が合わないとValueErrorになるので、入力のバリデーションやエラーハンドリングが重要です。
よく使う日付フォーマット例

実務でよく使われる日付フォーマットをいくつか紹介します。
| 用途例 | フォーマット文字列 | 例 |
|---|---|---|
| ログ・内部処理 | %Y-%m-%d | 2025-12-20 |
| 日本語画面表示 | %Y年%m月%d日(%a) | 2025年12月20日(Sat) |
| コンパクトな記録 | %Y%m%d | 20251220 |
| ファイル名用 | %Y%m%d_%H%M%S | 20251220_143000 |
| 国際標準(ISO8601 date) | %Y-%m-%d | 2025-12-20 |
from datetime import datetime
dt = datetime(2025, 12, 20, 14, 30, 0)
formats = {
"log": "%Y-%m-%d",
"display_jp": "%Y年%m月%d日(%a)",
"compact": "%Y%m%d",
"filename": "%Y%m%d_%H%M%S",
}
for name, fmt in formats.items():
print(name, ":", dt.strftime(fmt))
log : 2025-12-20
display_jp : 2025年12月20日(Sat)
compact : 20251220
filename : 20251220_143000
よく使う時刻フォーマット例

時刻部分だけを扱うフォーマットもよく使われます。
| 用途例 | フォーマット文字列 | 例 |
|---|---|---|
| シンプルな24時間制 | %H:%M | 14:30 |
| 秒まで | %H:%M:%S | 14:30:00 |
| ミリ秒相当表示 | %H:%M:%S.%f | 14:30:00.123456 |
| 12時間制 + AM/PM | %I:%M %p | 02:30 PM |
from datetime import datetime
dt = datetime(2025, 12, 20, 14, 30, 0, 123456)
print(dt.strftime("%H:%M"))
print(dt.strftime("%H:%M:%S"))
print(dt.strftime("%H:%M:%S.%f"))
print(dt.strftime("%I:%M %p"))
14:30
14:30:00
14:30:00.123456
02:30 PM
ログなどでは時刻の精度が重要になることもあるため、ミリ秒あるいはマイクロ秒まで記録するかを要件に応じて決めておくとよいです。
ISO形式の日付時刻

システム間のやり取りやAPIでは、ISO8601形式が事実上の標準になっています。
代表的な形式は次の通りです。
| 種類 | 例 | 説明 |
|---|---|---|
| 日付のみ | 2025-12-20 | %Y-%m-%d |
| 時刻のみ | 14:30:00 | %H:%M:%S |
| 日付+時刻(ローカル) | 2025-12-20T14:30:00 | %Y-%m-%dT%H:%M:%S |
| 日付+時刻+TZ | 2025-12-20T14:30:00+09:00 | %Y-%m-%dT%H:%M:%S%z (要注意) |
Pythonのdatetimeには、ISO形式との変換用に便利なメソッドも用意されています。
from datetime import datetime, timezone, timedelta
# タイムゾーン付きdatetimeの作成
dt = datetime(2025, 12, 20, 14, 30, 0, tzinfo=timezone(timedelta(hours=9)))
# ISO形式への変換
iso_str = dt.isoformat()
print("isoformat:", iso_str)
# ISO形式からの変換 (2024.7時点でfromisoformatが利用可能)
parsed = datetime.fromisoformat("2025-12-20T14:30:00+09:00")
print("parsed:", parsed, " tzinfo:", parsed.tzinfo)
isoformat: 2025-12-20T14:30:00+09:00
parsed: 2025-12-20 14:30:00+09:00 tzinfo: UTC+09:00
自前でstrftimeとstrptimeを組み合わせるより、ISO形式はisoformatとfromisoformatを優先的に使うと、タイムゾーンや小数秒の扱いでミスが減ります。
よくあるdatetime書式指定のミスと対策
datetimeの書式指定では、似た指定子の取り違えや、環境依存の挙動に起因するトラブルが起こりがちです。
ここでは代表的なものと対策を解説します。
%mと%Mの取り違え

最もよくあるミスの1つが、%m(月)と%M(分)の取り違えです。
たとえば、次のような間違いが起こりやすいです。
from datetime import datetime
dt = datetime(2025, 12, 20, 14, 5, 0)
# 間違い例: 分に%Mではなく%mを使ってしまう
wrong = dt.strftime("%Y-%m-%d %H:%m")
print("wrong:", wrong)
# 正しい例
correct = dt.strftime("%Y-%m-%d %H:%M")
print("correct:", correct)
wrong: 2025-12-20 14:12 # 「12」は月(December)が出てしまっている
correct: 2025-12-20 14:05
対策としては、「month = %m、小文字」「Minute = %M、大文字」と、頭文字で覚えておくと混同しにくくなります。
%Hと%Iの違い

%cst-code>%Hと%Iも混同しやすい指定子です。
- %H: 24時間制の時(00〜23)
- %I: 12時間制の時(01〜12、AM/PMと組み合わせて使う)
from datetime import datetime
dt = datetime(2025, 12, 20, 14, 30, 0)
print(dt.strftime("%H:%M")) # 24時間制
print(dt.strftime("%I:%M %p")) # 12時間制 + AM/PM
14:30
02:30 PM
ログや内部データでは%Hを基本とし、ユーザーに12時間表記を見せたいときのみ%I + %pを使う、という運用ルールをチーム内で共有しておくと安全です。
ゼロ埋めあり・なしの違い

日付や時刻の表示では、「01月」などゼロ埋めするか、「1月」とするかが問題になることがあります。
Pythonのstrftimeでは、一般的に次のような違いがあります。
- ゼロ埋めあり:
%m,%d,%H,%M,%Sなど - ゼロ埋めなし(Unix系のみ):
%-m,%-d,%-Hなど
Windows環境では%-mなどが使えないため、次のような工夫が必要になることがあります。
from datetime import datetime
dt = datetime(2025, 1, 2, 3, 4, 5)
# 共通で使えるゼロ埋めあり
s = dt.strftime("%Y-%m-%d %H:%M:%S")
print("ゼロ埋めあり:", s)
# ゼロ埋めなしにしたいときの一例(後処理で0を消す)
s_no_zero = dt.strftime("%Y-%m-%d %H:%M:%S")
s_no_zero = s_no_zero.replace("-0", "-").replace(" 0", " ")
print("ゼロ埋めなし(一例):", s_no_zero)
ゼロ埋めあり: 2025-01-02 03:04:05
ゼロ埋めなし(一例): 2025-1-2 3:4:5
環境差異を減らすため、業務システムでは「ゼロ埋めあり」に統一する方針にしてしまうのも有効です。
タイムゾーン付き日時のパースのポイント

タイムゾーン付きの日時文字列をstrptimeでパースする場合、%zの形式とPythonのバージョン・環境に注意が必要です。
一般的な文字列例:
"2025-12-20T14:30:00+0900"→%Y-%m-%dT%H:%M:%S%z"2025-12-20 14:30:00+09:00"→ Python 3.7以前ではstrptimeが対応していない場合がある
from datetime import datetime
s = "2025-12-20T14:30:00+0900"
dt = datetime.strptime(s, "%Y-%m-%dT%H:%M:%S%z")
print(dt)
print("tzinfo:", dt.tzinfo)
print("UTC時刻:", dt.astimezone(datetime.utcfromtimestamp(0).tzinfo))
2025-12-20 14:30:00+09:00
tzinfo: UTC+09:00
UTC時刻: 1970-01-01 00:00:00+00:00 # 実際には正しい変換のため別の書き方が必要です
上のUTC変換例は簡略化していますが、実務ではdatetime.timezone.utcやzoneinfoモジュールを使った正確な変換が重要です。
APIがどの形式のタイムゾーン表記(+0900 / +09:00 / Zなど)を返すかを事前に確認し、それに合わせたstrptimeやfromisoformatを選ぶことがポイントです。
Pythonバージョン差異とドキュメント確認のコツ

datetimeと書式指定周りは、Pythonのバージョンアップに伴い少しずつ拡張されています。
たとえば:
- Python 3.7以降:
datetime.fromisoformat()が強化され、ISO形式文字列のパースがしやすくなりました。 - Python 3.9以降:
zoneinfoモジュールが標準ライブラリ入りし、タイムゾーンの扱いが改善されました。
また、ロケール依存の指定子や%-mなどの非標準拡張はOSやCライブラリに依存するため、Pythonのバージョンだけでなく実行環境にも注意が必要です。
対策としては、次のような習慣を持つと安全です。
- 公式ドキュメントの「datetime — Basic date and time types」の該当バージョンを確認する
- チーム・プロジェクトでサポートするPythonバージョンを明確に決める
- 本番環境と開発環境でPythonやOSのバージョンを合わせる
最新の仕様や挙動は、以下の公式ドキュメントで確認できます。
まとめ
Pythonのdatetime書式指定は、「datetimeオブジェクトと文字列をどう行き来させるか」を決める重要な仕組みです。
strftimeとstrptimeを軸に、年・月・日・時・分・秒・タイムゾーンなどを表す書式指定子を正しく理解しておくことで、ログ出力や画面表示、API連携まで、日時処理を安全かつ一貫性を持って実装できます。
特に%mと%M、%Hと%Iの混同、ロケール依存やタイムゾーンの扱いには注意しながら、この記事の一覧・サンプルを早見表として活用していただければ幸いです。
