gpt4 book ai didi

javascript - JavaScript 中的 DST 实现导致发送到 MVC Controller 时出现问题

转载 作者:可可西里 更新时间:2023-11-01 01:34:41 25 4
gpt4 key购买 nike

我的客户在保险领域,需要潜在被保险人的出生日期。它使用 jQuery 日期选择器输入到 Web 表单中,使用 Knockout 连接到模型属性,并通过 JSON 中的 ajax 发送到 MVC 4 Controller 。

一些保单持有人收到的保险文件的出生日期有误。在随后的调查中,我们发现,除了数据录入错误极其轻微外,错误日期还集中在以下两个时期:

  • 三月最后三周到四月初
  • 十月的最后一周到十一月的第一周。

  • 由于我们的客户在美国/蒙特利尔时区,我立即想到了 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 Controller ,例如:

    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 部分日期误解的所有情况。不幸的是,这是一个丑陋的补丁,它不能解决其他潜在的情况,例如如果我的客户希望我们实现一个功能,要求我们获得过去发生的事件的准确日期和时间。

    另一种方法是编写一个算法来检测我的 Controller 中可能有问题的 DST 周,并设置正确的时间,如果我在相关周内得到一个日期。不幸的是,鉴于 ECMAScript 6 标准规定必须遵守 DST 更改历史记录(因此所有 future 的浏览器都应该正确处理这种情况),并且鉴于 IE10 已经正常工作,我担心将来会出现问题.从架构上来说,这种方法似乎也是错误的。

    另一个要考虑的方面是,如果我必须将模型从客户端传递到服务器,然后再传回客户端,我将需要有一种方法来重新创建“坏”的 JavaScript 日期对象,以确保不会影响在应用程序的客户端。

    没有解决方案似乎是正确和可扩展的。我不敢相信以前没有人必须处理过这个问题。

    我怎样才能永久地解决这个问题,并以一种可以应用于所有其他 JavaScript/MVC 项目的方式?

    编辑 #1 - 与问题没有直接关系的附加信息:

    正如@matt-johnson 指出的那样,很少有应该使用时区信息的情况。但是,在这种情况下,受保人的出生日期与我的客户所在的时区相关。让我们以居住在维多利亚-BC 的 17 岁 child 为例,他的生日是 12 月 2 日。如果他在 12 月 1 日 22:00 提交保险报价单,即使他仍然 17 岁,保险报价也会被接受,因为在我客户的时区中他已经 18 岁了。同样的规则适用于保险定价。这是法律要求。

    需要明确的是,我正在寻找一种可以应用于任何其他项目的全方位解决方案。具体问题是:Javascript,在 2007 年之前几年的特定几周内,报告的时间有 1 小时的偏移。无论我如何表示时间(本地时区或 UTC),这个偏移量总是存在的,因为它是错误的底层数据(不是数据表示)。

    我使用了“在中午设置时间部分”的解决方法来规避该错误,但潜在的问题仍然存在。如果我的客户要求我们开发一个 Web 应用程序,要求我们获取过去特定事件的日期和时间,会发生什么?例如:“请说明事故发生的确切日期和时间:2005 年 10 月 31 日 19:32”。 MVC Controller 会将时间设置为 18:32。

    最佳答案

    您忽略了 .Net 的一部分 DateTime结构体。具体来说,您没有考虑 .Kind任何 DateTime 的属性(property)是三种可能之一 DateTimeKind值。 More on MSDN .

    如果您使用的是 UTC 值,那么您需要设置 DateTimeKind.Utc .由于 JavaScript 的数值是基于 UTC 的,因此您应该使用它进行转换:

    DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)
    .AddMilliseconds(1162267200000);

    此外,您正在使用 zzz 做一些奇怪的事情。 DateTime 上的格式化程序有 DateTimeKind.Unspecified .在这种情况下,确实没有任何与该值相关联的时区,但 .Net 会假设您希望它的行为就像 DateTimeKind.Local 一样。 , 自 zzz否则格式化程序没有意义。

    你真的需要小心不要使用 DateTimeKind.Local值(例如 DateTime.Now )或任何未指定种类可能被误解为本地的(例如 zzz.ToUniversalTime() )。在这种情况下,“本地”对于您的服务器来说是本地的,这在 Web 应用程序中很少相关。 Read more here .

    关于 JavaScript 的 DST 实现,我对 ECMAScript 规范进行了类似的观察。 You can read more on that here .

    综上所述,您找到了一个非常具体的点,即 JavaScript 或 .Net 都没有提供表示没有时间的日期的类型。两者都采取将时间设置为午夜的方法。如果您不小心,您可能会遇到没有午夜的本地日期的问题,例如 October 20th, 2013 in Brazil .如果您仅限于美国,那么您可能没有那个特定的问题,但从设计的 Angular 来看它仍然是相关的。

    最好的方法是使用真正的“无时间日期”类型。在 .Net 中,您可以将其设为 LocalDateNoda Time图书馆。作为 ISO8601 字符串,它看起来像 "2013-10-31" ,没有任何时间或时区。

    如果你不想使用 Noda Time(虽然我强烈推荐它),你仍然可以使用 DateTime输入.Net,小心不要将时间部分用于任何事情。它应该有 DateTimeKind.Unspecified .

    不幸的是,目前 JavaScript 中没有针对没有时间的日期的 native 类型。 (JavaScript Date 类应该被命名为 DateTime )。因此,您需要自己构建一个仅限日期的字符串。您可以从 Date 组装它手动,例如:
    var s = dt.getFullYear() + "-" + 
    (dt.getMonth() < 10 ? "0" : "") + dt.getMonth() + "-" +
    (dt.getDate() < 10 ? "0" : "") + dt.getDate();

    但更简单的方法是使用 moment.js图书馆:
    var s = moment(dt).format("YYYY-MM-DD");

    我只是提供我对“最佳方法”的看法。但是,如果您只是想知道如何防止当前正在执行的操作失败,那么您应该小心不要在 JavaScript 响应中转换为 UTC。你正在用 .toISOString() 做这件事.同样,您可以手动组合完整的日期和时间,或者您可以使用 moment 来格式化根据本地时间的响应。

    如果您真的考虑一下,出生日期实际上并没有与之关联的时间或时区。大多数人在计算自己的年龄时不会跟踪他们出生的小时/分钟/秒(或他们出生地点的时区)。您可能会为占星术执行此操作,但对于日常业务用途,您只需使用您正在评估年龄的本地时区的一天开始时间。所以日期确实是唯一重要的数据。

    关于javascript - JavaScript 中的 DST 实现导致发送到 MVC Controller 时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19733241/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com