驳Fish Li 在文章《ASP.NET常被忽视的一些细节》 对.Net JavaScriptSerializer处理DateTime的误解

Fish Li今天发了一篇火爆的《ASP.NET常被忽视的一些细节》,其中有一个地方我认为他大大的冤枉了微软.Net 类库设计人员,你打开链接就直接跳到了重点,先直接粘贴过来引用如下:

Fish Li

DateTime的JSON序列化

在SP.NET3.5中,微软为ASP.NET为设计了一个JSON序列化的工具类, System.Web.Script.Serialization.JavaScriptSerializer,这个类的使用很广泛,而且比WCF的那个JSON序列化类的兼容性要好。 不过,这个类有一个问题,在序列化DataTime类型时,它生成的结果会让所有人感觉别扭, 其实序列化的结果表现形式还个小问题,在前端写个转换函数就能解决, 然而,如果你需要 用序列化和反序列化的方法来做对象的持久化,就会遇到问题,例如下面的代码:

DateTime dt1 = DateTime.Now;
JavaScriptSerializer jss = new JavaScriptSerializer();

string json = jss.Serialize(dt1);
DateTime dt2 = jss.Deserialize<DateTime>(json);

context.Response.Write(dt1 == dt2);

浏览器显示的结果会让人感到很意外,竟然是:False

出现这个原因与JavaScript的时间格式有关,它使用了UTC时间, 不过,这个理由让人感到难以接受,毕竟其它的反序列化都能还原对象,例如二进制序列化和XML都能正确的还原对象。 没办法,这里只能算是个坑了,所以,如果你要做对象的持久化操作,尽量不要选择JSON序列化。

 以上抱怨其实是没有对javascript时间有正确的理解 , 在mozilla开发者网络看了一篇文章, 介绍js Date对象的 , 详情见:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FDate 

截取其中一段对Date对象的描述原文如下: 

Description

If you supply no arguments, the constructor creates a JavaScript Date object for today's date and time according to local time. If you supply some arguments but not others, the missing arguments are set to 0. If you supply any arguments, you must supply at least the year, month, and day. You can omit the hours, minutes, seconds, and milliseconds.

The JavaScript date is measured in milliseconds since midnight 01 January, 1970 UTC. A day holds 86,400,000 milliseconds. The JavaScript Date object range is -100,000,000 days to 100,000,000 days relative to 01 January, 1970 UTC.

The JavaScript Date object provides uniform behavior across platforms.

The JavaScript Date object supports a number of UTC (universal) methods, as well as local time methods. UTC, also known as Greenwich Mean Time (GMT), refers to the time as set by the World Time Standard. The local time is the time known to the computer where JavaScript is executed.

Invoking JavaScript Date in a non-constructor context (i.e., without the new operator) will return a string representing the current time.

黑体部分是重点中的重点,大意是: javascript 日期以1970年1月1日的世界标准时的到现在的毫秒数计量,一天有86400000毫秒, js日期范围是世界标准时1970年1月1日之前的100000000天到其后的100000000天。

下面我们来看看MSDN上微软对JavaScriptSerializer 对象的说明,参见链接:http://msdn.microsoft.com/en-us/library/system.web.script.serialization.javascriptserializer.aspx 

下面是对.net类型和json类型的映射表格的一个截图, 详细见上面链接:

 以上说明了.NET DateTime 转换为JSON格式是以javascript标准日期为基准, 以1970-1-1半夜与当前UTC格式日期相隔的毫秒数为转换结果,这样我们在js中我们可以用Date对象内置函数随意转换为本地格式或其他格式,这样 Fish Li所言的“不过,这个类有一个问题,在序列化DataTime类型时,它生成的结果会让所有人感觉别扭, 其实序列化的结果表现形式还个小问题,在前端写个转换函数就能解决” 就完全不是问题了, 因为根本不需要写什么转换函数,下面是测试代码:

            DateTime now = DateTime.Now;
            Console.WriteLine(now.ToString());

            JavaScriptSerializer js = new JavaScriptSerializer();
            string json = js.Serialize(now);
            Console.WriteLine(json);

 执行结果截图如下:

将JSON字符结果放到javascript中运行如下: 

以上说明其序列化结果表现形式在js环境中完全不是问题, 那在持久化处理中有大问题吗, 还是以Fish Li 的代码来说明: 

DateTime dt1 = DateTime.Now;
JavaScriptSerializer jss = new JavaScriptSerializer();

string json = jss.Serialize(dt1);
DateTime dt2 = jss.Deserialize<DateTime>(json);

context.Response.Write(dt1 == dt2);

浏览器显示的结果会让人感到很意外,竟然是:False   

 其实只要在反序列化时不要忘记转换为本地时,问题就解决了:(因为我们中国在东八区,所以utc时间早了8小时)
 
 
 我回复了 Fish Li, 他回复“你能不能再想远点呢?
你要写的是通用的代码,不仅只处理一个DateTime类型,你不知道哪个类型中有DateTime属性,你打算怎么办?
 
这其实很好解决,如果真要使用本地时间, 应用完全不考虑国际化: 完全可以在含有DateTime成员的类中再加一个String 类型的成员, web界面处理时,只用显示DateTime的String值就可以了, 甚至如完全用一个String类型的DateTime就ok了,再要保存到数据库时再转回DateTime。。 例如:
class Test
    {
        private DateTime date = DateTime.Now;

        /// <summary>
        /// Datetime format Date
        /// </summary>
        public DateTime Date
        {
            get
            {
                return date;
            }
            set
            {
                date = value;
            }
        }

        /// <summary>
        /// String format Date
        /// </summary>
        public String DateString
        {
            get
            {
                return date.ToString();
            }
        }
    }

其实主流的JSON转换函数都是如MS库相同处理,所以我没法想到一个比标准还标准的所谓通用解决方案了  哎, 今天又没多少时间写win8 博客园客户端了 。。 

posted @ 2013-05-29 21:09  记忆的森林  阅读(8922)  评论(87编辑  收藏  举报