单元格编辑时,你可能会遇到前台传入的时间,后台经过C#获取时差8个小时,这是怎么回事呢?浏览器
这个问题可能会困扰一些同窗,我也不止一次的收到这样的问题,这个是昨天一个网友的提问:工具
以前还有网友在发表相似的问题:ui
为了演示这一过程,我经过一个简单的例子来讲明问题,首先新建一个页面:spa
@(F.DatePicker().DateFormatString("yyyy-MM-dd HH:mm:ss").Label("开始日期").ID("DatePicker1").ShowTime(true).SelectedDate(DateTime.Now)) @(F.Button().ID("btnSubmit").Text("提交表单").OnClick(Url.Action("btnSubmit_Click"), "DatePicker1")) @(F.Label().ID("labResult"))
后台代码:3d
[HttpPost] [ValidateAntiForgeryToken] public ActionResult btnSubmit_Click(FormCollection values) { UIHelper.Label("labResult").Text("开始日期:" + values["DatePicker1"]); return UIHelper.Result(); }
由于后台直接从请求表单中读取的字符串,因此没有问题,前台参数传入:调试
DatePicker1: 2019-03-21 14:48:55
页面上显示:code
开始日期:2019-03-21 14:48:55
如今前台新增一个按钮,并经过自定义回发的形式传入后台:orm
@(F.Button().ID("btnSubmit2").Text("自定义回发").OnClientClick("btnSubmit2Click();")) function btnSubmit2Click() { F.doPostBack('@Url.Action("btnSubmit2_Click")', { values: F.toJSON({ DatePicker1: F.ui.DatePicker1.getValue() }) }); }
后台直接从JSON对象中读取数据,并显示:对象
[HttpPost] [ValidateAntiForgeryToken] public ActionResult btnSubmit2_Click(JObject values) { UIHelper.Label("labResult").Text("开始日期:" + values["DatePicker1"].ToString()); return UIHelper.Result(); }
此时再看回发后的前台显示:blog
开始日期:2019/3/21 6:45:44
好嘛!恰好差8个小时,逮个正着!
可能有人会说了,是否是前台传入的数据有误?其实不是的,打开浏览器调试工具,看下传入的参数:
values: {"DatePicker1":"2019-03-21T06:48:55.000Z"}
能够发现,前台 F.toJSON 以后,原来的字符串 2019-03-21 14:48:55 被转化为标准时间:2019-03-21T06:48:55.000Z
这个转化是没问题的,由于它(2019-03-21T06:48:55.000Z)描述的是标准零时区的时间,和咱们的本地时间(北京时间,东八区)恰好差了8个小时。
问题出在后台JSON格式转化,JSON.NET会识别含有相似 2019-03-21T06:48:55.000Z 的字符串,并将之转化为时间格式!!
在VS中调试,能够看到 values["DatePicker1"] 实际上是 Date 类型,并不是咱们所指望的 string 类型:
其实这个时间对象也没问题,只不过它表示的是标准零时区时间,咱们只需将其转化为本地时间就能够了,因此正确的代码应该是这样的:
[HttpPost] [ValidateAntiForgeryToken] public ActionResult btnSubmit2_Click(JObject values) { UIHelper.Label("labResult").Text("开始日期:" + values.Value<DateTime>("DatePicker1").ToLocalTime().ToString()); return UIHelper.Result(); }
如今前台显示:
开始日期:2019/3/21 14:48:55
还能够将字符串格式化为须要的格式:
UIHelper.Label("labResult").Text("开始日期:" + values.Value<DateTime>("DatePicker1").ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss"));
此时前台显示:
开始日期:2019-03-21 14:48:55
还有观众说了,JSON.NET的这个自动转化我不须要,能不能直接拿到这个字符串,而后我本身经过 DateTime.Parse 来转换呢?
我在网上搜索了一下,发现以下两个解决办法,供参考:
办法一:
JsonReader reader = new JsonTextReader(new StringReader(values.ToString())); reader.DateParseHandling = DateParseHandling.None; JObject o = JObject.Load(reader); // 2019/3/21 14:48:55 var result1 = DateTime.Parse(o.Value<string>("DatePicker1")).ToString();
办法二:
JsonSerializerSettings settings = new JsonSerializerSettings() { DateParseHandling = DateParseHandling.None }; JObject j2 = JsonConvert.DeserializeObject<JObject>(values.ToString(), settings);
说白了就是告诉 JSON.NET,不要自做主张的帮我把字符串转换为日期对象(DateParseHandling.None),我要取得原始的字符串。
而且因为上面须要把 values 先转换为字符串,既然如此,还不如直接使用 string 来接受参数(少了一次参数自动类型转换和一次强制类型转换):
[HttpPost] [ValidateAntiForgeryToken] public ActionResult btnSubmit2_Click(string values) { JsonSerializerSettings settings = new JsonSerializerSettings() { DateParseHandling = DateParseHandling.None }; JObject j2 = JsonConvert.DeserializeObject<JObject>(values, settings); return UIHelper.Result(); }
只不过这个路子绕的有点远。