4种解决json日期格式问题的办法

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

开发中有时候需要从服务器端返回json格式的数据,在后台代码中如果有DateTime类型的数据使用系统自带的工具类序列化后将得到一个很长的数字表示日期数据,如下所示:

//设置服务器响应的结果为纯文本格式context.Response.ContentType ="text/plain";//学生对象集合List<Student> students =newList<Student>{newStudent(){Name ="Tom",

Birthday=Convert.ToDateTime("2014-01-31 12:12:12")},newStudent(){Name ="Rose",

Birthday=Convert.ToDateTime("2014-01-10 11:12:12")},newStudent(){Name ="Mark",

Birthday=Convert.ToDateTime("2014-01-09 10:12:12")}

};//javascript序列化器JavascriptSerializer jss=newJavaScriptSerializer();//序列化学生集合对象得到json字符stringstudentsJson=jss.Serialize(students);//将字符串响应到客户端context.Response.Write(studentsJson);

context.Response.End();

运行结果是:

其中Tom所对应生日“2014-01-31”变成了1391141532000,这其实是1970 年 1 月 1 日至今的毫秒数;1391141532000/1000/60/60/24/365=44.11年,44+1970=2014年,按这种方法可以得出年月日时分秒和毫秒。这种格式是一种可行的表示形式但不是普通人可以看懂的友好格式,怎么让这个格式变化?

解决办法:

方法1:在服务器端将日期格式使用Select方法或LINQ表达式转换后发到客户端:

usingSystem;usingSystem.Collections.Generic;usingSystem.Web;usingSystem.Web.Script.Serialization;namespaceJsonDate1

{usingSystem.Linq;///<summary>///学生类,测试用///</summary>publicclassStudent

{///<summary>///姓名///</summary>publicString Name {get;set; }///<summary>///生日///</summary>publicDateTime Birthday {get;set; }

}///<summary>///返回学生集合的json字符///</summary>publicclassGetJson : IHttpHandler

{publicvoidPRocessRequest(HttpContext context)

{//设置服务器响应的结果为纯文本格式context.Response.ContentType ="text/plain";//学生对象集合List<Student> students =newList<Student>{newStudent(){Name ="Tom",Birthday =Convert.ToDateTime("2014-01-31 12:12:12")},newStudent(){Name ="Rose",Birthday =Convert.ToDateTime("2014-01-10 11:12:12")},newStudent(){Name ="Mark",Birthday =Convert.ToDateTime("2014-01-09 10:12:12")}

};//使用Select方法重新投影对象集合将Birthday属性转换成一个新的属性//注意属性变化后要重新命名,并立即执行varstudentSet =students.Select

(

p=>new{ p.Name, Birthday = p.Birthday.ToString("yyyy-mm-dd") }

).ToList();//javascript序列化器JavaScriptSerializer jss =newJavaScriptSerializer();//序列化学生集合对象得到json字符stringstudentsJson =jss.Serialize(studentSet);//将字符串响应到客户端context.Response.Write(studentsJson);

context.Response.End();

}publicboolIsReusable

{get{returnfalse;

}

}

}

}

Select方法重新投影对象集合将Birthday属性转换成一个新的属性,注意属性变化后要重新命名,属性名可以相同;这里可以使用select方法也可以使用LINQ查询表达式,也可以选择别的方式达到相同的目的;这种办法可以将集合中客户端不用的属性剔除,达到简单优化性能的目的。

运行结果:

这时候的日期格式就已经变成友好格式了,不过在javascript中这只是一个字符串。

方法二:

在javascript中将"Birthday":"\/Date(1391141532000)\/"中的字符串转换成javascript中的日期对象,可以将Birthday这个Key所对应的Value中的非数字字符以替换的方式删除,到到一个数字1391141532000,然后实例化一个Date对象,将1391141532000毫秒作为参数,得到一个javascript中的日期对象,代码如下:

<!DOCTYPE html><htmlxmlns="http://www.w3.org/1999/xhtml"><head><title>json日期格式处理</title><scriptsrc="Scripts/jquery-1.10.2.min.js"type="text/javascript"></script><scripttype="text/javascript">$(function() {

$.getJSON("getJson.ashx",function(students) {

$.each(students,function(index, obj) {

$("<li/>").html(obj.Name).appendTo("#ulStudents");//使用正则表达式将生日属性中的非数字(\D)删除//并把得到的毫秒数转换成数字类型varbirthdayMilliseconds=parseInt(obj.Birthday.replace(/\D/igm,""));//实例化一个新的日期格式,使用1970 年 1 月 1 日至今的毫秒数为参数varbirthday=newDate(birthdayMilliseconds);

$("<li/>").html(birthday.toLocaleString()).appendTo("#ulStudents"); ;

});

});

});</script></head><body><h2>json日期格式处理</h2><ulid="ulStudents"></ul></body></html>

