本文 AI 產出,尚未審核

Python 日期與時間(Datetime)

date、time、timedelta 完全攻略


簡介

在日常開發中,日期與時間是不可或缺的資訊。無論是記錄使用者的登入時間、計算兩筆訂單之間的間隔,或是產生報表的時間戳,都需要正確且彈性的時間處理。Python 內建的 datetime 模組提供了 datetimetimedelta 等核心類別,讓開發者可以以直觀且安全的方式操作時間資料。

本篇文章將從 概念說明實作範例常見陷阱 以及 最佳實踐 全面切入,協助初學者快速上手,同時提供給中級開發者在實務專案中可直接套用的技巧。


核心概念

1. datetime.date – 僅表示「日期」

date 只包含年、月、日三個屬性,沒有時、分、秒的資訊。適合用於 生日、節假日、會議日期 等只關心「哪一天」的情境。

from datetime import date

# 建立日期物件(年, 月, 日)
today = date.today()
print("今天日期:", today)               # 2025-11-20

# 指定日期
birthday = date(1990, 5, 15)
print("生日:", birthday)                # 1990-05-15

# 取得各屬性
print("年份:", today.year)              # 2025
print("月份:", today.month)             # 11
print("日期:", today.day)               # 20

2. datetime.time – 僅表示「時間」

time 用來描述 時、分、秒、微秒,不包含日期資訊。常見於 排程系統、時段設定 等只需要時間點的情況。

from datetime import time

# 建立時間物件(時, 分, 秒, 微秒)
t1 = time(14, 30)               # 14:30:00
t2 = time(9, 45, 12, 500000)    # 09:45:12.500000

print("上午時段:", t1)          # 14:30:00
print("精確時間:", t2)          # 09:45:12.500000

# 取得屬性
print("小時:", t2.hour)          # 9
print("分鐘:", t2.minute)        # 45
print("秒數:", t2.second)        # 12
print("微秒:", t2.microsecond)   # 500000

3. datetime.timedelta – 時間差距

timedelta 代表兩個時間點之間的 時間差,支援天、秒、微秒等單位的加減運算。它是 日期/時間算術 的核心。

from datetime import timedelta, date

# 建立 timedelta(天, 秒, 微秒)
delta1 = timedelta(days=10)          # 10 天
delta2 = timedelta(hours=5, minutes=30)  # 5 小時 30 分鐘

# 日期加上時間差
future = date.today() + delta1
print("10 天後的日期:", future)

# 時間差轉換為秒
print("5 小時 30 分鐘等於秒數:", delta2.total_seconds())

4. datetime.datetime – 完整的「日期+時間」

雖然本主題重點是 datetimetimedelta,但在實務上,我們常會先建立 datetime,再透過 .date().time() 取得子集。

from datetime import datetime

now = datetime.now()
print("現在時間:", now)               # 2025-11-20 13:45:23.123456

# 分離出日期與時間
just_date = now.date()
just_time = now.time()
print("只要日期:", just_date)          # 2025-11-20
print("只要時間:", just_time)          # 13:45:23.123456

程式碼範例(實用案例)

範例 1️⃣ 計算兩筆交易的天數差

from datetime import date

order1 = date(2025, 10, 1)
order2 = date(2025, 11, 15)

days_between = (order2 - order1).days
print(f"兩筆訂單相差 {days_between} 天")   # 兩筆訂單相差 45 天

說明:直接用 date 物件相減會得到 timedelta,再取 .days 取得天數。


範例 2️⃣ 產生每週例行任務的時間點(每週一 09:00)

from datetime import datetime, timedelta, time

def next_monday_at_9(now=None):
    now = now or datetime.now()
    # 找到本週的星期一
    monday = now - timedelta(days=now.weekday())
    target = datetime.combine(monday.date(), time(9, 0))
    # 若已過本週 9 點,則往後推一週
    if target <= now:
        target += timedelta(weeks=1)
    return target

print("下次例行任務時間:", next_monday_at_9())

說明:利用 timedelta(days=now.weekday()) 取得本週一,再以 datetime.combine 合併日期與時間,最後判斷是否已過。


範例 3️⃣ 計算「倒數計時」:距離活動還有多少時間

from datetime import datetime, timedelta

event = datetime(2025, 12, 31, 23, 59, 59)
now = datetime.now()
remaining = event - now

