iT邦幫忙

2026 iThome 鐵人賽

DAY 6
0
Claude AI

Claude Code陪跑:一人開發者的訂閱制SaaS架構與十大地雷實戰記系列 第 6

# Day 6|地雷#3:資料庫時間函式預設 UTC,在地時區永遠差一截

  • 分享至 

  • xImage
  •  

事故現場

使用者回報:某個「以昨天為基準」的數字不對。我看:明明是對的。過幾個小時再看:欸,又對了?

這種「時對時錯、無法穩定重現」的 bug 最消耗心力。最後定位出來的規律是:只在午夜到早上八點之間會錯。

根因解剖

台灣時區是 UTC+8。資料庫的 CURRENT_DATECURRENT_TIMESTAMP 回傳的是 UTC 時間。所以台灣時間 00:00 到 08:00 這個窗口裡,資料庫認為的「今天」還是台灣的「昨天」:

台灣時間  2026-08-08 06:30
UTC       2026-08-07 22:30   ← CURRENT_DATE 回傳 2026-08-07

任何依賴「今天」概念的邏輯——每日結算基準、「今天是否已執行過」的判斷、以日期為鍵的查詢——在這 8 小時窗口內全部悄悄錯位一天。

它的陰險有三重:

  1. 不報錯,只是安靜地算錯
  2. 一天裡有 16 小時是對的——你白天開發、白天測試,永遠看不到它發作
  3. 使用者回報時附的截圖是早上的,你中午去看已經「自己好了」

防線怎麼蓋

散彈式地在每個出事的地方補 + 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 每一處改動的語意有沒有被改變。

通則

「現在幾點」在有時區的世界裡永遠是個危險問題。 任何跟日期有關的邏輯,寫下第一行之前先回答:這裡的「今天」是誰的今天?資料庫的、伺服器的、還是使用者的?三者在你的部署環境裡一致嗎?半夜呢?


上一篇
# Day 5|地雷#2:DDL 型別寫錯,正式站開機直接掛掉的一課
下一篇
# Day 7|地雷#4:同一個欄位,兩張表用不同單位記錄,混用差1000倍還不報錯
系列文
Claude Code陪跑:一人開發者的訂閱制SaaS架構與十大地雷實戰記16
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言