发现问题
单元格编辑时, 你可能会遇到前台传入的时间, 后台通过 C# 获取时差 8 个小时, 这是怎么回事呢?
这个问题可能会困扰一些同学, 我也不止一次的收到这样的问题, 这个是昨天一个网友的提问:
之前还有网友在发表类似的问题:
为了演示这一过程, 我通过一个简单的例子来说明问题, 首先新建一个页面:
- @(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"))
后台代码:
- [HttpPost]
- [ValidateAntiForgeryToken]
- public ActionResult btnSubmit_Click(FormCollection values)
- {
- UIHelper.Label("labResult").Text("开始日期:" + values["DatePicker1"]);
- return UIHelper.Result();
- }
因为后台直接从请求表单中读取的字符串, 所以没有问题, 前台参数传入:
DatePicker1: 2019-03-21 14:48:55
页面上显示:
开始日期: 2019-03-21 14:48:55
现在前台新增一个按钮, 并通过自定义回发的形式传入后台:
- @(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();
- }
此时再看回发后的前台显示:
开始日期: 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();
- }
只不过这个路子绕的有点远.
来源: https://www.cnblogs.com/sanshi/p/10572060.html