DateTime持久化总结
我在学习Fishli李老师的博客时,看到一个话题,就是DateTime持久化, 还有人驳斥他的文章,弄的我迷糊了,于是花了点时间,一探究竟,顺便做一个总结
直接上结论:
* 1. DateTime是结构体
*
* 2. DateTime.Kind 指明此DateTime 是Utc(协调世界时) 还是 Local(本地时间) , 但是DateTime里并不保存时区和时差值.
*
* 3. DateTime.Ticks 是0001年1月1日0点0分0秒为原点. 精确到 "0.1微秒". 指明计数周期 (1Tick = 0.1微秒)
*
* 4. dt1 == dt2, 判断的依据是Ticks是否相等, 而不考虑 Kind, 所以会出现两种情况: 1.不为同一时刻, 但值相等. 2.同一时刻, 但值不相等 .
*
* 5. 序列化时, 以Utc时间1970年1月1日0点0分0秒0毫秒为原点, 精确到 "1毫秒" ,
* 早于原点时间显示负数,例如"\/Date(-112+0800)\/", 晚于原点时间显示正数,例如:"\/Date(991+0800)\/" .
*
*
* 假设 dt_loc.Kind = Local , dt_loc.Ticks = 621356256009910001
*
* 等效为: dt_loc.ToUniversalTime().Kind = Utc , dt_loc.ToUniversalTime().Ticks = 621355968009910001
*
* JavaScriptSerializer序列化过程:
* 计算生成Utc下的Ticks值=621355968009910001
* 改为以1970年1月1日0点0分0秒0毫秒为时间原点 ,得到 9910001
* 精度从0.1微秒降为1毫秒, (直接砍掉了后四位0001), 得到991
* 序列化为 "\/Date(991)\/"
* 序列化结果里只包含Utc的Ticks值, 不含Kind和时差值.
*
*
*
* DataContractJsonSerializer & Newtonsoft.Json (版本<=4.5) 序列化过程:
* 保持原Ticks值=621356256009910000
* 改为以1970年1月1日0点0分0秒0毫秒为时间原点 ,得到 9910000
* 精度从0.1微秒降为1毫秒, (直接砍掉了后四位0001), 得到991
* 通过TimeZoneInfo.Local.Id得到时差值: +0800
* 序列化为 "\/Date(991+0800)\/"
* 序列化结果里不含Kind, 但包含时差值,变相保存了时区信息、Kind信息(有+0800就是Local,没有+0800就是Utc).
*
JavaScriptSerializer不能持久化的原因有两个: 1. 不保存时差值 2.精度和DateTime的精度不一致
DataContractJsonSerializer和Newtonsoft.Json(版本<=4.5)不能持久化的原因有一个: 1. .精度和DateTime的精度不一致
总结: 不能持久的关键原因为: "\/Date(991+0800)\/" , 微软格式的精度和DateTime的精度不一致, 是不是javascript的Date的精度就到毫秒,微软顾及javascript, 懂的来说说吧..
* 后来在网上查到了下面的资料
* .net自带的json序列化器,JavaScriptSerializer和DataContractJsonSerializer,都是序列化成微软的datetime json格式,e.g. "\/Date(1198908717056)\/"
Newtonsoft.Json的行为是这样的。
<=4.5,也是序列化成微软的datetime json格式,e.g. "\/Date(1198908717056+0800)\/".
>4.5,序列化成ISO标准时间格式,"2016-05-05T14:59:30.4617225+08:00" , 精确到小数点7位了, 精度和DateTime一致了
于是我下载了5.0.1版本的Newtonsoft. 试了下, 的确可以持久化了.
var settings = new JsonSerializerSettings();
settings.DateFormatHandling = DateFormatHandling.IsoDateFormat; // 如果要输出ISO标准时间,可以通过dateTimeFormat进行设置。
string s0 = JsonConvert.SerializeObject(dt_loc, settings);
DateTime Newtonsoft_dt2 = JsonConvert.DeserializeObject<DateTime>(s0);
dt_loc == Newtonsoft_dt2 为 true
结论就是: Newtonsoft.Json(版本>4.5) 能持久化的关键原因就是, 序列化时采取ISO标准, 保存了时差, 保持了精度,所以反序列化时才能原原本本的还原.
那篇反驳的文章则验证持久化的方法不对, 他将序列化后的JSON字符结果放到javascript中能够解析出时间, 就认为持久化没有问题,
但是他没有注意, JSON字符里的Ticks 和 DateTime里的Ticks 精度并不一样, JSON字符里的Ticks的精度只到1毫秒, 而 DateTime里的Ticks的精确到0.1微秒,
验证持久化最简单的办法就是, 判断一下Kind是否一致, 再验证一下Ticks是否一致 , 最后就是 dt1 == dt2 是否返回true啊,
他这三个一个没验证, 竟然就说持久化没问题,太不严谨了,还是严谨点好, 不然理解总是有偏差, 误导了别人就不好了.