JSON日期轉換的時區陷阱
来源:互联网 发布:颜晖c语言视频百度云 编辑:程序博客网 时间:2024/06/11 02:04
JSON日期轉換的時區陷阱
2014-02-12 17:20:56| 分类:HTML/CSS/JS |举报|字号 订阅
在使用Kendo UI DatePicker時,出現選好日期送至後端卻變成前一天的狀況。
以下程式可重現問題,kendoDatePicker所選日期透過.value()可得到一個JavaScript Date物件,JSON.stringify()後傳至Server端,使用Json.NET還原回DateTime後,以ToString("yyyy-MM-dd HH:mm:ss")方式傳回Client端alert顯示。
<%@ Page Language="C#" %><%@ Import Namespace="Newtonsoft.Json" %> <!DOCTYPE html> <script runat="server"> protected void Page_Load(object sender, EventArgs e) { if (Request["m"] == "post") { var p = Request["d"]; var nd = JsonConvert.DeserializeObject<DateTime>(p); Response.Write(string.Format("{0}->{1:yyyy-MM-dd HH:mm:ss}", p, nd)); Response.End(); } }</script> <html xmlns="http://www.w3.org/1999/xhtml"><head id="Head1" runat="server"> <title></title> <link href="../Content/kendo/2013.1.319/kendo.common.min.css" rel="stylesheet" /> <link href="../Content/kendo/2013.1.319/kendo.bootstrap.min.css" rel="stylesheet" /></head><body> <form id="form1" runat="server"> <input data-bind="kendoDatePicker: { value: TheDate, format: 'yyyy-MM-dd' }" /> <br /> <span data-bind="text: TheDate"></span> <input type="button" data-bind="click: post" value="POST" /> </form> <script src="../Scripts/jquery-1.9.1.min.js"></script> <script src="../Scripts/kendo/2013.1.319/kendo.web.min.js"></script> <script src="../Scripts/knockout-2.2.1.js"></script> <script src="../Scripts/knockout-kendo.min.js"></script> <script> function myViewModel() { var self = this; self.TheDate = ko.observable("2012-12-21"); self.post = function () { $.post("", { m: "post", d: JSON.stringify(self.TheDate()) }, function (r) { alert("Result = " + r); }); }; } var vm = new myViewModel(); ko.applyBindings(vm); </script></body></html>
測試結果如下:
明明選了12/22日,但傳到.NET端ToString後卻是12/21日! 問題出在12/22的本地時間在JSON.stringify時被轉成UTC,12/22凌晨0點減去8小時,於是.NET端得到 DateTimeKind = UTC 的DateTime -- 12/21 16:00 UTC。
依據Telerik RD的說法,kendo.stringify跟JSON.stringify一樣,會將本地時間轉換成UTC時間,而kendoDatePicker .value()傳回的是JavaScript Date物件時區則會以本地時間為準,JSON轉成UTC後,若.NET處理時沒轉回本地時間或UTC時間,就會出問題。
知道原委,我理解到這個問題與Kendo UI無關,而是JSON具有全球化觀點,.NET端沒跟上造成的。在一個全球化網站,傳送時間需反應使用者所在時區,Server端才能精準掌握真正時點,但前提是.NET端應將來自各地的時間一律轉為UTC時間或本地時間才合理,直接ToString()看到的是當地時間,忽略時區差異便會衍生問題。
因此,我們可以重塑一個與Kendo UI無關的精簡範例:
<%@ Page Language="C#" %><%@ Import Namespace="Newtonsoft.Json" %> <!DOCTYPE html> <script runat="server"> protected void Page_Load(object sender, EventArgs e) { if (Request["m"] == "post") { var p = Request["d"]; var nd = JsonConvert.DeserializeObject<DateTime>(p); Response.Write(string.Format("{0}->{1:yyyy-MM-dd HH:mm:ss}", p, nd)); Response.End(); } }</script> <html xmlns="http://www.w3.org/1999/xhtml"><head id="Head1" runat="server"> <title></title></head><body> <form id="form1" runat="server"> <span id="sTime"></span> </form> <script src="../Scripts/jquery-1.9.1.min.js"></script> <script> var d = new Date(); $("#sTime").text(d.toString()); $.post("", { m: "post", d: JSON.stringify(d) }, function (r) { alert("Result = " + r); }); </script></body></html>
在早上8:00以前,將new Date()經JSON轉換後送到.NET,還原回DateTime再ToString(),看到的日期會是前一天!!
面對這個問題有兩個解決方向:
- 在Server端落實全球化概念,所有來自Client端的JSON時間,一律轉為UTC保存,顯示呈現時再視需求決定時區。
- 如果只是本土小公司使用的內網系統,所有Client端座落在方圓100公尺內,只因為用了JSON就要在系統推行全球化有點小題大作。而且,Server未必能配合修改,此時就要考慮由Client端解決。
要從Client端解決,我想到的做法是讓JSON.stringify()忽略時區差異,轉成"2013-06-22T07:18:48"(最後不加Z或+0800,對應成.NET DateTime相當於Kind = Unspecified)。實作技巧是偷偷將Date.prototype.toISOString()改成我們自訂的版本:
<script> //將原本的函數保留起來,必要時可以換回去 var _toIsoDate = Date.prototype.toISOString; //借用kendo.toString做出Unspecified Kind的ISO8601格式 Date.prototype.toISOString = function () { return kendo.toString(this, "yyyy-MM-ddTHH:mm:ss"); }; function myViewModel() { var self = this; self.TheDate = ko.observable("2012-12-21");//...以下略...
重新評估後,改寫.toJSON()只會針對JSON轉換調整邏輯,較置換.toISOString()更符合目的,感謝Kuo-Chun Su提醒。
<script> //借用kendo.toString做出Unspecified Kind的ISO8601格式 Date.prototype.toJSON = function () { return kendo.toString(this, "yyyy-MM-ddTHH:mm:ss"); }; function myViewModel() { var self = this;
如此,應該就能避開惱人的JSON日期時差問題囉~
- JSON日期轉換的時區陷阱
- Java Date Timestamp 日期比较的陷阱
- Json日期格式的问题
- HRBUST 2007 小Q的生日 (日期陷阱)
- ASP.NET MVC的JSON序列化陷阱
- JSON日期在前端显示的格式
- json对象的用法包括日期格式化
- json对象的用法包括日期格式化
- linq json 对象里面的 日期 转换
- 关于json返回日期格式化的解决方案
- 关于json返回日期格式化的解决方案
- 关于json返回日期格式化的解决方案
- 关于JSON返回日期格式化的解决方案
- json返回日期格式化的解决
- 返回json的日期格式问题
- springmvc返回json的日期格式问题
- 【前端】格式化Json传递的日期
- Json-lib 如何转换日期格式的字段 json-->java
- 解决JLINK_v8灯不亮
- 在linux下安装redis
- hdu5014 构造b数列使得t最大(小想法)
- 黑马程序员------张孝祥高新技术(一)--java1.5新特性
- 如何自定义iOS中的控件
- JSON日期轉換的時區陷阱
- 分久必合,合久必分
- turbogears学习记录(一)
- 程序动态完整性校验之指令分支记录
- 字符串替换
- CSS选择器、优先级与匹配原理
- POJ 2159 Ancient Cipher
- SQLite基础知识及简单应用
- 如何在ubuntu下安装设置mysql