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

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

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

            //javascript序列化器
            JavaScriptSerializer jss=new JavaScriptSerializer();
           //序列化学生集合对象得到json字符
            string studentsJson=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表达式转换后发到客户端:

using System;
using System.Collections.Generic;
using System.Web;

using System.Web.Script.Serialization;

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

            //使用Select方法重新投影对象集合将Birthday属性转换成一个新的属性
            //注意属性变化后要重新命名,并立即执行
            var studentSet =
                students.Select
                (
                p => new { p.Name, Birthday = p.Birthday.ToString("yyyy-mm-dd") }
                ).ToList();

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

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

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

运行结果:

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

方法二:

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

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>json日期格式处理</title>
    <script src="Scripts/jquery-1.10.2.min.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(function() {
            $.getJSON("getJson.ashx", function (students) {
                $.each(students, function (index, obj) {
                    $("<li/>").html(obj.Name).appendTo("#ulStudents");

                    //使用正则表达式将生日属性中的非数字(\D)删除
                    //并把得到的毫秒数转换成数字类型
                    var birthdayMilliseconds = parseInt(obj.Birthday.replace(/\D/igm, ""));
                    //实例化一个新的日期格式,使用1970 年 1 月 1 日至今的毫秒数为参数
                    var birthday = new Date(birthdayMilliseconds);

                    $("<li/>").html(birthday.toLocaleString()).appendTo("#ulStudents"); ;
                });
            });
        });
    </script>
</head>
<body>
    <h2>json日期格式处理</h2>
    <ul id="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)删除
                    //并把得到的毫秒数转换成数字类型
                    var birthdayMilliseconds = parseInt(obj.Birthday.replace(/\D/igm, ""));
                  //实例化一个新的日期格式,使用1970 年 1 月 1 日至今的毫秒数为参数
                    var birthday = new Date(birthdayMilliseconds);

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

        //在String对象中扩展一个toDate方法,可以根据要求完善
        String.prototype.toDate = function () {
            var dateMilliseconds;
            if (isNaN(this)) {
                //使用正则表达式将日期属性中的非数字(\D)删除
                dateMilliseconds =this.replace(/\D/igm, "");
            } else {
                dateMilliseconds=this;
            }
            //实例化一个新的日期格式,使用1970 年 1 月 1 日至今的毫秒数为参数
            return new Date(parseInt(dateMilliseconds));
        };

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

方法三:

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

1.fastJSON.
2.JSON_checker.
3.Jayrock.

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
    {
        public void ProcessRequest(HttpContext context)
        {
            //设置服务器响应的结果为纯文本格式
            context.Response.ContentType = "text/plain";
            //学生对象集合
            List<Student> students = new List<Student>
            {
                new Student(){Name ="Tom",Birthday =Convert.ToDateTime("2014-01-31 12:12:12")},
                new Student(){Name ="Rose",Birthday =Convert.ToDateTime("2014-01-10 11:12:12")},
                new Student(){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
            {
                return false;
            }
        }
    }
}

运行结果如下:

这时候的日期格式就基本正确了,只要在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");

                    var birthday = new Date(obj.Birthday);
                    $("<li/>").html(birthday.toLocaleString()).appendTo("#ulStudents");
                });
            });
        });

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

方法四:

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

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.Web.Mvc;

namespace JSONDateMVC.Controllers
{
    public class HomeController : Controller
    {
        public JsonResult GetJson1()
        {
            //序列化当前日期与时间对象,并允许客户端Get请求
            return Json(DateTime.Now, JsonRequestBehavior.AllowGet);
        }
    }
}

运行结果:

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

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

Return调用的Json方法:

protected internal JsonResult Json(object data, JsonRequestBehavior behavior)
{
    return this.Json(data, null, null, behavior);
}

this.Json方法

protected internal virtual JsonResult Json(object data, string contentType, Encoding contentEncoding, JsonRequestBehavior behavior)
{
    return new JsonResult { Data = data, ContentType = contentType, ContentEncoding = contentEncoding, JsonRequestBehavior = behavior };
}

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

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

namespace JSONDateMVC.Common
{
    using System;
    using System.Web;

    using System.Web.Mvc;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Converters;

    public class JsonResultPro : JsonResult
    {
        public JsonResultPro(){}
        public JsonResultPro(object data, JsonRequestBehavior behavior)
        {
            base.Data = data;
            base.JsonRequestBehavior = behavior;
            this.DateTimeFormat = "yyyy-MM-dd hh:mm:ss";
        }
        public JsonResultPro(object data, String dateTimeFormat)
        {
            base.Data = data;
            base.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
            this.DateTimeFormat = dateTimeFormat;
        }

