簡體   English   中英

ASP.NET MVC JsonResult 日期格式

[英]ASP.NET MVC JsonResult Date Format

我有一個控制器動作,它有效地簡單地返回我的模型的 JsonResult。 所以,在我的方法中,我有如下內容:

return new JsonResult(myModel);

這很有效,除了一個問題。 模型中有一個日期屬性,這似乎在 Json 結果中返回,如下所示:

"\/Date(1239018869048)\/"

我應該如何處理日期以便它們以我需要的格式返回? 或者我如何在腳本中處理上面的這種格式?

只是為了擴展casperOne 的答案

JSON 規范不考慮日期值。 MS 不得不打電話,他們選擇的路徑是利用 javascript 字符串表示中的一個小技巧:字符串文字“/”與“\\/”相同,並且字符串文字永遠不會被序列化為“ \\/”(甚至“\\/”也必須映射到“\\\\/”)。

請參閱http://msdn.microsoft.com/en-us/library/bb299886.aspx#intro_to_json_topic2以獲得更好的解釋(向下滾動到“從 JavaScript 文字到 JSON”)

JSON 的痛點之一是缺少日期/時間文字。 許多人在第一次遇到 JSON 時,對了解這一點感到驚訝和失望。 沒有日期/時間字面量的簡單解釋(安慰與否)是 JavaScript 也從未有過:JavaScript 中對日期和時間值的支持完全通過 Date 對象提供。 因此,大多數使用 JSON 作為數據格式的應用程序通常傾向於使用字符串或數字來表示日期和時間值。 如果使用字符串,通常可以期望它采用 ISO 8601 格式。 如果使用數字,則該值通常表示自紀元以來世界協調時間 (UTC) 中的毫秒數,其中紀元定義為 1970 年 1 月 1 日午夜 (UTC)。 同樣,這只是一個約定,而不是 JSON 標准的一部分。 如果您要與另一個應用程序交換數據,則需要查看其文檔以了解它如何在 JSON 文本中編碼日期和時間值。 例如,Microsoft 的 ASP.NET AJAX 不使用上述任何一種約定。 相反,它將 .NET DateTime 值編碼為 JSON 字符串,其中字符串的內容是 /Date(ticks)/ 並且其中 ticks 表示自紀元 (UTC) 以來的毫秒數。 所以 1989 年 11 月 29 日凌晨 4:55:30,在 UTC 中被編碼為“\\/Date(628318530718)\\/”。

一種解決方案是將其解析出來:

value = new Date(parseInt(value.replace("/Date(", "").replace(")/",""), 10));

但是我聽說在某處有一個設置可以讓序列化程序使用new Date(xxx)語法輸出DateTime對象。 我會試着把它挖出來。


JSON.parse()的第二個參數接受一個reviver函數,該函數在返回之前規定了最初產生的值的方式。

這是日期的示例:

var parsed = JSON.parse(data, function(key, value) {
  if (typeof value === 'string') {
    var d = /\/Date\((\d*)\)\//.exec(value);
    return (d) ? new Date(+d[1]) : value;
  }
  return value;
});

查看JSON.parse()的文檔

這是我在 Javascript 中的解決方案 - 非常像 JPot 的,但更短(可能快一點):

value = new Date(parseInt(value.substr(6)));

“value.substr(6)”取出“/Date(”部分,parseInt函數會忽略最后出現的非數字字符。

編輯:我故意省略了基數(parseInt 的第二個參數); 請參閱下面的評論 另外,請注意 ISO-8601 日期優先於這種舊格式——所以這種格式通常不應該用於新的開發。

對於 ISO-8601 格式的 JSON 日期,只需將字符串傳遞給 Date 構造函數:

var date = new Date(jsonDate); //no ugly parsing needed; full timezone support

處理它的客戶端有很多答案,但是如果需要,您可以更改輸出服務器端。

有幾種方法可以解決這個問題,我將從基礎開始。 您必須繼承 JsonResult 類並覆蓋 ExecuteResult 方法。 從那里您可以采用幾種不同的方法來更改序列化。

方法 1:默認實現使用JsonScriptSerializer 如果您查看文檔,您可以使用 RegisterConverters 方法添加自定義JavaScriptConverters 但這有一些問題: JavaScriptConverter 序列化為字典,即它接受一個對象並序列化為 Json 字典。 為了使對象序列化為字符串,它需要一些技巧,請參閱帖子 這個特殊的 hack 也會對字符串進行轉義。

public class CustomJsonResult : JsonResult
{
    private const string _dateFormat = "yyyy-MM-dd HH:mm:ss";

    public override void ExecuteResult(ControllerContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }

        HttpResponseBase response = context.HttpContext.Response;

        if (!String.IsNullOrEmpty(ContentType))
        {
            response.ContentType = ContentType;
        }
        else
        {
            response.ContentType = "application/json";
        }
        if (ContentEncoding != null)
        {
            response.ContentEncoding = ContentEncoding;
        }
        if (Data != null)
        {
            JavaScriptSerializer serializer = new JavaScriptSerializer();

            // Use your custom JavaScriptConverter subclass here.
            serializer.RegisterConverters(new JavascriptConverter[] { new CustomConverter });

            response.Write(serializer.Serialize(Data));
        }
    }
}

