C#中DateTime的缺陷 ---- 代替品DateTimeOffset
C#中的DateTime在逻辑上有个非常严重的缺陷:
> var d = DateTime.Now;
> var d2 = d.ToUniversalTime();
> d == d2
false
> d.Equals(d2);
false
在C#交互模式中输入以上代码,可以发现尽管一个是本地时间(d),一个是UTC时间(d2),只是时区不一样,但在这个世界上,应该属于同一个时刻。然而两个时间却不相等。。。
原因在于DateTime不存储时区,或者说,只存储了一个模糊的关于时区的字段Kind,它是DateTimeKind枚举类型的,有三种取值:Utc/Local/Unspecified,当取值为Unspecified时,则会有歧义。
但我还是要吐槽,如果d.Kind或d2.Kind中任意一个是Unspecified,那么d != d2我可以理解。但是上面的d.Kind是Local,d2.Kind是Utc,如果按照DateTime不存储时区的逻辑,那么这两个统一转换Utc或者Local时,那么它们应该相等,事实上也是如此:
> d == d2.ToLocalTime()
true
如果把d的本地时间t1当做9,本地时间所处时区z1当做+8,相应的UTC时间t0当做1,UTC时间所处时区z0当做0,对它们做规范化处理:
那么 d = t1-z1 = 9 - 8 = 1, d2 = t0 - z0 = 1 - 0 = 1 。
然而 d != d2。这才是它怪异的地方。
以东八区为例,在C#交互模式中输入以下代码:

> var d3 = new DateTime(, , );
> d3
[// ::]
> d3.ToLocalTime()
[// ::]
> d3.ToUniversalTime()
[// ::]

可以发现,一个简单的构造函数,开发者心中默认一般都是本地时间,然而它却允许直接创建出一个既非本地时间、也非UTC时间的怪物。
当d3转成本地时间时,会把d3作为UTC时间来加8小时。
当d3转成UTC时间时,却会把d3作为本地时间来减8小时。
那么d3到底是本地时间还是UTC时间呢?没人清楚,除非它存在于一个非常小的局部作用域中,并且生命周期极短,这时候我们也许可以假设它为本地时间。
然而这个本地时间也依赖于它的运行环境,如果是有几台时区不一致的计算机,阉割了时区信息的DateTime转成字符串在网络中传输到另一个时区(比如隔壁的十一区)的另一台服务器中,解析出来后,所谓的东八区本地时间8点,到了日本,变成了既非本地时间、也非UTC时间的怪物。
DateTime在官方文档中已经不推荐使用,而是推荐使用它的代替品DateTimeOffset,后者保存时区信息。
在交互模式中验证一下:
> var dto = DateTimeOffset.Now;
> var dto2 = dto.ToUniversalTime();
> dto == dto2
true
可以发现,DateTimeoffset判断两个时间是否等价的标准,是以世界时间轴的时刻来判断的,与时区无关,甚至可以与UTC时间无关。只要它们都在同一个时间体系里、能互相变换即可。
在实际项目中,建议大家:
- 如果有使用DateTime的,统一换成DateTimeOffset。
- 如果有用到32比特的UNIX时间戳的,统一换成64比特的long来存储UtcTicks。
即使项目本身不跨时区,仍然有可能遇到时区问题,比如如果使用了mongodb的,mongodb存储的时候都是统一存成UTC时间的(好像是,忘了),而且一般来说会带有时区信息。但是有一种情况比较糟糕,如果你的DateTime的Kind是Unspecified的,隐含的时区的信息就会丢失。再取出来之后,就会有8小时的时差。有一些第三方的或者自己公司的类库之类的,如果没有处理好这个问题,也有潜在的时区丢失问题。UNIX时间戳存成Utc Ticks也有好处,无论是精度还是时间跨度,都远超UNIX时间戳。只需要64比特,即可获得下至100纳秒的精度,上超万年的时间跨度,一劳永逸,无论是转回UNIX时间戳还是JS时间戳,都能胜任。空间代价也非常小,除非你的存储空间真的是硬伤。。
出处:http://www.cnblogs.com/zlmdy/p/8560396.html
C#中DateTime的缺陷 ---- 代替品DateTimeOffset的更多相关文章
- C#中DateTime的缺陷与代替品DateTimeOffset
C#中的DateTime在逻辑上有个非常严重的缺陷: > var d = DateTime.Now; > var d2 = d.ToUniversalTime(); > d == d ...
- C#中 DateTime , DateTime2 ,DateTimeOffset 之间的小区别 (转载)
闲来无事列了个表比对一下这3兄弟之间还是有一点差距的╮(╯_╰)╭ DateTime DateTime2 DateTimeOffset 日期范围 1753-01-01到 9999-12-31 00 ...
- .NET中DateTime.Now.ToString的格式化字符串
.NET中DateTime.Now.ToString显示毫秒:DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") DateTime.N ...
- easyui datagrid中datetime字段的显示和增删改查问题
datagrid中datetime字段的异常显示: 使用过easyui datagrid的应该都知道,如果数据库中的字段是datetime类型,绑定在datagrid显式的时候会不正常显示,一般需要借 ...
- 解决Asp.net Mvc返回JsonResult中DateTime类型数据格式的问题
问题背景: 在使用asp.net mvc 结合jquery esayui做一个系统,但是在使用使用this.json方法直接返回一个json对象,在列表中显示时发现datetime类型的数据在转为字符 ...
- SQL中DateTime转换成Varchar样式
SQL中DateTime转换成Varchar样式语句及查询结果:Select CONVERT(varchar(100), GETDATE(), 0): 05 16 2006 10:57AMSelect ...
- python中datetime模块中datetime对象的使用方法
本文只讲述datetime模块中datetime对象的一些常用的方法,如果读者需要更多datetime模块的信息,请查阅此文档. datetime模块的对象有如下: timedelta date da ...
- C# WebAPI中DateTime类型字段在使用微软自带的方法转json格式后默认含T的解决办法
原文:C# WebAPI中DateTime类型字段在使用微软自带的方法转json格式后默认含T的解决办法 本人新手,在.Net中写WebAPI的时候,当接口返回的json数据含有日期时间类型的字段时, ...
- 解决python写入mysql中datetime类型遇到的问题
解决python写入mysql中datetime类型遇到的问题 刚开始使用python,还不太熟练,遇到一个datetime数据类型的问题: 在mysql数据库中,有一个datetime类型的字段用于 ...
随机推荐
- 原生js实现选项卡
html代码: <div class="tab"> <ul> <li class="selected">图片</li& ...
- 『Python』图像金字塔、滑动窗口和非极大值抑制实现
图像金字塔 1.在从cv2.resize中,传入参数时先列后行的 2.使用了python中的生成器,调用时使用for i in pyramid即可 3.scaleFactor是缩放因子,需要保证缩放后 ...
- python-day21--sys模块
sys模块是与python解释器交互的一个接口 1.sys.argv 命令行参数List,第一个元素是程序本身路径 # 传参 应用场景:权限控制 2.sys.path ...
- UVA-11214 Guarding the Chessboard (迭代加深搜索)
题目大意:在一个国际象棋盘上放置皇后,使得目标全部被占领,求最少的皇后个数. 题目分析:迭代加深搜索,否则超时. 小技巧:用vis[0][r].vis[1][c].vis[2][r+c].vis[c- ...
- HDU-1548 A strange lift(单源最短路 或 BFS)
Problem Description There is a strange lift.The lift can stop can at every floor as you want, and th ...
- dp入门:最长不下降序列
#include "bits/stdc++.h" using namespace std; ],dp[]; int main() { int n; cin >> n; ...
- Apache Tomcat 6.0 Tomcat6 服务因 1 (0x1) 服务特定错误而停止
1.Tomcat目录下的bin
- Vue--Vue.nextTick()的使用
Vue.nextTick()是比较常用到的API Vue官网对它的解释是:在下次 DOM 更新循环结束之后执行延迟回调.在修改数据之后立即使用这个方法,获取更新后的 DOM. 首先要明白Vue的响应式 ...
- @SpringBootApplication的使用
之前用户使用的是3个注解注解他们的main类.分别是@Configuration,@EnableAutoConfiguration,@ComponentScan.由于这些注解一般都是一起使用,spri ...
- Grep console 设置
Grep console DEBUG 9961B8 INFO 4B5E76 WARN 8A8A00 ERROR 9F6B00 8A7674