print(f"距離跨年還有 {remaining.days} 天 "
      f"{remaining.seconds // 3600} 小時 "
      f"{(remaining.seconds % 3600) // 60} 分鐘")

說明timedelta 內的 seconds 只包含不到一天的秒數,需自行換算成時、分。


範例 4️⃣ 時區感知(timezone-aware)與 date/time 的互換

from datetime import datetime, timezone, timedelta, date, time

# 建立 UTC 時間
utc_now = datetime.now(timezone.utc)

# 轉換為台北時間 (+8 時區)
tz_tpe = timezone(timedelta(hours=8))
tpe_now = utc_now.astimezone(tz_tpe)

print("UTC 現在:", utc_now)
print("台北現在:", tpe_now)

# 只取日期與時間
tpe_date = tpe_now.date()
tpe_time = tpe_now.time()
print("台北日期:", tpe_date)
print("台北時間:", tpe_time)

說明datetime 支援時區資訊,datetime 本身是 無時區 的,若需要時區概念,請先在 datetime 上處理。


範例 5️⃣ 使用 timedelta 做排程批次的「間隔」計算

from datetime import datetime, timedelta

start = datetime(2025, 11, 20, 8, 0)   # 批次開始時間 08:00
interval = timedelta(minutes=15)      # 每 15 分鐘執行一次
batch_times = [start + i * interval for i in range(5)]

for idx, t in enumerate(batch_times, 1):
    print(f"第 {idx} 次執行時間: {t.time()}")

輸出
第 1 次執行時間: 08:00:00
第 2 次執行時間: 08:15:00
第 3 次執行時間: 08:30:00
第 4 次執行時間: 08:45:00
第 5 次執行時間: 09:00:00


常見陷阱與最佳實踐

陷阱 說明 解決方式
直接比較 naive datetime 與 aware datetime 兩者混用會拋出 TypeError 盡量使用 時區感知 (timezone-aware) 的 datetime,或在比較前先 replace(tzinfo=None)
忽略閏年與月份天數 手動加減天數時可能出錯(例如 2 月 28 日加 1 天)。 使用 timedeltadateutil.relativedelta 讓程式自行處理。
timedelta 只支援天、秒、微秒 想直接使用「月」或「年」會失敗。 若需要月、年,使用 dateutil.relativedelta 或自行計算。
時間字串格式不一致 strptime 失敗會導致例外。 統一使用 ISO 8601 (YYYY-MM-DDTHH:MM:SS) 或在解析前先驗證。
忘記考慮夏令時間(DST) 時區轉換在夏令時間切換時會產生錯誤。 使用 pytz 或 Python 3.9+ 的 zoneinfo,讓系統自動處理 DST。

最佳實踐

  1. 盡量使用 datetime 取代單獨的 date/time:在需要同時處理日期與時間時,直接使用 datetime 可避免不必要的轉換。
  2. 統一時區:在大型系統中,建議所有時間均以 UTC 存儲,顯示層再轉換為使用者時區。
  3. 使用 timedelta 進行算術:避免自行計算秒、分、時的進位,交給 timedelta 處理更安全。
  4. 封裝時間工具函式:將常用的「取得本週一」或「倒數計時」等功能抽成函式,提升程式碼可讀性與重用性。

實際應用場景

場景 需求 使用的 datetime 組件
訂單系統 計算訂單出貨天數、逾期時間 datetimedelta
排程任務 每天 02:00 自動備份資料庫 datetime.combine + time + timedelta
社群平台 顯示「X 分鐘前」的發文時間 datetime.now()timedelta.total_seconds()
金融交易 以毫秒為單位的時間戳記 datetime + timestamp()
多時區報表 產生跨國營運的每日營收 datetime + timezone ( zoneinfo )

總結

  • datetimetimedeltaPython 日期時間處理的基石,分別負責「只要日期」「只要時間」以及「時間差」的表示。
  • 透過 datetime 的組合與 timedelta 的算術,我們可以輕鬆完成 日期加減、時間間隔、排程計算 等常見需求。
  • 注意 時區感知閏年/月份天數夏令時間 等陷阱,遵循 統一時區、封裝工具函式 的最佳實踐,可讓程式碼更健壯、易維護。

掌握了這些概念與範例後,你就能在任何 Python 專案中自信地處理日期與時間,從簡單的生日提醒到複雜的跨時區排程,都能迎刃而解。祝你寫程式愉快,時間永遠在你掌控之中!