我有一个控制器操作,实际上只返回我的模型的JsonResult。 所以,在我的方法中,我有以下内容:
return new JsonResult(myModel);
这个方法很好用,但是存在一个问题。模型中有一个日期属性,在Json结果中会以如下方式返回:
"\/Date(1239018869048)\/"
我该如何处理日期,以便以所需的格式返回?或者说,在脚本中如何处理上述格式?
我有一个控制器操作,实际上只返回我的模型的JsonResult。 所以,在我的方法中,我有以下内容:
return new JsonResult(myModel);
这个方法很好用,但是存在一个问题。模型中有一个日期属性,在Json结果中会以如下方式返回:
"\/Date(1239018869048)\/"
我该如何处理日期,以便以所需的格式返回?或者说,在脚本中如何处理上述格式?
在casperOne的回答上进行扩展。
JSON规范没有考虑到日期格式值。微软不得不做出决策,他们选择的方法是利用javascript字符串表示中的一个小技巧:字符串文字“ /”与“ \ /”相同,而且字符串文字永远不会被序列化为“ /”(甚至“ \/”也必须映射为“ \ / \”)。
请参见http://msdn.microsoft.com/en-us/library/bb299886.aspx#intro_to_json_topic2以了解更好的解释(向下滚动到“从JavaScript文字到JSON”)。
JSON中的一个痛点是缺乏日期/时间字面量。许多人在首次遇到JSON时对此感到惊讶和失望。对于缺少日期/时间字面量的简单解释(无论是否令人宽慰),是JavaScript本身也从未提供过这种值:JavaScript对于日期和时间值的支持完全通过Date对象实现。因此,大多数使用JSON作为数据格式的应用程序通常倾向于使用字符串或数字来表示日期和时间值。如果使用字符串,通常可以期望它以ISO 8601格式表示。相反,如果使用数字,则该值通常被认为是自1970年1月1日午夜(UTC)以来的通用协调时间(UTC)毫秒数, 其中始点被定义为UTC的。再次强调,这只是一个约定,而不是JSON标准的一部分。如果您正在与另一个应用程序交换数据,则需要查看其文档以了解它如何在JSON字面量中编码日期和时间值。例如,微软的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;
});
parseInt()
的第二个参数。它告诉函数在十进制数系统中提取整数。这是一个基数。如果你在那里放入 8
,它将提取一个八进制数。 - AnalogWeapon/\/Date\((-?\d*)\)\//
。 - RobG以下是我的 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
value.substr(6, 13)
来删除其他非数字字符。但是,如果您这样做,所有早于1938年4月26日的日期都将无效!我们不知道 parseInt
会忽略非数字字符。谢谢! - LockTar有很多答案可以在客户端处理它,但如果你愿意,也可以在服务器端更改输出。
有几种方法可以解决这个问题,我会从基础开始介绍。您将需要子类化JsonResult类并重写ExecuteResult方法。从那里,您可以采用一些不同的方法来更改序列化。
方法1: 默认实现使用JsonScriptSerializer。如果您查看文档,可以使用RegisterConverters方法添加自定义JavaScriptConverters。 但是有一些问题:JavaScriptConverter序列化为字典,即它将对象序列化为Json字典。为了使对象序列化为字符串,它需要一些技巧,请参见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));
}
}
}
方法二(推荐): 第二种方法是从重写的JsonResult开始,选择另一个Json序列化器,例如我的选择是Json.NET。这不需要第一种方法中所需的技巧。这是我实现的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(); } };
}
额外鸣谢: James Newton-King
JsonNetResult
类的示例,链接为http://james.newtonking.com/archive/2008/10/16/asp-net-mvc-and-json-net,该示例类似于第二种方法,并提供了完整的JsonSerializerSettings属性访问。 - undefinedMoment.js是一个广泛支持日期时间的库,它也支持这个。
http://momentjs.com/docs/#/parsing/asp-net-json-dates/例如:moment("/Date(1198908717056-0700)/")
它可能有所帮助。plunker 输出
moment("json_date_string_value").format('appropriate format');
即可。
您可以在moment.js页面上看到不同的格式值。 - Harshil Shah我发现创建新的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
进行序列化。
$.parseJSON
自动转换日期注意:此答案提供了一个jQuery扩展,添加了自动支持ISO和.NET日期格式。
考虑到您正在使用Asp.net MVC,我猜您在客户端使用jQuery。建议您阅读这篇博客文章,其中有代码说明如何使用$.parseJSON
来自动转换日期。
代码支持像您提到的Asp.net格式化日期以及ISO格式化日期。通过使用$.parseJSON()
,所有日期都将自动为您格式化。
客户端与服务器之间的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();
}
服务器端
之前的解决方案使用客户端脚本将日期转换为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可以是"01 Jan 2009"。
请看这个线程:
http://forums.asp.net/p/1038457/1441866.aspx#1441866
基本上,虽然Date()
格式是有效的JavaScript,但它不是有效的JSON(有区别)。如果您想要旧格式,您可能需要创建一个门面并自己转换值,或找到一种方法来获取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;
}