日期和時(shí)間相關(guān)的 bug,永遠(yuǎn)是寫業(yè)務(wù)代碼時(shí)容易忽視的大坑。我剛?cè)胄袝r(shí),幾乎每個(gè)時(shí)間戳都直接DateTime.Now
,直到有一天,線上報(bào)了個(gè)“訂單時(shí)間提前了6小時(shí)”的嚴(yán)重 bug。今天聊聊.NET中DateTime.Now
的那些坑,以及如何優(yōu)雅地處理時(shí)間。
DateTime.Now 與 DateTime.UtcNow 究竟差了什么? 真實(shí)場(chǎng)景 想象下,你在中國(guó)服務(wù)器上用DateTime.Now
記錄訂單創(chuàng)建時(shí)間,把這個(gè)時(shí)間存數(shù)據(jù)庫(kù),日后用于各種報(bào)表、通知,甚至對(duì)接海外系統(tǒng)。突然,某天服務(wù)器被遷移到倫敦,或者有微服務(wù)在其它時(shí)區(qū),瞬間表里的時(shí)間全錯(cuò)——不是提前就是延后。
兩者差別 ? DateTime.Now
:返回本地時(shí)區(qū)時(shí)間,受服務(wù)器當(dāng)前所在時(shí)區(qū)影響。當(dāng)服務(wù)器時(shí)區(qū)有變動(dòng),歷史數(shù)據(jù)就可能混亂。 ? DateTime.UtcNow
:UTC 時(shí)間,全世界統(tǒng)一,對(duì)分布式系統(tǒng)、微服務(wù)極其友好。 推薦實(shí)踐:優(yōu)先使用 UTC 時(shí)間 我現(xiàn)在除了做業(yè)務(wù)邏輯直接跟 UI 展示相關(guān)的,都用DateTime.UtcNow
存儲(chǔ),只有UI展示時(shí)再做時(shí)區(qū)轉(zhuǎn)換。這極大減少了跨時(shí)區(qū)的 bug,也讓系統(tǒng)變得健壯。
代碼示例 // 寫入數(shù)據(jù)庫(kù)前 var createdUtc = DateTime.UtcNow; SaveToDb(orderId, createdUtc); // 存儲(chǔ)統(tǒng)一 UTC 時(shí)間 // 展示時(shí)轉(zhuǎn)換為用戶時(shí)區(qū) var userTimeZone = TimeZoneInfo.FindSystemTimeZoneById("China Standard Time" );var displayTime = TimeZoneInfo.ConvertTimeFromUtc(createdUtc, userTimeZone); Console.WriteLine($"訂單創(chuàng)建時(shí)間: {displayTime} " );
開發(fā)常見誤區(qū) ? **誤區(qū)一:只有海外業(yè)務(wù)才用 UTC。**其實(shí)只要有多臺(tái)服務(wù)器、云部署,這事就得注意。 ? **誤區(qū)二:DateTime.Now
能自動(dòng)感知時(shí)區(qū)變化。**其實(shí)它只是當(dāng)前操作系統(tǒng)時(shí)區(qū),不是用戶真實(shí)時(shí)區(qū)。 最佳實(shí)踐清單 ? 數(shù)據(jù)庫(kù)存儲(chǔ)一律用DateTime.UtcNow
。 ? 展示時(shí)明確用戶時(shí)區(qū),做轉(zhuǎn)換。 ? 日志、審計(jì)、接口調(diào)用時(shí)間,也建議用 UTC。 踩坑總結(jié) 早期公司時(shí)區(qū)變更,把表里本地時(shí)間誤認(rèn)成 UTC,導(dǎo)致歷史訂單全亂,臨時(shí)寫了幾十行腳本才勉強(qiáng)修正。建議大家把這事早早規(guī)范,特別是涉及分布式、微服務(wù)、海外業(yè)務(wù)的項(xiàng)目。
結(jié)論: 以后動(dòng)手寫DateTime.Now
前,先問自己——這玩意存下來(lái)后,時(shí)區(qū)變了會(huì)不會(huì)掛?只要有疑慮,直接上DateTime.UtcNow
,展示時(shí)再轉(zhuǎn)換。本地時(shí)間只做瞬時(shí)展示,存儲(chǔ)永遠(yuǎn) UTC,后患無(wú)窮全趕走!
該文章在 2025/9/2 12:06:42 編輯過