        /// <summary>
        /// 日期格式
        /// </summary>
        public string DateTimeFormat{ get; set; }

        public override void ExecuteResult(ControllerContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            if ((this.JsonRequestBehavior == JsonRequestBehavior.DenyGet) && string.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
            {
                throw new InvalidOperationException("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=new IsoDateTimeConverter();
                //设置日期格式
                isoDateTimeConverter.DateTimeFormat = DateTimeFormat;
                //序列化
                String jsonResult = JsonConvert.SerializeObject(this.Data,isoDateTimeConverter);
                //相应结果
                base2.Write(jsonResult);
            }

        }
    }
}

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

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

运行结果:

"2014-02-03 18:10"

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

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

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

转   遗憾的不是java,应该可以借鉴

时间: 2024-10-14 21:14:18

4种解决json日期格式问题的办法的相关文章

json日期格式问题的办法

开发中有时候需要从服务器端返回json格式的数据,在后台代码中如果有DateTime类型的数据使用系统自带的工具类序列化后将得到一个很长的数字表示日期数据,如下所示: //设置服务器响应的结果为纯文本格式 context.Response.ContentType = "text/plain"; //学生对象集合 List<Student> students = new List<Student> { new Student(){Name ="Tom&q

使用newtonjson解决Json日期格式问题

使用Json.Net代替最简单的方法就是使用下面的JsonNetResult 来作为 ActionResult返回. 但是比较麻烦,还有很多其他方法.下面使用我研究的最没有"侵入性"的方法(什么是"侵入性"? 引入这个技术对系统的改动量),知道原理.会照着配置即可,不用记住. 下面这种做法是体现了"一夫当关万夫莫开"的AOP的思想. 1) Install-Package newtonsoft.json 2) 创建一个JsonNetResult继承

JAVA中json日期格式问题的办法

package cn.jbit.BookSys.util; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import net.sf.json.JsonConfig; import net.sf.json.processors.JsonValueProcessor; public class JsonDateValueProcessor implements JsonValue

Java与C#间json日期格式互转完美解决方案

http://blog.csdn.net/wilsonke/article/details/24362851 作用一种简单方便的数据传输方案,JSON已经成为替代XML的事实标准.然而在JSON中,时间(DateTime,Timestamp,Date等)格式一直没有很好地统一,当需要跨平台序列化/反序列化时,遇到不少麻烦.作者经过反复尝试,解决了C#与Java通过JSON进行时间传输的困难.C#解析Java/Javascript生成的JSON并不困难,但Java解析C#生成的JSON困难重重.下

Newtonsoft post Json 日期格式处理

 Newtonsoft.Json.Converters.IsoDateTimeConverter DateTimeConverter = new Newtonsoft.Json.Converters.IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd hh:mm:ss" };            ApiUrl += "?action=" + Action;            string PostJson =

针对两种不同的日期格式进行转成年月日时分秒的格式

有两个时间字符串,格式分别是 string dateEnglish = "1-6-14 8:25";//格式为 月-日-年 string dateFranch = "13-1-14 13:56"; //格式为 日-月-年 IFormatProvider cultureE = new System.Globalization.CultureInfo("en-us", true); DateTime dt = DateTime.Parse(dateE

JSON 日期格式带 T 问题

var iso = new IsoDateTimeConverter(); iso.DateTimeFormat = "yyyy-MM-dd"; object obj = new object(); JsonConvert.SerializeObject(obj, iso); var iso = new Newtonsoft.Json.Converters.IsoDateTimeConverter(); iso.DateTimeFormat = "yyyy-MM-dd HH:

用JS将json日期格式化成正常日期

   function ChangeDateFormat(cellval) {             var date = new Date(parseInt(cellval.replace("/Date(", "").replace(")/", ""), 10));             var month = date.getMonth() + 1 < 10 ? "0" + (date.get

Json日期格式 转化为 YYYY-MM-DD-hh-mm-ss

function timeStamp2String(time) { var datetime = new Date(); datetime.setTime(time); var year = datetime.getFullYear(); var month = datetime.getMonth() + 1 < 10 ? "0" + (datetime.getMonth() + 1) : datetime.getMonth() + 1; var date = datetime.