方法 2(推薦):第二種方法是從覆蓋的 JsonResult 開始,然后使用另一個 Json 序列化程序,在我的例子中是Json.NET序列化程序。 這不需要方法 1 的技巧。這是我對 JsonResult 子類的實現:

public class CustomJsonResult : JsonResult
{
    private const string _dateFormat = "yyyy-MM-dd HH:mm:ss";

    public override void ExecuteResult(ControllerContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }

        HttpResponseBase response = context.HttpContext.Response;

        if (!String.IsNullOrEmpty(ContentType))
        {
            response.ContentType = ContentType;
        }
        else
        {
            response.ContentType = "application/json";
        }
        if (ContentEncoding != null)
        {
            response.ContentEncoding = ContentEncoding;
        }
        if (Data != null)
        {
            // Using Json.NET serializer
            var isoConvert = new IsoDateTimeConverter();
            isoConvert.DateTimeFormat = _dateFormat;
            response.Write(JsonConvert.SerializeObject(Data, isoConvert));
        }
    }
}

用法示例:

[HttpGet]
public ActionResult Index() {
    return new CustomJsonResult { Data = new { users=db.Users.ToList(); } };
}

附加學分: 詹姆斯·牛頓-金

Moment.js 是一個廣泛的日期時間庫,也支持這一點。 http://momentjs.com/docs/#/parsing/asp-net-json-dates/

例如:時刻(“/日期(1198908717056-0700)/”)

它可能會有所幫助。 plunker 輸出

我發現創建一個新的JsonResult並返回它並不令人滿意 - 必須用return new MyJsonResult { Data = obj }替換所有對return Json(obj)調用是一種痛苦。


所以我想,為什么不直接使用ActionFilter劫持JsonResult

public class JsonNetFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.Result is JsonResult == false)
        {
            return;
        }

        filterContext.Result = new JsonNetResult(
            (JsonResult)filterContext.Result);
    }

    private class JsonNetResult : JsonResult
    {
        public JsonNetResult(JsonResult jsonResult)
        {
            this.ContentEncoding = jsonResult.ContentEncoding;
            this.ContentType = jsonResult.ContentType;
            this.Data = jsonResult.Data;
            this.JsonRequestBehavior = jsonResult.JsonRequestBehavior;
            this.MaxJsonLength = jsonResult.MaxJsonLength;
            this.RecursionLimit = jsonResult.RecursionLimit;
        }

        public override void ExecuteResult(ControllerContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            var isMethodGet = string.Equals(
                context.HttpContext.Request.HttpMethod, 
                "GET", 
                StringComparison.OrdinalIgnoreCase);

            if (this.JsonRequestBehavior == JsonRequestBehavior.DenyGet
                && isMethodGet)
            {
                throw new InvalidOperationException(
                    "GET not allowed! Change JsonRequestBehavior to AllowGet.");
            }

            var response = context.HttpContext.Response;

            response.ContentType = string.IsNullOrEmpty(this.ContentType) 
                ? "application/json" 
                : this.ContentType;

            if (this.ContentEncoding != null)
            {
                response.ContentEncoding = this.ContentEncoding;
            }

            if (this.Data != null)
            {
                response.Write(JsonConvert.SerializeObject(this.Data));
            }
        }
    }
}

這可以應用於任何返回JsonResult以使用 JSON.Net 的方法:

[JsonNetFilter]
public ActionResult GetJson()
{
    return Json(new { hello = new Date(2015, 03, 09) }, JsonRequestBehavior.AllowGet)
}

這將回應

{"hello":"2015-03-09T00:00:00+00:00"}

如預期的!


如果您不介意在每次請求時調用is比較,您可以將其添加到您的FilterConfig