运行结果:

上的使用正则/\D/igm达到替换所有非数字的目的,\D表示非数字,igm是参数,分别表示忽视(ignore)大小写;多次、全局(global)替换;多行替换(multi-line);有一些时候还会出现+86的情况,只需要变换正则同样可以达到目的。另外如果项目中反复出现这种需要处理日期格式的问题,可以扩展一个javascript方法,代码如下:

$(function() {

$.getJSON("getJson.ashx",function(students) {

$.each(students,function(index, obj) {

$("<li/>").html(obj.Name).appendTo("#ulStudents");//使用正则表达式将生日属性中的非数字(\D)删除//并把得到的毫秒数转换成数字类型varbirthdayMilliseconds = parseInt(obj.Birthday.replace(/\D/igm, ""));//实例化一个新的日期格式,使用1970 年 1 月 1 日至今的毫秒数为参数varbirthday =newDate(birthdayMilliseconds);

$("<li/>").html(birthday.toLocaleString()).appendTo("#ulStudents");

$("<li/>").html(obj.Birthday.toDate()).appendTo("#ulStudents");

});

});

});//在String对象中扩展一个toDate方法,可以根据要求完善String.prototype.toDate =function() {vardateMilliseconds;if(isNaN(this)) {//使用正则表达式将日期属性中的非数字(\D)删除dateMilliseconds =this.replace(/\D/igm, "");

}else{

dateMilliseconds=this;

}//实例化一个新的日期格式,使用1970 年 1 月 1 日至今的毫秒数为参数returnnewDate(parseInt(dateMilliseconds));

};

上面扩展的方法toDate不一定合理,也不够强大,可以根据需要修改。

方法三:

可以选择一些第三方的json工具类,其中不乏有一些已经对日期格式问题已处理好了的,常见的json序列化与反序列化工具库有:

1.fastJSON.

2.JSON_checker.

3.Jayrock.

4.Json.NET - LINQ to JSON.

5.LitJSON.

6.JSON for .NET.

7.JsonFx.

8.JSONSharp.

9.JsonExSerializer.

10.fluent-json

11.Manatee Json

这里以litjson为序列化与反序列化json的工具类作示例,代码如下:

using System;

using System.Collections.Generic;

using System.Web;

using LitJson;

namespace JsonDate2

{

using System.Linq;/// <summary>/// 学生类,测试用/// </summary>public class Student

{/// <summary>/// 姓名/// </summary>public String Name { get; set; }/// <summary>/// 生日/// </summary>public DateTime Birthday { get; set; }

}/// <summary>/// 返回学生集合的json字符/// </summary>public class GetJson : IHttpHandler

{

publicvoidProcessRequest(HttpContext context)

{//设置服务器响应的结果为纯文本格式context.Response.ContentType = "text/plain";//学生对象集合List<Student> students =newList<Student>{newStudent(){Name ="Tom",Birthday =Convert.ToDateTime("2014-01-31 12:12:12")},newStudent(){Name ="Rose",Birthday =Convert.ToDateTime("2014-01-10 11:12:12")},newStudent(){Name ="Mark",Birthday =Convert.ToDateTime("2014-01-09 10:12:12")}

};//序列化学生集合对象得到json字符string studentsJson =JsonMapper.ToJson(students);//将字符串响应到客户端context.Response.Write(studentsJson);

context.Response.End();

}

public bool IsReusable

{

get

{returnfalse;

}

}

}

}

运行结果如下:

这时候的日期格式就基本正确了,只要在javascript中直接实例化日期就好了,

var date = new Date("01/31/2014 12:12:12");

alert(date.toLocaleString());

客户端的代码如下:

$(function() {

$.getJSON("GetJson2.ashx",function(students) {

$.each(students,function(index, obj) {

$("<li/>").html(obj.Name).appendTo("#ulStudents");varbirthday =newDate(obj.Birthday);

$("<li/>").html(birthday.toLocaleString()).appendTo("#ulStudents");

});

});

});vardate =newDate("01/31/2014 12:12:12");

alert(date.toLocaleString());

方法四:

这点文字发到博客上有网友提出了他们宝贵的意见,我并没有考虑在MVC中的情况,其实MVC中也可以使用handler,所以区别不是很大了,但MVC中有专门针对服务器响应为JSON的Action,代码如下:

usingSystem;usingSystem.Web.Mvc;namespaceJSONDateMVC.Controllers

{publicclassHomeController : Controller

{publicJsonResult GetJson1()

{//序列化当前日期与时间对象,并允许客户端Get请求returnJson(DateTime.Now, JsonRequestBehavior.AllowGet);

}

}

}

运行结果:

下载一个内容为application/json的文件,文件名为GetJson1,内容是"\/Date(1391418272884)\/"

从上面的情况看来MVC中序列化时并未对日期格式特别处理,我们可以反编译看源码:

Return调用的Json方法:

protectedinternalJsonResult Json(objectdata, JsonRequestBehavior behavior)

{returnthis.Json(data,null,null, behavior);

}

this.Json方法

protectedinternalvirtualJsonResult Json(objectdata,stringcontentType, Encoding contentEncoding, JsonRequestBehavior behavior)

{returnnewJsonResult { Data = data, ContentType = contentType, ContentEncoding = contentEncoding, JsonRequestBehavior =behavior };

}

JsonResult类ActionResult类的子类,ExecuteResult方法:

从上面的代码中不难看出微软的JsonResult类仍然是使用了JavaScriptSerializer,所以返回的结果与方法一未处理时是一样的,要解决这个问题我们可以派生出一个新的类,重写ExecuteResult方法,使用Json.net来完成序列化工作,JsonResultPro.cs文件的代码如下:

namespaceJSONDateMVC.Common

{usingSystem;usingSystem.Web;usingSystem.Web.Mvc;usingNewtonsoft.Json;usingNewtonsoft.Json.Converters;publicclassJsonResultPro : JsonResult

{publicJsonResultPro(){}publicJsonResultPro(objectdata, JsonRequestBehavior behavior)

{base.Data =data;base.JsonRequestBehavior =behavior;this.DateTimeFormat ="yyyy-MM-dd hh:mm:ss";

}publicJsonResultPro(objectdata, String dateTimeFormat)

{base.Data =data;base.JsonRequestBehavior =JsonRequestBehavior.AllowGet;this.DateTimeFormat =dateTimeFormat;

}///<summary>///日期格式///</summary>publicstringDateTimeFormat{get;set; }publicoverridevoidExecuteResult(ControllerContext context)

{if(context ==null)

{thrownewArgumentNullException("context");

}if((this.JsonRequestBehavior == JsonRequestBehavior.DenyGet) &&string.Equals(context.HttpContext.Request.HttpMethod,"GET", StringComparison.OrdinalIgnoreCase))

{thrownewInvalidOperationException("MvcResources.JsonRequest_GetNotAllowed");

}

HttpResponseBase base2=context.HttpContext.Response;if(!string.IsNullOrEmpty(this.ContentType))

{

base2.ContentType=this.ContentType;

}else{

base2.ContentType="application/json";

}if(this.ContentEncoding !=null)

{

base2.ContentEncoding=this.ContentEncoding;

}if(this.Data !=null)

{//转换System.DateTime的日期格式到 ISO 8601日期格式//ISO 8601 (如2008-04-12T12:53Z)IsoDateTimeConverter isoDateTimeConverter=newIsoDateTimeConverter();//设置日期格式isoDateTimeConverter.DateTimeFormat =DateTimeFormat;//序列化String jsonResult = JsonConvert.SerializeObject(this.Data,isoDateTimeConverter);//相应结果base2.Write(jsonResult);

}

}

}

}

使用上面的JsonResultPro Action类型的代码如下:

publicJsonResultPro GetJson2()

{//序列化当前日期与时间对象,并允许客户端Get请求,注意H是大写returnnewJsonResultPro(DateTime.Now,"yyyy-MM-dd HH:mm");

}

运行结果:

"2014-02-03 18:10"

这样就可以完全按自己的意思来设置日期格式了,但需要注意日期格式如平时的Format是有区别的,如这里表示时间的H如果大写表示24小时制,如果小写表示12小时制。另外还有几个问题要问大家:

1、通过Reflector反编译得到的代码中有很多变化,如属性会变成get_Request()方法的形式,不知道大家有没有更好的方法。

2、在反编译得到的代码中使用到了资源文件MvcResources.JsonRequest_GetNotAllowed,怎么在重写时也可以使用?

这里讲到了几种解决json中序列化后的日期格式问题,应该还有更好更完善的方法,欢迎您告诉我。因为有很多学生问我所以我写了这点文字,欢迎批评指正。

示例代码下载

MVC示例代码下载

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航