我在保险领域的客户需要潜在被保险人的出生日期。它使用 jQuery datepicker 输入到 Web 表单中,使用 Knockout 连接到模型属性,并通过 JSON 中的 ajax 发送到 MVC 4 控制器。
一些投保人收到的保险文件中出生日期错误。在随后的调查中,我们发现除了数据录入错误极少外,错误日期还集中在以下两个时期:
- 三月的最后三周到四月初
- 十月的最后一周到十一月的第一周。
由于我们的客户在美国/蒙特利尔时区,我立即想到了 DST 的问题。DST 规则在 2007 年在这个时区发生了变化。
阅读了几篇文章和其他 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
。网 :
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。