// ...
filters.Add(new JsonNetFilterAttribute());

並且您的所有 JSON 現在都將使用 JSON.Net 而不是內置的JavaScriptSerializer進行序列化。

使用 jQuery 通過$.parseJSON自動轉換日期

注意:這個答案提供了一個 jQuery 擴展,它添加了自動 ISO 和 .net 日期格式支持。

由於您使用的是 Asp.net MVC,我懷疑您在客戶端使用 jQuery。 我建議您閱讀這篇博客文章,其中包含如何使用$.parseJSON為您自動轉換日期的代碼。

代碼支持 Asp.net 格式的日期,如您提到的日期以及 ISO 格式的日期。 所有日期都將使用$.parseJSON()自動為您格式化。

客戶端和服務器之間的 Ajax 通信通常涉及 JSON 格式的數據。 雖然 JSON 適用於字符串、數字和布爾值,但由於 ASP.NET 序列化它們的方式,它可能會給日期帶來一些困難。 由於它沒有任何特殊的日期表示形式,因此它們被序列化為純字符串。 作為解決方案,ASP.NET Web 窗體和 MVC 的默認序列化機制以特殊形式序列化日期 - /Date(ticks)/- 其中 ticks 是自 1970 年 1 月 1 日以來的毫秒數。

這個問題可以通過兩種方式解決:

客戶端

將接收到的日期字符串轉換為數字,並使用日期類的構造函數以刻度為參數創建一個日期對象。

function ToJavaScriptDate(value) {
  var pattern = /Date\(([^)]+)\)/;
  var results = pattern.exec(value);
  var dt = new Date(parseFloat(results[1]));
  return (dt.getMonth() + 1) + "/" + dt.getDate() + "/" + dt.getFullYear();
}

服務器端

前面的解決方案使用客戶端腳本將日期轉換為 JavaScript 日期對象。 您還可以使用服務器端代碼以您選擇的格式序列化 .NET DateTime 實例。 要完成此任務,您需要創建自己的 ActionResult,然后以您想要的方式序列化數據。

參考: http : //www.developer.com/net/dealing-with-json-dates-in-asp.net-mvc.html

我遇到了同樣的問題,我只是在上面使用了 ToString("dd MMM yyyy") 而不是返回實際日期值。 然后在我的 javascript 中,我使用了 new Date(datevalue),其中 datevalue 可能是“2009 年 1 月 1 日”。

看到這個線程:

http://forums.asp.net/p/1038457/1441866.aspx#1441866

基本上,雖然Date()格式是有效的 javascript,但它不是有效的 JSON(有區別)。 如果您想要舊格式,您可能必須創建一個外觀並自己轉換值,或者找到一種方法來獲取JsonResult您的類型的序列化JsonResult並讓它使用自定義日期格式。

不是最優雅的方式,但這對我有用:

var ms = date.substring(6, date.length - 2);
var newDate = formatDate(ms);


function formatDate(ms) {

    var date = new Date(parseInt(ms));
    var hour = date.getHours();
    var mins = date.getMinutes() + '';
    var time = "AM";

    // find time 
    if (hour >= 12) {
        time = "PM";
    }
    // fix hours format
    if (hour > 12) {
        hour -= 12;
    }
    else if (hour == 0) {
        hour = 12;
    }
    // fix minutes format
    if (mins.length == 1) {
        mins = "0" + mins;
    }
    // return formatted date time string
    return date.getMonth() + 1 + "/" + date.getDate() + "/" + date.getFullYear() + " " + hour + ":" + mins + " " + time;
}

在knockoutjs 中處理日期的更好方法是使用moment 庫並像boss 一樣處理日期。 您可以輕松處理 /Date(-62135578800000)/ 之類的日期。 無需擔心您如何在控制器中序列化日期。

function jsonToDate(date,format) {
   return moment(date).format(format);
}

像使用它一樣

var formattedDate = jsonToDate(date,'MM/DD/YYYY')

momentjs支持許多日期時間格式和日期實用程序功能。

我一直在研究這個問題的解決方案,因為上述答案都沒有真正幫助我。 我正在使用 jquery 周歷,需要我的日期在服務器上和頁面本地上有時區信息。 經過一番挖掘,我找到了一個可以幫助其他人的解決方案。

我正在使用 asp.net 3.5、vs 2008、asp.net MVC 2 和 jquery 周歷,

