我在學習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啊,
他這三個一個沒驗證, 竟然就說持久化沒問題,太不嚴謹了,還是嚴謹點好, 不然理解總是有偏差, 誤導了別人就不好了.
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/195857.html
標籤:.NET技术
