将用户输入的确切日期从 Javascript 传递到 .NET

Passing exact date entered by user from Javascript to .NET

在我们的 ASP.NET 私立学校 MVC 网络应用程序中,用户可以输入日历事件的日期(以及其他内容,即家庭作业截止日期),这些日期将使用 学校的 时区,不一定与他们自己的计算机相同(即,如果他们在另一个州度假时使用网络应用程序)。

我只想按字面意思传递日期,这样当我在服务器上接收到它们时,我可以确切地知道用户输入的值是什么,并让服务器根据学校的时区。

另一方面,我也希望服务器将已调整的日期传递给客户端,然后客户端应按原样显示这些日期。我不希望日期自动转换为计算机时区,因为我希望所有日期都显示为学校时区。

我们将 Json.NET 用于 serializing/deserializing JSON。我们当前的日期设置是:

serializerSettings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
serializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;

也许我应该为 DateTimeZoneHandling 使用不同的选项...?

反序列化日期的最大问题是用户输入的实际日期不会被保留,除非它们与我们的服务器处于同一时区。因此,如果太平洋地区的客户端输入时间为 4:00 PM 的日期,则服务器(中部时间)会将其视为 6:00 PM,这是正确的,因为它们代表同一时间UTC,但我真正想要的是知道用户输入 4:00 PM,并注意弄清楚服务器端实际代表的 UTC 时间。

我在服务器上使用 NodaTime 来处理将用户输入时间转换为要存储在数据库中的实际 UTC 时间。

我在 javascript 中的当前解决方案是,当从服务器接收日期时,将它们 返回 转换为 UTC,以便我获得服务器传递的实际日期。这部分感觉很hacky。

    function convertToUTCDate(date) {
        var utcDate = new Date(
            date.getUTCFullYear(),
            date.getUTCMonth(),
            date.getUTCDate(),
            date.getUTCHours(),
            date.getUTCMinutes(),
            date.getUTCSeconds()
        );

        return utcDate;
    }

我查看了很多 Whosebug 问题,并且学习了 Matt Johnson 在 PluralSight 中的日期和时间基础课程。我在 javascript 和 .NET 中学到了很多关于日期的好原则,但它们似乎都与我的情况不同:我不在乎用户的时区是什么,我想要所有日期以学校时区显示,并将日期输入视为在学校时区上下文中输入时间。

是否有一种简单且非 hacky 的方法可以在两个方向上做我想做的事情? (客户端向服务器发送日期,服务器向客户端发送日期)

不是 100% 确定我明白你说的。

但是如果你使用像 momentjs 这样的东西,那么不要转换为服务器上的时区。到处使用UTC日期,然后告诉客户端javascript要使用的时区是什么,然后使用moment将utc时间转换成你想要显示的时区。

从您描述的情况来看,听起来最简单的事情就是只传递不合格的日期和时间值,而不是本地或 UTC。

  • 在服务器上,使用 DateTimeUnspecified 类型,或使用 Noda Time 的 LocalDateTime.

  • 保留 JSON.Net 的默认日期格式处理,即 DateFormatHandling.IsoDateFormatDateTimeZoneHandling.RoundtripKind。你很少需要修改这些,只要你适当注意Kind

    • 如果您直接序列化 Noda Time 类型,请确保使用 ConfigureForNodaTime 连接 NodaTime.Serialization.JsonNet 库,如 in the user guide.
    • 所述
  • 通过网络,数据应该类似于 "eventTime" : "2016-03-01T10:00:00"。不要包含 Z,因为您不发送 UTC。也不包括偏移量。

  • 在客户端,不要使用 Date 对象。它总是在当地时区工作。相反,请考虑使用 moment.js.

    • 目前没有 "unspecified" 模式,但您可以使用 UTC 模式伪造它,即使该值实际上不是 UTC 格式,这仍然适用于格式化。呼叫moment.utc(yourvalue)。不要使用 moment(yourvalue),因为它将处于 local 模式,并且会像 Date 对象一样采用本地时区的 DST 行为.

    • 或者,您真的可以只使用 RobG 在评论中建议的字符串。您只需要自己在用户输入和有线格式之间解析和格式化它们。有些人可能会觉得这很容易,而另一些人则更愿意让图书馆来做。

最后,请注意,我是根据您描述的场景中的许多假设提出此建议的。如果还有您没有解释的其他用例,它可能是理想的,也可能不是理想的。例如,如果您通过此 API 向某些第三方发送相同的值,那么使用包含偏移量的序列化 DateTimeOffset 可能更合适。

还认识到您可以在所有客户端执行此操作,使用诸如 moment-timezone 之类的东西。然而,对于这种特殊情况,这可能不是必需的。