先定義業務語意,再談欄位格式
跨系統整合最常見的錯誤,是看到「日期」或「金額」欄位便直接建立一對一映射。實際上,2026-10-27 09:00 可能是台北當地時間、UTC、使用者瀏覽器時間,或只是沒有時區意義的排程時間;1000 也可能代表新台幣、美元、含稅售價、未稅淨額,甚至是已依當日匯率換算後的報表金額。欄位名稱相同,不代表語意相同。
工程團隊應先為每個欄位建立資料契約,說明來源語意、儲存格式、時區或幣別、精度、允許空值,以及轉換失敗時的處理方式。這份契約應由系統負責人與業務使用者共同確認,因為「訂單日期」究竟是建立時間、付款時間或會計入帳日,不能只靠程式碼推測。
- 時間欄位:區分事件時間、日期型業務欄位與沒有時區的本地排程。
- 金額欄位:同時保存數值、ISO 幣別代碼、稅務語意與精度。
- 轉換規則:記錄採用的時區、匯率來源、匯率日期與四捨五入方式。
- 原始資料:保留來源值與來源系統,讓異常可以重播與稽核。
日期與時區要區分「瞬間」和「日曆日期」
代表真實事件瞬間的資料,例如 API 呼叫、付款成功或設備告警,建議在整合層轉成 UTC,並使用帶時區資訊的 ISO 8601 格式傳輸。資料庫可儲存 UTC 時間戳,顯示時再依使用者或營運據點的時區轉換。不要只存台灣時間,也不要假設所有系統都使用 UTC+8;海外分公司、雲端服務與第三方 SaaS 很容易打破這項假設。
生日、發票日期、會計期間與合約到期日則通常是日曆日期,不應強制轉成 UTC 時間戳。若把 2026-10-27 轉成午夜再套用時區,其他地區可能看到前一天。另一方面,「每天上午九點執行」屬於本地排程,應保存時區識別碼,例如 Asia/Taipei,而不是只保存固定偏移量。固定偏移量無法完整表達採用日光節約時間地區的歷史與未來規則。
- 傳輸格式:事件時間應包含 Z 或明確偏移量,不接受沒有時區的模糊時間。
- 解析規則:指定可接受格式,不要依賴執行環境自動猜測月日順序。
- 夏令時間:對不存在或重複的本地時間,預先定義拒絕、順延或選擇哪個偏移量。
- 系統時鐘:伺服器應同步時間,但整合邏輯仍不可把接收時間當成來源事件時間。
幣別轉換必須可重現,而不只是乘上一個匯率
金額建議使用十進位型別或最小貨幣單位的整數,避免二進位浮點數造成累積誤差。資料模型至少要包含原幣金額與幣別代碼;若產生換算金額,還應保存目標幣別、匯率、匯率基準時間、來源與規則版本。如此一來,即使匯率服務日後更新,歷史訂單、發票與報表仍能重現當時結果。
匯率選擇是業務政策,不是純技術決定。交易系統可能採付款時間匯率,ERP 可能採入帳日或月底匯率,管理報表又可能採固定預算匯率。整合層不應自行挑選「最新匯率」覆蓋所有情境。還要明確決定四捨五入發生在明細、稅額、訂單合計或入帳階段;不同順序都可能合理,但混用會造成總額無法對帳。
- 運算精度:中間計算保留足夠精度,只在規定的業務邊界進行捨入。
- 零位小數幣別:不要假設所有貨幣都有兩位小數,規則應由幣別中繼資料驅動。
- 退款與折讓:確認使用原交易匯率、退款日匯率,或由財務系統計算匯兌差額。
- 缺少匯率:選擇阻擋交易、排入待處理佇列或使用經核准的替代規則,並留下告警。
讓轉換可以驗證、追蹤與安全重跑
正規化邏輯應集中在明確的整合邊界,而不是散落在前端、API、ETL 與報表中各自實作。建立可版本化的轉換函式,並針對月底、跨年、夏令時間切換、閏日、負數金額、超大金額、空值與未知幣別設計測試案例。除了單元測試,也要使用來源與目標系統都同意的範例資料做契約測試。
正式環境需要保留原始值、正規化值、規則版本與處理時間,並讓同一筆訊息可以冪等重跑。監控不只看 API 是否成功,還應檢查無法解析的日期、未知時區、缺失幣別、匯率逾期與對帳差額。若某些舊系統只能提供模糊資料,與其靜默猜測,不如標記資料品質狀態並送入例外流程。可靠的整合不是把所有輸入都勉強轉成功,而是讓每一次轉換都有清楚、可驗證且可追溯的依據。