使用者回報:某個「以昨天為基準」的數字不對。我看:明明是對的。過幾個小時再看:欸,又對了?
這種「時對時錯、無法穩定重現」的 bug 最消耗心力。最後定位出來的規律是:只在午夜到早上八點之間會錯。
台灣時區是 UTC+8。資料庫的 CURRENT_DATE、CURRENT_TIMESTAMP 回傳的是 UTC 時間。所以台灣時間 00:00 到 08:00 這個窗口裡,資料庫認為的「今天」還是台灣的「昨天」:
台灣時間 2026-08-08 06:30
UTC 2026-08-07 22:30 ← CURRENT_DATE 回傳 2026-08-07
任何依賴「今天」概念的邏輯——每日結算基準、「今天是否已執行過」的判斷、以日期為鍵的查詢——在這 8 小時窗口內全部悄悄錯位一天。
它的陰險有三重:
散彈式地在每個出事的地方補 + INTERVAL '8 hours' 是最糟的修法——你永遠不知道還有幾處沒補到,而且下一個寫新功能的人(或 agent)還會繼續產出新的錯誤用法。
正確做法是收斂到單一入口:
# services/local_time.py
def local_today() -> date:
"""在地時區的「今天」。禁止在業務邏輯裡直接用資料庫的 CURRENT_DATE,
原因見地雷清單 #3:UTC 造成 00:00-08:00 窗口差一天。"""
return datetime.now(LOCAL_TZ).date()
def local_midnight_utc() -> datetime:
"""在地今天 00:00 對應的 UTC 時間戳,用於跟 UTC 欄位比較。"""
...
然後做一次全站掃蕩:搜出所有直接使用資料庫日期函式的地方,逐一改走統一入口。這種「機械化的全面掃蕩」正是 agent 最擅長的工作形狀——條件明確、範圍全專案、單點改動風險低,我把掃蕩交給 agent,自己只 review 每一處改動的語意有沒有被改變。
「現在幾點」在有時區的世界裡永遠是個危險問題。 任何跟日期有關的邏輯,寫下第一行之前先回答:這裡的「今天」是誰的今天?資料庫的、伺服器的、還是使用者的?三者在你的部署環境裡一致嗎?半夜呢?