FineUI 官方论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

本论坛已关闭(禁止注册、发帖和回复)
请移步 三石和他的朋友们

FineUI首页 WebForms - MVC & Core - JavaScript 常见问题 - QQ群 - 十周年征文活动

FineUI(开源版) 下载源代码 - 下载空项目 - 获取ExtJS - 文档 在线示例 - 版本更新 - 捐赠作者 - 教程

升级到 ASP.NET Core 3.1,快、快、快! 全新ASP.NET Core,比WebForms还简单! 欢迎加入【三石和他的朋友们】(基础版下载)

搜索
查看: 2560|回复: 0
打印 上一主题 下一主题

【经验分享】为什么后台取到的时间差8小时?

[复制链接]
跳转到指定楼层
楼主
发表于 2019-3-21 15:16:22 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
发现问题

单元格编辑时,你可能会遇到前台传入的时间,后台通过C#获取时差8个小时,这是怎么回事呢?

为了演示这一过程,我通过一个简单的例子来说明问题,首先新建一个页面:
  1. @(F.DatePicker().DateFormatString("yyyy-MM-dd HH:mm:ss").Label("开始日期").ID("DatePicker1").ShowTime(true).SelectedDate(DateTime.Now))
  2.     @(F.Button().ID("btnSubmit").Text("提交表单").OnClick(Url.Action("btnSubmit_Click"), "DatePicker1"))

  3.     @(F.Label().ID("labResult"))
复制代码


后台代码:
  1. [HttpPost]
  2. [ValidateAntiForgeryToken]
  3. public ActionResult btnSubmit_Click(FormCollection values)
  4. {
  5.         UIHelper.Label("labResult").Text("开始日期:" + values["DatePicker1"]);

  6.         return UIHelper.Result();
  7. }
复制代码


因为后台直接从请求表单中读取的字符串,所以没有问题,前台参数传入:
  1. DatePicker1: 2019-03-21 14:48:55
复制代码


页面上显示:
  1. 开始日期:2019-03-21 14:48:55
复制代码



现在前台新增一个按钮,并通过自定义回发的形式传入后台:
  1. @(F.Button().ID("btnSubmit2").Text("自定义回发").OnClientClick("btnSubmit2Click();"))

  2. function btnSubmit2Click() {
  3.         F.doPostBack('@Url.Action("btnSubmit2_Click")', {
  4.                 values: F.toJSON({
  5.                         DatePicker1: F.ui.DatePicker1.getValue()
  6.                 })
  7.         });
  8. }
复制代码


后台直接从JSON对象中读取数据,并显示:
  1. [HttpPost]
  2. [ValidateAntiForgeryToken]
  3. public ActionResult btnSubmit2_Click(JObject values)
  4. {
  5.         UIHelper.Label("labResult").Text("开始日期:" + values["DatePicker1"].ToString());

  6.         return UIHelper.Result();
  7. }
复制代码
此时再看回发后的前台显示:
  1. 开始日期:2019/3/21 6:45:44
复制代码


好嘛!刚好差8个小时,逮个正着!

分析问题

可能有人会说了,是不是前台传入的数据有误?其实不是的,打开浏览器调试工具,看下传入的参数:
  1. 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 类型:



解决问题

其实这个时间对象也没问题,只不过它表示的是标准零时区时间,我们只需将其转化为本地时间就可以了,所以正确的代码应该是这样的:
  1. [HttpPost]
  2. [ValidateAntiForgeryToken]
  3. public ActionResult btnSubmit2_Click(JObject values)
  4. {
  5.         UIHelper.Label("labResult").Text("开始日期:" + values.Value<DateTime>("DatePicker1").ToLocalTime().ToString());

  6.         return UIHelper.Result();
  7. }
复制代码


现在前台显示:
  1. 开始日期:2019/3/21 14:48:55
复制代码



还可以将字符串格式化为需要的格式:
  1. UIHelper.Label("labResult").Text("开始日期:" + values.Value<DateTime>("DatePicker1").ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss"));
复制代码



此时前台显示:
  1. 开始日期:2019-03-21 14:48:55
复制代码


延伸问题

还有观众说了,JSON.NET的这个自动转化我不需要,能不能直接拿到这个字符串,然后我自己通过 DateTime.Parse 来转换呢?

我在网上搜索了一下,发现如下两个解决办法,供参考:

办法一:
  1. JsonReader reader = new JsonTextReader(new StringReader(values.ToString()));
  2. reader.DateParseHandling = DateParseHandling.None;
  3. JObject o = JObject.Load(reader);
  4. // 2019/3/21 14:48:55
  5. var result1 = DateTime.Parse(o.Value<string>("DatePicker1")).ToString();
复制代码


办法二:
  1. JsonSerializerSettings settings = new JsonSerializerSettings()
  2. {
  3.         DateParseHandling = DateParseHandling.None
  4. };
  5. JObject j2 = JsonConvert.DeserializeObject<JObject>(values.ToString(), settings);
复制代码


说白了就是告诉 JSON.NET,不要自作主张的帮我把字符串转换为日期对象(DateParseHandling.None),我要取得原始的字符串。

只不过这个路子绕的有点远。



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|FineUI 官方论坛 ( 皖ICP备2021006167号-1 )

GMT+8, 2024-11-21 22:53 , Processed in 0.049234 second(s), 19 queries , Gzip On.

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表