好久沒發文章了,感覺確實該動動了。實際上已經准備了幾篇內容,但是不整理到自己感覺清晰的程度,總是不想發布,因為網上零零碎碎的信息確實太多了,不必再多一份。
所以今天談一個簡單點的問題:DateTime.Now獲取時間竟然不是當前時間!
原始場景使用FluentValidation框架做數據驗證,顧客的出生日期與當前日期DateTime.Now.Date做對比,
對比結果就出現了標題所說的場景,Log記錄大體意思是客戶生日[2020-7-6]不能晚於當前日期。
而此時時間是2020-7-8。這不是怪了么!2020-7-6確實是前端傳過來的沒有錯。
出現這個問題的時候,我的內心是崩潰的!這樣說是DateTime.Now.Date獲取時間不正確?What's the hell!
在說出這里面的鬼之前,先看一段代碼。
1 class TimeValidation 2 { 3 /// <summary> 4 /// 最大時間值 5 /// </summary> 6 readonly DateTime _timeMax; 7 8 public TimeValidation(DateTime timeMax) 9 { 10 _timeMax = timeMax; 11 } 12 13 public bool IsTimeValid(DateTime time) 14 { 15 return time <= _timeMax; 16 } 17 }
對於這個驗證類,執行以下代碼返回值應該是什么呢?
1 var timeValidation = new TimeValidation(DateTime.Now); 2 bool result1 = timeValidation.IsTimeValid(now); 3 //概括目的就是:實例化驗證類,用當前時間作為屬性值的最大限定值,
4 //然后驗證當前時間是不是有效的值,
5 //這時result1是true還是false?請先選出你的答案
最終結果當然不是true,否則就不會感覺見鬼了。在說明緣由之前,再看一段代碼或許大家都能恍然大悟。
1 class TimeValidationEx 2 { 3 /// <summary> 4 /// 最大時間值表達式 5 /// </summary> 6 readonly Expression<Func<DateTime>> _timeMaxEx; 7 8 public TimeValidationEx(Expression<Func<DateTime>> timeMaxExpression) 9 { 10 _timeMaxEx = timeMaxExpression; 11 } 12 13 public bool IsTimeValid(DateTime time) 14 { 15 return time <= _timeMaxEx.Compile()(); 16 } 17 }
對於這個驗證類,執行以下代碼返回值應該是什么呢?
1 var timeValidation2 = new TimeValidationEx(() => DateTime.Now); 2 bool result2 = timeValidation2.IsTimeValid(now); 3 //這時result2是true還是false?
答案是true。
此時或許大家都能想到到底哪里有鬼了。
對於TimeValidation類,實例化時候傳遞參數DateTime.Now,本來意圖是傳遞當前時間,但實際只是傳遞當前這一時刻的時間值,並賦值給了內部的_timeMax字段。
而賦值完成后,這個“當前時間”就已經是歷史了(我提到的案例中就是停留在了昨天2020-7-6),而不是我們想要的當前時間了。
對於TimeValidationEx類,實例化時候傳遞參數是() => DateTime.Now,這是一個Expression<Func<DateTime>>類型的值(如果不了解Expression,可以單獨去了解一下)。
而在驗證方法里代碼也是這樣的:
return time <= _timeMaxEx.Compile()();
所有_timeMaxEx是一個Expression<Func<DateTime>>類型的實例,是一個Expression,而這個Expression內部是一個Func<DateTime>委托,
委托就是特殊的方法嘛,而這個方法的邏輯就是直接返回DateTime.Now的值。
相對TimeValidation類中的_timeMax字段,它在需要時候才會被調用來獲取值並返回,它是“動態”的,它才是真正的獲取當前時間!
總結一下:
- 在開發過程中,對於類似DateTime.Now這種“動態”的值一定要留神;
- 頭腦要時刻明白,這個值只是代碼執行的一瞬間獲取到的,保存到任何變量以后,它就已經是固定的、過去的;
- 確定需要獲取真正的當前值得時候,使用表達式或者委托(Expression<Func<T>>或Func<T>)。
努力工作 認真生活 持續學習 以勤補拙