首先,我使用的是 Steven Levithan 編寫的庫,它有助於在客戶端處理日期,即Steven Levithan 的日期庫 isoUtcDateTime 格式非常適合我的需要。 在我的 jquery AJAX 調用中,我使用帶有 isoUtcDateTime 格式的庫提供的格式函數,當 ajax 調用命中我的操作方法時,日期時間種類設置為本地並反映服務器時間。

當我通過 AJAX 將日期發送到我的頁面時,我通過使用“ddd, dd MMM yyyy HH':'mm':'ss 'GMT'zzzz”格式化日期將它們作為文本字符串發送。 這種格式很容易轉換客戶端使用

var myDate = new Date(myReceivedDate);

這是我的完整解決方案減去 Steve Levithan 的源代碼,您可以下載:

控制器:

public class HomeController : Controller
{
    public const string DATE_FORMAT = "ddd, dd MMM yyyy HH':'mm':'ss 'GMT'zzzz";

    public ActionResult Index()
    {
        ViewData["Message"] = "Welcome to ASP.NET MVC!";

        return View();
    }

    public ActionResult About()
    {
        return View();
    }


    public JsonResult GetData()
    {
        DateTime myDate = DateTime.Now.ToLocalTime();

        return new JsonResult { Data = new { myDate = myDate.ToString(DATE_FORMAT) } };
    }

    public JsonResult ReceiveData(DateTime myDate)
    {
        return new JsonResult { Data = new { myDate = myDate.ToString(DATE_FORMAT) } };
    }
}

Javascript:

<script type="text/javascript">

function getData() {
    $.ajax({
        url: "/Home/GetData",
        type: "POST",
        cache: "false",
        dataType: "json",
        success: function(data) {
            alert(data.myDate);
            var newDate = cleanDate(data.myDate);
            alert(newDate);
            sendData(newDate);
        }
    });
} 

function cleanDate(d) {
    if (typeof d == 'string') {
        return new Date(d) || Date.parse(d) || new Date(parseInt(d));
    }
    if (typeof d == 'number') {
        return new Date(d);
    }
    return d;
}

function sendData(newDate) {
    $.ajax({
        url: "/Home/ReceiveData",
        type: "POST",
        cache: "false",
        dataType: "json",
        data:
        {
            myDate: newDate.format("isoUtcDateTime")
        },
        success: function(data) {
            alert(data.myDate);
            var newDate = cleanDate(data.myDate);
            alert(newDate);
        }
    });
}

// bind myButton click event to call getData
$(document).ready(function() {
    $('input#myButton').bind('click', getData);
});
</script>

我希望這個簡單的例子可以幫助我遇到相同情況的其他人。此時它似乎與 Microsoft JSON 序列化一起工作得很好,並保持我的日期跨時區正確。

這是我編寫的一些 JavaScript 代碼,它根據從 ASP.NET MVC 傳遞的日期設置<input type="date">值。

var setDate = function(id, d) {
  if (d !== undefined && d !== null) {
    var date = new Date(parseInt(d.replace("/Date(", "").replace(")/", ""), 10));
    var day = ('0' + date.getDate()).slice(-2);
    var month = ('0' + (date.getMonth() + 1)).slice(-2);
    var parsedDate = date.getFullYear() + "-" + (month) + "-" + (day);
    $(id).val(parsedDate);
  }
};

你像這樣調用這個函數:

setDate('#productCommissionStartDate', data.commissionStartDate);

其中commissionStartDate是MVC 傳遞的JSON 日期。

您可以使用此方法:

String.prototype.jsonToDate = function(){
    try{
        var date;
        eval(("date = new " + this).replace(/\//g,''));
        return date;
    } 
    catch(e){
        return new Date(0);
    }
};

格式化查詢中的日期。

var _myModel = from _m in model.ModelSearch(word)
    select new { date = ((DateTime)_m.Date).ToShortDateString() };

此解決方案的唯一問題是,如果任何日期值為空,您將不會得到任何結果。 為了解決這個問題,您可以在選擇忽略日期空值的日期之前在查詢中放置條件語句,或者您可以設置一個查詢以獲取所有結果,然后使用 foreach 循環遍歷所有這些信息並分配一個值在您執行 SELECT new 之前為空的所有日期。

兩者的例子:

var _test = from _t in adc.ItemSearchTest(word)
                        where _t.Date != null
                        select new { date = ((DateTime)_t.Date).ToShortDateString() };

第二個選項完全需要另一個查詢,因此您可以為所有空值分配值。 這和 foreach 循環必須在您選擇值的查詢之前。

var _testA = from _t in adc.ItemSearchTest(word)
                         select _i;

            foreach (var detail in _testA)
            {
                if (detail.Date== null)
                {
                    detail.Date= Convert.ToDateTime("1/1/0001");
                }
            }

只是一個想法,我發現它比所有 javascript 示例都容易。

在您的頁面中添加 jquery ui 插件。

function JsonDateFormate(dateFormate, jsonDateTime) {
    return $.datepicker.formatDate(dateFormate, eval('new ' + jsonDateTime.slice(1, -1)));
};

它返回服務器日期格式。 您需要定義自己的函數。

function jsonDateFormat(jsonDate) {
  // Changed data format;
  return (new Date(parseInt(jsonDate.substr(6)))).format("mm-dd-yyyy / h:MM tt");
};

不是一無是處,但還有另一種方式。 首先,構建您的 LINQ 查詢。 然后,構建枚舉結果的查詢並應用適合您的任何類型的格式。

var query = from t in db.Table select new { t.DateField };
var result = from c in query.AsEnumerable() select new { c.DateField.toString("dd MMM yyy") };

我不得不說,額外的步驟很煩人,但效果很好。

對我有用的是創建一個包含日期屬性作為字符串的視圖模型。 從域模型分配 DateTime 屬性並在將值分配給視圖模型的同時調用日期屬性上的 .ToString() 。

來自 MVC 操作方法的 JSON 結果將以與視圖兼容的格式返回日期。

查看模型

public class TransactionsViewModel
{
    public string DateInitiated { get; set; }
    public string DateCompleted { get; set; }
}

領域模型

public class Transaction{
   public DateTime? DateInitiated {get; set;}
   public DateTime? DateCompleted {get; set;}
}

控制器動作方法

public JsonResult GetTransactions(){

var transactions = _transactionsRepository.All;
        var model = new List<TransactionsViewModel>();

        foreach (var transaction in transactions)
        {
            var item = new TransactionsViewModel
            {
                ...............
                DateInitiated = transaction.DateInitiated.ToString(),
                DateCompleted = transaction.DateCompleted.ToString(),
            };

            model.Add(item);
        }
        return Json(model, JsonRequestBehavior.AllowGet);
}

覆蓋控制器 Json/JsonResult 以返回 JSON.Net:

這是一種享受

煩人,不是嗎?

我的解決方案是更改我的 WCF 服務,使其以更具可讀性(非 Microsoft)的格式返回 DateTimes。 請注意下面的“ UpdateDateOriginal ”,它是 WCF 的默認日期格式,以及我的“ UpdateDate ”,它的格式設置為更具可讀性。

在此處輸入圖片說明

這是如何做到的:

更改 WCF 日期格式

希望這可以幫助。

我發現這是更改服務器端的最簡單方法。

using System.Collections.Generic;
using System.Web.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;

namespace Website
{
    /// <summary>
    /// This is like MVC5's JsonResult but it uses CamelCase and date formatting.
    /// </summary>
    public class MyJsonResult : ContentResult
    {
        private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver(),
            Converters = new List<JsonConverter> { new StringEnumConverter() }
        };

        public FindersJsonResult(object obj)
        {
            this.Content = JsonConvert.SerializeObject(obj, Settings);
            this.ContentType = "application/json";
        }
    }
}

我遇到了許多關於 JSON 日期的問題,並決定通過解決 SQL 中的日期問題來解決這個問題。 將日期格式更改為字符串格式

select flddate from tblName

select flddate, convert(varchar(12), flddate, 113) as fldDateStr from tblName

通過使用 fldDateStr 問題消失了,我仍然可以使用日期字段進行排序或其他目的。

0

在你的 cshtml 中,

<tr ng-repeat="value in Results">                
 <td>{{value.FileReceivedOn | mydate | date : 'dd-MM-yyyy'}} </td>
</tr>

在你的 JS 文件中,也許是 app.js,

在 app.controller 之外,添加以下過濾器。

這里的“mydate”是您調用的用於解析日期的函數。 這里的“app”是包含 angular.module 的變量

app.filter("mydate", function () {
    var re = /\/Date\(([0-9]*)\)\//;
    return function (x) {
        var m = x.match(re);
        if (m) return new Date(parseInt(m[1]));
        else return null;
    };
});

最簡單的一種:

var milisegundos = parseInt(data.replace("/Date(", "").replace(")/", ""));
var newDate = new Date(milisegundos)。 toLocaleDateString ("en-UE");

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM