Supabase 在 2026 年 10 月 30 日公告,部分較舊的 Supabase Postgres 版本使用過期 tzdata,對 America/Vancouver、America/Edmonton 與 Africa/Casablanca 執行本地時間換算時可能得到錯誤結果。受影響門檻是低於 15.19.0.003 的 Postgres 15,或低於 17.11.0.003 的 Postgres 17。
這不是所有 timestamp 都被改壞,也不是 Supabase 資料庫全面故障。官方說明指出,已儲存的 timestamp 本身不受影響;問題發生在使用命名時區把時間轉成本地時間時,而且不會自動報錯。2026 年 British Columbia、Alberta 與 Morocco 的規則改變後,舊資料庫仍依過期規則計算,結果可能與瀏覽器、手機或新版時區資料不同。
哪些系統風險最高
單純以 UTC 儲存、顯示時才在已更新的前端轉換,風險相對小。較需要立刻盤點的是預約、課程、訂單截止、通知、帳單週期與跨國排班:如果後端用 (date + time) AT TIME ZONE zone 把使用者輸入的牆上時間轉成 instant,錯誤結果可能已經寫入資料。後續 worker、郵件與行事曆都會忠實執行那個錯誤 instant。
另外,expression index 若把 AT TIME ZONE 或指定時區的換算結果存進索引,即使升級後 runtime 規則正確,索引內仍可能保留舊計算值。這也是為什麼只看 timestamptz 欄位是否完整不夠,還要盤點 view、generated column、materialized view、index 與排程資料的產生邏輯。
Supabase 官方 GitHub issue 在 9 月已提供重現與影響討論,並有代管專案使用者回報;10 月 30 日的 changelog 與 Knowledge Base 則給出正式受影響版本和升級方式。這些第一手資料形成完整證據鏈,比單純看到「時間差一小時」就猜測前端 bug 更可靠。
先確認版本與實際使用範圍
在 Supabase Dashboard 的 Project Settings、General、Service Version 查看版本。只有版本低於官方門檻,而且系統使用上述時區時,才符合這次公告的直接影響範圍。不要因為看見 AT TIME ZONE 就假設所有地區都錯,也不要把台灣 Asia/Taipei 的顯示問題直接歸因於這次事件。
接著搜尋 schema、migration、function、view、cron job 與 application code 中的三個時區名稱、AT TIME ZONE、timezone() 及本地日期組合邏輯。資料表也要找出同時保存 local date、local time、zone 與 UTC instant 的欄位,這類資料較有機會重算;若只保存轉換後 instant,則必須從訂單、預約確認信或外部紀錄取得原始意圖,不能憑一小時差異批次修改。
官方 Knowledge Base 建議查找含時區換算的 index 定義。可以從 pg_indexes.indexdef 搜尋 at time zone 與三個 zone,產生候選清單;清單需要人工確認,因為字串搜尋可能漏掉封裝在 immutable function 內的換算,也可能找到與本次規則無關的索引。
升級前要把停機和回復一起規劃
Supabase 升級指引說明,project upgrade 會讓資料庫與相關服務暫時離線,後台會先檢查 eligibility,再建立新 instance、搬移資料並執行 upgrade。正式環境應選低流量窗口,先驗證備份可用、估算停機、通知依賴系統,並暫停會在切換期間大量重試的 queue 或排程。
升級前在 staging 複製 schema 與具代表性的匿名資料,執行官方門檻以上版本。準備固定 UTC instant 與預期 local time 的測試,不要只用 now(),否則不同執行時間難以比較。測試至少涵蓋規則改變前、改變當天、改變後,以及預約建立、修改、提醒與取消流程。
升級成功後,重新執行版本確認和固定時間測試。對候選 expression index 使用 REINDEX INDEX CONCURRENTLY 逐一重建;官方文件指出 concurrent 方式不阻擋一般讀寫,但仍會消耗 I/O 與 CPU,因此應分批執行並監看 query latency。materialized view 或應用層快取則依各自機制 refresh,不能把 reindex 當成全部資料衍生物都已更新。
已經產生的錯誤排程怎麼修
先把可能受影響資料分成「只在讀取時顯示錯誤」與「錯誤 instant 已寫入」兩類。前者在 runtime 和索引修正後通常會恢復;後者需要依原始 local date、time、zone 重新計算。批次修正前先輸出 record id、舊值、新值、差異、來源與修正理由,交由業務 owner 確認,再以可回滾 migration 更新。
已經寄出的確認信、第三方行事曆、付款或物流截止時間不會因資料庫修正而自動同步。若 appointment time 改變,應以既有通知政策重新發送,並標示是時間修正;若無法確認使用者原始意圖,應進人工處理,不要直接把所有資料加減一小時。
長期資料模型應同時保存使用者輸入的 local date、local time、IANA zone,以及由當時規則算出的 instant,並記錄最後計算時間或 tzdata version。這不是要讓每張表重複所有欄位,而是讓具有法律、營運或提醒意義的未來事件可以在時區規則改變時重新計算與稽核。
選擇上,直接使用受影響時區且版本過舊的代管專案應排程升級;沒有使用這三個時區的專案仍可依正常維護週期更新,不必以事故方式處理。自架 Supabase 則不能假設代管升級會替自己修正,應檢查 image 與 PostgreSQL 實際編譯使用的 zoneinfo。這次事件最重要的提醒,是時間換算屬於版本化業務規則:沒有錯誤訊息,不代表排程結果正確。