zoukankan      html  css  js  c++  java
  • 【经验分享】为什么后台取到的时间和前台差8个小时?

    发现问题

    单元格编辑时,你可能会遇到前台传入的时间,后台通过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();
    }

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

  • 相关阅读:
    Java
    数据同步方案(附Java源码)
    windows下强大的wmic命令行工具
    利用dokan作虚拟磁盘开发
    用apache配置多个tomcat webapp
    apache2.2+tomcat配置[转]
    tomcat webdav
    Modbus/TCP
    AI语音验证码识别
    Win10 重命名文件夹:找不到指定文件。
  • 原文地址:https://www.cnblogs.com/sanshi/p/10572060.html
Copyright © 2011-2022 走看看