ASP.NET MVC JsonResult日期格式

Jon*_*way 237 javascript asp.net-mvc json

我有一个控制器动作,有效地简单地返回我的模型的JsonResult.所以,在我的方法中,我有类似以下内容:

return new JsonResult(myModel);
Run Code Online (Sandbox Code Playgroud)

除了一个问题外,这很有效.模型中有一个日期属性,这似乎在Json结果中返回,如下所示:

"\/Date(1239018869048)\/"
Run Code Online (Sandbox Code Playgroud)

我应该如何处理日期,以便以我要求的格式退回?或者如何在脚本中处理上述格式?

JPo*_*Pot 189

只是为了扩展casperOne的答案.

JSON规范并不考虑日期值.MS必须进行调用,他们选择的路径是在字符串的javascript表示中利用一个小技巧:字符串文字"/"与"\ /"相同,字符串文字永远不会被序列化为"\/"(偶数"\ /"必须映射到"\\ /").

有关更好的解释,请参阅http://msdn.microsoft.com/en-us/library/bb299886.aspx#intro_to_json_topic2(向下滚动到"从JavaScript Literals到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));
Run Code Online (Sandbox Code Playgroud)

但是我听说有一个设置可以让序列化器用语法输出DateTime对象new Date(xxx).我会试着去解决这个问题.


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;
});
Run Code Online (Sandbox Code Playgroud)

查看JSON.parse()的文档

  • 你可以将js缩短为新的日期(parseInt(dateString.replace(/\/ Date \\((\ d +)\\)\ // gi,"$ 1"))) (6认同)
  • 实际上正则表达式更正确为替换(/\/ Date \\(( - ?\ d +)\\)\ // gi,"$ 1")因为日期也可以表示为-ve数字 (6认同)

Roy*_*ker 95

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

value = new Date(parseInt(value.substr(6)));
Run Code Online (Sandbox Code Playgroud)

"value.substr(6)"取出"/ Date("部分,而parseInt函数忽略最后出现的非数字字符.

编辑:我故意遗漏了基数(第二个参数为parseInt); 请参阅下面的评论.此外,请注意ISO-8601日期优先于此旧格式 - 因此这种格式通常不应用于新开发.请参阅优秀的Json.NET库,以获得使用ISO-8601格式序列化日期的绝佳选择.

对于ISO-8601格式的JSON日期,只需将字符串传递给Date构造函数:

var date = new Date(jsonDate); //no ugly parsing needed; full timezone support
Run Code Online (Sandbox Code Playgroud)

  • 使用parseInt时,应始终指定基数.[来源]:https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/parseInt (7认同)
  • @JohnZabroski:每条规则都有例外..NET date serializer _never_返回带有前导零的整数,因此我们可以安全地省略基数. (6认同)
  • 我们几乎有同样的事情.我们使用`value.substr(6,13)`来删除其他非数字字符.但是如果你这样做,那么所有的日期都将在2017年4月26日之前无效!我们不知道`parseInt`会忽略非数字字符.谢谢! (3认同)
  • @JohnZabroski—`parseInt` 应该忽略 [*ECMAScript ed 5*](http://ecma-international.org/ecma-262/6.0/index.html#sec-parseint-string-radix) (2011) 的前导零)。 (2认同)

Per*_*ave 64

处理客户端方面有很多答案,但如果需要,可以更改输出服务器端.

有几种方法可以解决这个问题,我将从基础知识开始.您必须继承JsonResult类并重写ExecuteResult方法.从那里,您可以采取一些不同的方法来更改序列化.

方法1: 默认实现使用JsonScriptSerializer.如果您查看文档,可以使用RegisterConverters方法添加自定义JavaScriptConverters.但是有一些问题:JavaScriptConverter序列化为字典,即它需要一个对象并序列化为Json字典.为了使对象序列化为字符串,它需要一些hackery,请参阅post.这个特殊的黑客也将逃脱字符串.

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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

方法2(推荐): 第二种方法是从重写的JsonResult开始,然后使用另一个Json序列化程序,在我的例子中是Json.NET序列化程序.这不需要方法1的hackery.这是我对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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

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

额外学分: James Newton-King

  • 如果您使用这些方法中的任何一种,则需要进行一次更正 - 第一行应该是:private const string _dateFormat ="yyyy-MM-ddTHH:mm:ss"; 我加了"T". (2认同)

Eri*_*ric 31

Moment.js是一个广泛的日期时间库,也支持这一点.http://momentjs.com/docs/#/parsing/asp-net-json-dates/

ex:moment("/ Date(1198908717056-0700)/")

它可能有所帮助.plunker输出


Rob*_*nik 19

使用jQuery自动转换日期 $.parseJSON

注意:此答案提供了一个jQuery扩展,它添加了自动ISO和.net日期格式支持.

由于您使用的是Asp.net MVC,我怀疑您在客户端使用jQuery.我建议你阅读这篇博文,里面有代码如何用来$.parseJSON为你自动转换日期.

代码支持Asp.net格式的日期,如您提到的日期以及ISO格式的日期.所有日期都将自动为您格式化$.parseJSON().

  • 起初我认为这种方法非常有效.(请参阅文章末尾有关如何在$ .ajaxSetup()中注册转换器的注释)但是,这个解决方案的一大缺点是它不支持Epoc(1970)之前的日期.....所以现在我已经决定放弃.asmx文件并切换到更好地格式化日期的WebAPI(使用JSON.NET)并将避免所有这些麻烦. (2认同)

dav*_*v_i 19

我发现创建一个新的JsonResult并且不能令人满意的返回 - 必须替换所有调用return Json(obj)with return new MyJsonResult { Data = obj }是一种痛苦.


所以我想,为什么不只是劫持JsonResult使用ActionFilter:

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));
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这可以应用于任何返回JsonResult使用JSON.Net的方法:

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

会回应

{"hello":"2015-03-09T00:00:00+00:00"}
Run Code Online (Sandbox Code Playgroud)

如预期的!


如果您不介意is在每个请求中调用比较,您可以将其添加到FilterConfig:

// ...
filters.Add(new JsonNetFilterAttribute());
Run Code Online (Sandbox Code Playgroud)

现在,所有JSON都将使用JSON.Net而不是内置序列化JavaScriptSerializer.


Mis*_*cha 11

客户端和服务器之间的Ajax通信通常涉及JSON格式的数据.虽然JSON适用于字符串,数字和布尔值,但由于ASP.NET序列化它们的方式,它可能会给日期带来一些困难.由于它没有任何特殊的日期表示,因此它们被序列化为纯字符串.作为一种解决方案,ASP.NET Web Forms和MVC的默认序列化机制以特殊形式序列化日期 - /Date(ticks)/ - 其中ticks是自1970年1月1日以来的毫秒数.

这个问题可以通过两种方式解决:

客户端

将接收的日期字符串转换为数字,并使用日期类的构造函数创建日期对象,并将ticks作为参数.

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();
Run Code Online (Sandbox Code Playgroud)

}

服务器端

以前的解决方案使用客户端脚本将日期转换为JavaScript Date对象.您还可以使用以您选择的格式序列化.NET DateTime实例的服务器端代码.要完成此任务,您需要创建自己的ActionResult,然后按照您希望的方式序列化数据.

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


Joe*_*Joe 7

我有同样的问题,而不是返回实际的日期值,我只使用了ToString("dd MMM yyyy").然后在我的javascript中我使用了新的Date(datevalue),其中datevalue可能是"2009年1月1日".