坑!為什么DateTime.Now獲取時間不正確,而是過去的時間?


好久沒發文章了,感覺確實該動動了。實際上已經准備了幾篇內容,但是不整理到自己感覺清晰的程度,總是不想發布,因為網上零零碎碎的信息確實太多了,不必再多一份。

所以今天談一個簡單點的問題: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字段,它在需要時候才會被調用來獲取值並返回,它是“動態”的,它才是真正的獲取當前時間

 

總結一下:

  1. 在開發過程中,對於類似DateTime.Now這種“動態”的值一定要留神;
  2. 頭腦要時刻明白,這個值只是代碼執行的一瞬間獲取到的,保存到任何變量以后,它就已經是固定的、過去的;
  3. 確定需要獲取真正的當前值得時候,使用表達式或者委托(Expression<Func<T>>或Func<T>)。

 

努力工作 認真生活 持續學習 以勤補拙


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM