将本地时间转换为 UTC 时间

Convert local time of day to UTC time

我们的 ASP.NET MVC 网络应用程序具有向用户发送定期通知电子邮件的功能。我们将添加一项功能,用户可以 select 在一天中的特定时间接收他们的电子邮件(即 "I would like to receive an email once per day at 5pm")。

我计划使用 SQL time 类型存储 selected 时间。我们将有一个后台进程,每分钟 运行s 查找需要发送电子邮件的用户。该过程使用 LINQ-to-Entities 查询来查找所有匹配的用户。我打算编写一个查询,基本上找到每天电子邮件时间少于当前 UTC 时间的所有用户 - 这就是我 运行 遇到问题的地方。每个用户都可以属于不同的时区——我们将他们的时区作为 IANA 时区标识符存储在数据库中。我们在我们的项目中使用 NodaTime 将存储在我们数据库中的任何日期作为 UTC 转换为用户的时区。为了继续我尝试这样做的方式,我需要一些我可以放在 LINQ-to-entities 查询中的东西,所以我不能真正使用任何 NodaTime 函数来转换时间并确定当前时间day 在用户指定的一天中的时间之后,在他们的时区中。我不能只用 UTC 时间存储他们指定的一天中的时间,如果我这样做了,那么每当 DST 到来时它就会关闭一个小时。

我现在能想到的最佳解决方案是 "cache" 我们数据库中每个时区的当前 UTC 偏移量。所以我可以有一些代码使用 NodaTime 获取每个时区的当前偏移量并将其保存到存储 TimeZoneID 和 UTCHourOffset 的数据库中的 table。我可以定期处理 运行 这段代码,并确保缓存的小时偏移量保持最新。然后在我的查询中,我可以通过查找缓存的 UTC 偏移并将其添加到他们的一天中的时间来转换每个用户的指定时间,以确定是否应该向他们发送电子邮件。

有没有更简单的方法来完成我想做的事情?

很高兴看到你考虑周全。事实上,当您尝试在 user-local 时区安排重复事件时,您不能只存储 UTC 时间。 (不要让任何人告诉你 "always UTC" - 这是一个常见的误解,你确实有一个当地时间的有效案例。)我已经写过几次了,最彻底的答案是 here.

而不是缓存偏移量,您应该将下一个 pre-calculating 时间视为精确的 UTC 时间戳(日期和时间)。然后您可以查询它以了解何时发送电子邮件。或者,考虑使用已经处理此问题的 timezone-aware 作业调度程序。 Quartz.NET 不错。

您说得对,您目前不能将 Noda Time 类型与 EF 一起使用。这是由于 EF tracked in this issue. The good news is the dev work was recently completed for EF Core 2.1 (still in development). After that releases, someone (probably me) will have to apply that feature to create an EF-NodaTime support package. In the meantime, treat SQL time types as a .Net TimeSpan, and use the Buddy Properties approach 长期缺乏公开 NodaTime 类型的功能。您必须针对 TimeSpan 编写 LINQ 查询。如果您迁移到 EF Core 2.1,您可以稍后重构它。