使用 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 只要格式不符就會失敗。若輸入格式多樣,需先做「前處理」或逐步嘗試多種格式(或盡量限制輸入格式)。
7. 常用三大模式
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)等。
相關文章:
系列前作: