坑!为什么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>)。

 

努力工作 认真生活 持续学习 以勤补拙

posted @ 2020-07-10 00:12  丁哥  阅读(4312)  评论(0编辑  收藏  举报