【經驗分享】為什么后台取到的時間和前台差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();
}

 

只不過這個路子繞的有點遠。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM