我在學習Fishli李老師的博客時,看到一個話題,就是DateTime持久化, 還有人駁斥他的文章,弄的我迷糊了,因而花了點時間,一探究竟,順便作一個總結javascript
直接上結論:java
* 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毫秒" ,json
* 早於原點時間顯示負數,例如"\/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的精度不一致spa
DataContractJsonSerializer和Newtonsoft.Json(版本<=4.5)不能持久化的緣由有一個: 1. .精度和DateTime的精度不一致.net
總結: 不能持久的關鍵緣由爲: "\/Date(991+0800)\/" , 微軟格式的精度和DateTime的精度不一致, 是否是javascript的Date的精度就到毫秒,微軟顧及javascript, 懂的來講說吧..
* 後來在網上查到了下面的資料
* .net自帶的json序列化器,JavaScriptSerializer和DataContractJsonSerializer,都是序列化成微軟的datetime json格式,e.g. "\/Date(1198908717056)\/"orm
Newtonsoft.Json的行爲是這樣的。ip
<=4.5,也是序列化成微軟的datetime json格式,e.g. "\/Date(1198908717056+0800)\/".博客
>4.5,序列化成ISO標準時間格式,"2016-05-05T14:59:30.4617225+08:00" , 精確到小數點7位了, 精度和DateTime一致了string
因而我下載了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啊,
他這三個一個沒驗證, 居然就說持久化沒問題,太不嚴謹了,仍是嚴謹點好, 否則理解老是有誤差, 誤導了別人就很差了.