訂單在 11/05 23:54 成立,NMQ Job 到午夜後才寫入回饋紀錄,UpdateTime 落在 11/06 00:02。前後只隔幾分鐘,稽核卻說 BookingTime 差了 24 小時。Job 沒有跑上一整天;問題是正流程拿訂單日期排程,舊稽核卻可能拿 Job 寫入紀錄的日期重算。同一筆回饋,兩邊翻了不同頁的日曆。

NMQ Job 晚幾分鐘寫入,稽核為何多算 24 小時?

案卷的 00:02 是回饋紀錄的 UpdateTime,不是 NMQ Job 的精確啟動時間。圖要指出的是:Job 處理與寫入落在訂單成立的隔日,而日期基準選錯,才讓稽核重算結果可能差一天。

先認識這場戲的主角:BookingTime 是回饋的預約號碼牌。Dispatcher 看號碼牌,決定何時輪到給點或給券;稽核器則翻出規則,檢查號碼牌當初有沒有印錯。同一筆時間被兩個單位拿去問不同的問題,難怪只看欄位名稱,案情還是霧煞煞。

同一張號碼牌,兩個單位來查

派工像櫃檯叫號:Dispatcher 透過 BookingDateUTC-BookingTimeUTC-index 找出時間窗口內的紀錄。稽核像事後對帳:重算預期時間,再比對 BookingTimeUTC。一個問「輪到誰」,一個問「號碼對不對」。

先看正流程怎麼排時間。案發當時,線上訂單若走「加 N 天」分支,程式從訂單成立的 OrderTime 取日期,加上回饋天數,排在目標日午夜。NMQ Job 晚幾分鐘才寫入紀錄,不會讓這筆預約自動順延一天;這是第一張對照用的日曆。

正流程先抽哪張時間規則?

這張圖是 EComOrderPromotionRewardCalculateService.GetRewardConditionSetting() 的線上訂單分流。先看有沒有指定日期,再看訂單狀態與 RewardDays。規則有先後,不能一見「加 N 天」就直接跳到結局。
案發版本的算式是 OrderTime.Date.AddDays(N),結果落在目標日的 00:00。UpdateTime 記錄的是 Job 何時寫入這筆回饋,不能代替訂單成立時間。下一幕要看稽核器是否拿同一個起點來對答案。

輪到稽核器出場。已出貨、指定日期、券不足、未出貨,各有各的比對規則。這次的未出貨回饋卡在一個選擇題:用訂單成立的 OrderTime 起算,還是用 NMQ Job 寫入紀錄時留下的 UpdateTime 起算?兩者剛好分居午夜兩側,選錯起點,預期日期就跟著換頁。

稽核先分流,才輪到對時間

回饋類型 判斷順序 本文關注的入口
給點 略過指定狀態 → 已出貨且非指定日 → 指定日期 → 其餘 未出貨時進入 VerifyBookingTimeForUnshippedOrder
給券 略過指定狀態 → 近期券不足 → 已出貨 → 指定日期 → 其餘 沒有先命中券不足、已出貨或指定日時,才進入未出貨稽核
有些紀錄根本不用進考場:MatchWithoutQuota、Unmatch、Cancel、Reward 會直接略過。給點與給券的關卡順序也不同,給券會先查券不足。先看入場券,再談時間算式。

未出貨這題,誰提供起跑線?

線下訂單走 OrderTime;線上訂單若是加 N 天、又沒有改期記號,也走 OrderTime。其餘未出貨情境才輪到 UpdateTime。這張圖聚焦在稽核選擇哪個時間基準。
案發時,未出貨稽核要求時間差小於 1 小時。若起算日期選到隔天,預期排程就可能整整晚一天,24 小時差異自然過不了這道門檻。

真正的轉折不是「Job 晚了幾分鐘」本身,而是這幾分鐘剛好跨過午夜。正流程用 11/05 的訂單日期排 BookingTime;舊稽核若用 NMQ Job 寫入紀錄後留下的 11/06 UpdateTime 重算,再把時分秒歸零,兩張日曆就差了一天。Job 沒遲到 24 小時,稽核的答案卻可能晚了 24 小時。

Job 跨日後寫入,為什麼讓稽核多算一天?

這張是假設加 7 天、以 UTC+8 時鐘計算的示意圖:正流程與舊稽核若分別取訂單日期、Job 寫入紀錄的日期,排到午夜後就差 24 小時。案卷未列出該筆的 RewardDays,所以這是機制示範,不能當成原案的實際算式。

真正的案卷,留下了哪些時間?

DDB 欄位 原始 UTC 值 換算為 UTC+8
OrderTimeUTC 2025-11-05 15:54:52Z 11/05 23:54:52
UpdateTimeUTC 2025-11-05 16:02:14Z 11/06 00:02:14
BookingTimeUTC 2025-11-12 16:00:00Z 11/13 00:00:00
案卷 VSTS 546845 記下「差異 24.00 小時」。OrderTimeUTC 是訂單成立時間;UpdateTimeUTC 是 NMQ Job 處理回饋時寫下的紀錄更新時間,不是 Job 的精確啟動時間。兩者換成 UTC+8 後確實跨過午夜。不過案卷沒有列出這筆的 RewardDays;若硬套上圖的「加 7 天」,算出的 UTC 值也對不上實際 BookingTimeUTC。機制能解釋誤判方向,不能把示意圖冒充現場計算結果。

