相同鐘面時間可能是兩個時刻
採用夏令時間的地區,在秋季調回時鐘時,某段當地時間會出現兩次。如果報表只用日期加小時作唯一鍵,可能把第二次當重複刪掉,也可能整段重跑後重算第一次。先保留可唯一定位的時間,再決定畫面如何呈現。
本篇使用America/Los_Angeles在二零二零年十一月一日的歷史例子,避免把規則當成所有地區永遠相同。當天凌晨一時三十分有兩個版本,一個偏移負七小時,一個偏移負八小時,兩者在真實時間上相差一小時。
第一個一時三十分對應UTC八時三十分,第二個對應UTC九時三十分。假設各有一個不同產品事件,兩筆都應保留;當地時分相同不代表事件ID相同,也不是可以去重的充分條件。
適用於跨夏令時間的班報、日報與歷史查詢。若原始資料只剩當地時分且沒有偏移、序號或其他可判定資訊,歧義可能無法完全還原,應標示待核對,不默認挑一個版本當成事實。
用UTC區間作桶身分
每個小時桶保留UTC起訖,當地時間作顯示。回撥日的兩個一點桶可以標成一點小時的第一次與第二次,並附UTC區間或對應偏移。桶的唯一身分不能只用文字「01」,還要有日期及實際時間範圍。
例如一點三十分負七的事件進UTC八時至九時桶,一點三十分負八的事件進UTC九時至十時桶。各桶若各有十件,合計二十件;畫面可以分列兩桶,也可合併為當地一點共二十件,但合併時要說明包含兩段實際小時。
每個桶採起點包含、終點不包含。UTC九時整不能同時計入前後兩桶。不要先轉成沒有偏移的當地字串再去重,否則原本不同的UTC時刻會在轉換中失去辨識。
若報表固定畫二十四欄,回撥日可能放不下二十五個實際小時,前進日則可能只有二十三個。應讓版面適應實際區間,或清楚顯示合併與不存在的時段,不能為湊滿欄位而刪除或複製資料。
完成這一步,原始有效事件數應等於所有不重疊UTC桶的事件合計。若同一份資料只因切換顯示時區就少一批,優先查桶身分與時間字串碰撞。
班長與日長不要固定假設
在本例回撥日,當地零時到隔日零時的實際經過時間是二十五小時。若連續以每實際小時一百件生產,合計應為二千五百件,以實際二十五小時計算平均仍是一百件每小時。硬除二十四會得到約一百零四點一七,形成假性效率上升。
反方向的春季跳時,某些當地時間根本不存在。本例地區二零二零年三月八日的當地日長為二十三小時。報表空出不存在的時段與設備真的沒資料是不同狀態,不能都標成停機一小時。
計算實際持續時間時,先把兩個端點換成UTC再相減。不要只用鐘面小時相減,也不要假設每個程式庫對同一時區物件的日期運算都等同實際秒數。先核對工具語意,再用跨轉換案例測試。
班表若在歧義時段換班,還需要明確規則:第一個一點半或第二個一點半。人資、產量與控制排程的規則可能不同,本文不替組織決定;沒有定義就無法唯一產生UTC班界。
對未來班表保留地區名稱與規則版本,因為時區政策可能改變。對已發生事件保留原始偏移與UTC時刻,方便日後依不同規則重算時仍能追溯當時紀錄。
測試歧義輸入與重跑行為
匯出檔也保留偏移或UTC,不只在網頁顯示完整時間而下載時又省略。若下游試算表把兩個一點半合併,仍會重新引入問題;驗收應包含匯出再匯入的結果。
Python zoneinfo文件使用fold區分重複當地時間:本例fold為零採轉換前偏移,為一採轉換後偏移。它是該工具的表示方式,不能假設資料庫或PLC也有同名欄位;介面契約應直接保留足夠的時間資訊。
時區物件能被建立,不代表任意輸入的當地時間都合法。對春季不存在時間或秋季歧義時間,輸入流程需要驗證與處置規則。不能只把時區名稱貼上字串,就默認程式替你選到了正確實際時刻。
測試集放兩筆同名但不同偏移的一點三十分,再放一筆完全相同ID的重送。預期兩個真事件都計入,而重送不新增。這可同時檢查時區歧義與事件去重是否互相混淆。
報表重跑使用同一UTC範圍與規則版本,應得到相同結果。若排程器在回撥小時觸發兩次,處理工作需要按報表區間與版本避免重複發布;排程是否重複觸發則查實際平台,不假設全部工具一致。
完成後保存實際桶數、總件數、日長與邊界測試結果。僅看報表日期正確不足以驗收,因為丟失的那個小時可能藏在合計裡。
練習與常見問題
練習:本例第一段一點有八十件,第二段一點有九十件,其餘二十三個實際小時各一百件。全日共二千四百七十件,實際二十五小時,平均九十八點八件每小時。若只保留其中一個一點桶,總數與平均都會偏差。
失敗時先查原始時間有沒有偏移、桶鍵是否唯一、期間長度如何計算,以及重跑是否去重。若原始歧義已不可解,列出受影響範圍,不能以假造偏移補成看似完整的紀錄。 同時保留受影響事件清單,讓補證據後可以只重算相關區間。
問:回撥時重複的時間要刪掉一份嗎?答:兩段是真實不同時刻,只有同一事件重送才去重。
問:每天一定二十四小時嗎?答:地方民用日跨轉換時可能不同,應算UTC端點差。
問:加一個時區名稱能解決所有歧義嗎?答:重複時段還需偏移或其他明確區分。
問:臺灣設備也要考慮嗎?答:若資料跨地區或分析歷史時間,就需按來源規則處理。
參考:Python zoneinfo:IANA時區、偏移轉換及fold歧義時間示例。
參考:PostgreSQL Date/Time Types:時區與帶時區時間戳的處理。