【发布时间】:2013-11-13 00:52:17
【问题描述】:
我的客户在保险领域,要求提供潜在被保险人的出生日期。它使用 jQuery 日期选择器输入到 Web 表单中,使用 Knockout 连接到模型属性,并通过 JSON 中的 ajax 发送到 MVC 4 控制器。
一些投保人收到的保险文件中出生日期错误。在随后的调查中,我们发现除了数据录入错误极少外,错误日期还集中在以下两个时期:
- 3 月的最后三周到 4 月初
- 10 月的最后一周到 11 月的第一周。
由于我们的客户在美国/蒙特利尔时区,我立即想到了 DST 的问题。 The DST rules changed in 2007 in this timezone.
阅读了几篇文章和其他 Stack Overflow 问题后,我了解到 ECMAScript 5 标准规定实现必须考虑到当前的 DST 规则,并且不需要尊重 DST 的更改历史。 ES5 15.9.1.8 目前唯一不符合此规范的浏览器是 IE10(稍后会详细介绍)。
鉴于此规范,浏览器将报告日期如下(在 Chrome 中测试):
(new Date(2006, 9, 31, 0, 0, 0)).toISOString()
// 2006-10-31T04:00:00.000Z
(new Date(2008, 9, 31, 0, 0, 0)).toISOString()
// 2008-10-31T04:00:00.000Z
.NET 平台正确报告日期如下:
DateTime dt = new DateTime(2006, 10, 31, 0, 0, 0);
Console.WriteLine("{0:MM/dd/yy H:mm:ss zzz}", dt);
// 10-31-06 0:00:00 -05:00
dt = new DateTime(2008, 10, 31, 0, 0, 0);
Console.WriteLine("{0:MM/dd/yy H:mm:ss zzz}", dt);
// 10-31-08 0:00:00 -04:00
这个问题的一个原因是,如果被保险人出生在 2007 年之前的 10 月最后一周,UTC 时间会错误地报告给我的 MVC 控制器,例如:
Javascript 日期对象:
new DateTime(2006, 9, 31, 0, 0, 0);
.Net 解析 JSON 数据并获取:
10-30-06 23:00:00 GMT
在测试过程中,我发现 JavaScript 中 Date 对象的内部表示与 .Net DateTime 的表示不兼容,并且我无法使用 JavaScript 表示滚动我自己的解析器:
Javascript:
(new Date(2006, 9, 31, 0, 0, 0)).getTime()
// 1162267200000
.Net:
DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(1162267200000);
Console.WriteLine("{0}", dt);
// 2006-10-31 04:00:00
(这是错误的,因为它表示为当地时间 2006 年 10 月 30 日 23:00。)
对于我的客户的用例,由于我感兴趣的是日期部分,我可能只是将 Date 对象的时间部分设置为中午,这样可以保护我免受 JavaScript 部分日期误解的所有情况。不幸的是,这是一个丑陋的补丁,它不能解决其他潜在的情况,例如我的客户希望我们实现一个功能,要求我们知道过去发生的事件的准确日期和时间。
另一种方法是编写一个算法来检测我的控制器中可能存在问题的 DST 周,并在我在相关周内获得日期时设置正确的时间。不幸的是,鉴于 ECMAScript 6 标准规定必须遵守 DST 更改历史记录(因此所有未来的浏览器都应该正确处理这种情况),并且鉴于 IE10 已经正常工作,我担心将来会造成问题.从架构上讲,这种方法似乎也是错误的。
要考虑的另一个方面是,如果我必须将模型从客户端传递到服务器,然后再传回客户端,我将需要有一种方法来重新创建“坏”JavaScript Date 对象,以确保不会影响显示在应用程序的客户端。
似乎没有一种解决方案是正确且可扩展的。我不敢相信以前没有人处理过这个问题。
我怎样才能永久地解决这个问题,并且以一种可以应用于所有其他 JavaScript / MVC 项目的方式?
编辑 #1 - 与问题没有直接关系的附加信息:
正如@matt-johnson 指出的那样,很少有应该使用时区信息的情况。然而,在这种情况下,被保险人的出生日期与我的客户所在的时区有关。让我们以一个住在不列颠哥伦比亚省维多利亚的 17 岁的孩子为例,他的生日是 12 月 2 日。如果他在 12 月 1 日 22:00 提交保险报价,即使他仍然 17 岁,保险报价也会被接受,因为在我客户的时区他已经 18 岁。同样的规则也适用于保险定价。这是法律要求。
为了清楚起见,我正在寻找一个可以应用于任何其他项目的全方位解决方案。具体问题是:Javascript,在 2007 年之前的几个特定周内,报告时间偏移 1 小时。无论我如何表示时间(本地时区或 UTC),这个偏移量始终存在,因为它是错误的基础数据(而不是数据表示)。
我使用“将时间部分设置在中午”的解决方法来规避该错误,但根本问题仍然存在。如果我的客户要求我们开发一个 Web 应用程序,要求我们获取过去特定事件的日期和时间,会发生什么情况?例如:“请说明事故发生的确切日期和时间:2005 年 10 月 31 日 19:32”。 MVC 控制器会将时间设置为 18:32。
【问题讨论】:
-
是否可以从等式中完全删除时区?仅使用 UTC 作为日期/时间?如果您必须跟踪未来的时间,请将它们转换为 UTC 以存储在数据库中以及何时需要处理时间计算,然后在正确的时区处理 UI 显示。
-
好评,@StevenV。这是我的第一个想法,但即使是 UTC 日期也没有在 JavaScript 中正确报告这些日期。问题源于 JS Date 对象中的错误时区偏移,因此在应用于 UTC 表示时它仍然存在。此外,我们必须维护客户的时区,因为公司是全国性的,并且有业务规则要求我们将被保险人的时区与我的客户的时区进行比较。
-
“我们必须维护客户端的时区”,你是指哪个客户端?如果您谈论的是被保险人,您如何获得有关个人的数据?否则,您只是获得浏览器/系统的时区,可以轻松修改/更改。此外,在您的测试中很奇怪,
Date()构造函数中的month参数是从零开始的。 9 月 8 日,10 月 9 日。 -
是的,我指的是保险时区。事实上,它可以改变,但有权访问该平台的经纪人知道这一点。任何欺诈性提交都可能导致诉讼。这不是我要解决的问题。是的,感谢您指出错误。我更正了。
标签: javascript ajax asp.net-mvc json datetime