UpdateTime 變晚了,不代表預約真的改期。這點很像群組訊息:有人半夜補一句話,不等於整場活動改到明天。稽核得翻 RewardHistoryList,找程式留下的指定改期記號,再決定要不要改用更新時間起算。沒有記號,就不能自行幫預約辦一場「改期發布會」。

有更新紀錄,就算真的改期嗎?

HasDelayBookingTime() 只認既有程式寫入的固定字串 設定BookingDataTime。找到記號也還沒直接大結局;實際時間基準仍要依線上或線下,以及 RewardDays 的分支順序決定。

分支一多,規則就像口袋裡的耳機線,拿出來自動打結。拆成三個問題就好:這筆要不要稽核?拿哪個時間起算?最後怎麼比?表格是攻略地圖,但關卡有順序,不能直接傳送到喜歡的結局。

八種情境,別拿錯攻略

情境預期時間的來源稽核如何比
MatchWithoutQuota、Unmatch、Cancel、Reward不計算直接略過
線上未出貨、加 N 天、沒有改期記號OrderTime + RewardDays取訂單日期,加 N 天後與 BookingTime 比
線上未出貨、加 N 天、有改期記號UpdateTime + RewardDays取更新日期,加 N 天後與 BookingTime 比
線下未出貨OrderTime + RewardDays加 N 天時取日期並比對 BookingTime
未出貨、RewardDays = 0線上以 UpdateTime;線下以 OrderTime保留時分秒,比對 BookingTime
指定日期回饋活動設定的 RewardDateTime與 BookingTime 精確比對
已出貨回饋最後出貨時間加回饋天數,且不早於活動有效日比對 BookingDate 的日期
券不足重試依 UpdateTime 排到當天 22:00、當天或隔天 10:00與 BookingTime 精確比對
攻略表只列出各關卡怎麼算,沒有開放任意跳關。給點遇到「已出貨且指定日期」,會先走指定日期稽核;給券則先查券不足,再查已出貨。這次警報要看的,是未出貨分支有沒有誤把 Job 寫入時間當成訂單時間。

不同關卡,不能共用同一把尺

案發版本:未出貨

時間差必須小於 1 小時。剛好差 1 小時也不算過關。

指定日期

照活動設定的日期時間比對 BookingTime,不靠未出貨分支的時間基準。

券不足重試

依重試規則排出時間,再與 BookingTime 精確比對。

最後把鏡頭拉遠:訂單在午夜前成立,NMQ Job 在午夜後處理並寫入回饋紀錄。真正讓稽核報出 24 小時差異的,是正流程與舊稽核可能採用了不同的起算日期。後來的修正提交把未延遲情境改回 OrderTime;但提交不等於已在正式環境上線,這段不能擅自替劇情加彩蛋。

案發現場

HK-Prod 訂單先成立,NMQ Job 跨日後寫入回饋紀錄。

警報喊了什麼

BookingTime 與預期不符,差異為 24.00 小時。

後來修了哪裡

未延遲的線上加 N 天回饋,稽核改用 OrderTime 起算。

案發到修正,時間線說了什麼?

2025/11/05 23:54,UTC+8

訂單成立,午夜倒數中。

2025/11/06 00:02,UTC+8

NMQ Job 處理後寫入回饋紀錄,UpdateTime 落在隔日;這不是 Job 啟動時間。

原始稽核警報

工作項目記錄 BookingTime 與預期相差 24 小時。警報先響,原因還得查。

2026/01/27,稽核修正提交

未延遲的線上加 N 天回饋,稽核改用 OrderTime 起算。

警報記在 VSTS 546845;稽核修正對應 Git 提交 0dadda61。提交日期是程式碼履歷,不是正式環境的上線打卡紀錄。
已能確定的修正方向:初始且沒有延遲記號的線上加 N 天回饋,正流程與稽核都該以 OrderTime 起算。Job 何時寫入紀錄,不能悄悄把原本的訂單日期換掉。至少這次,查票與排班終於拿同一份時刻表。
要完整復盤,案卷還缺哪些拼圖?
  1. 該筆回饋實際設定的 RewardDays,以及適用的回饋條件。
  2. 應用程式讀入三個 UTC 欄位時的 DateTime 時區轉換與日期基準。
  3. 修正版本在 HK-Prod 的實際上線時間與上線後的稽核結果。
  4. 該筆 NMQ Job 的啟動時間與完整執行日誌;目前只有紀錄寫入時留下的 UpdateTime。

在這些資料補齊之前,能確定的是「24 小時警報」和「修正程式選擇的時間基準」。加 7 天只是示意算式,不能假扮成這筆訂單的實測結果。故事可以說得好懂,證據邊界還是要畫清楚。

補充:現行版本的分桶

2026/08/31 的提交 38b01eb9 才加入 RewardBookingTimeAllocator,將加 N 天的目標日分到 00:00、01:00 或 02:00。現行未出貨稽核對此使用 Math.Max(bucketCount, 3) 小時的容忍值。這是後續版本的規則,不用來重算 2025 年 11 月的警報。