C# 如何使用节点时间(给定日光)计算指定日期和时间的时区UTC偏移量?
我有一个时区Id,需要知道一些日期时间的时区偏移量。 据我所知,以下函数返回DateTime.Now的偏移量(或者没有日光偏移量?) 但我需要C# 如何使用节点时间(给定日光)计算指定日期和时间的时区UTC偏移量?,c#,nodatime,C#,Nodatime,我有一个时区Id,需要知道一些日期时间的时区偏移量。 据我所知,以下函数返回DateTime.Now的偏移量(或者没有日光偏移量?) 但我需要 TimeSpan GetTimeZoneOffset(string timeZoneId, DateTime utcInstant) 如何实现它?从根本上说,您需要,它接受一个即时 TimeSpan GetTimeZoneOffset(string timeZoneId, DateTime date) => new DateTimeZon
TimeSpan GetTimeZoneOffset(string timeZoneId, DateTime utcInstant)
如何实现它?从根本上说,您需要,它接受一个即时
TimeSpan GetTimeZoneOffset(string timeZoneId, DateTime date) =>
new DateTimeZoneCache(TzdbDateTimeZoneSource.Default)
.GetZoneOrNull(timeZoneId)
.GetUtcOffset(Instant.FromDateTimeUtc(utcDay))
.ToTimeSpan();
如果DateTime
值的种类始终为Utc
,则可以使用。如果它可能有不同的类型
,您需要制定更详细的需求
接下来,您需要一个IDateTimeZoneProvider
将时区ID映射到DateTimeZone
。这可能是DateTimeZoneProviders.Tzdb
,也可能是为了可测试性而注入的
一旦获得了即时
和日期时区
,您就可以调用GetUtcOffset
来获取偏移量。您可以将其转换回TimeSpan
,但我实际上鼓励您在应用程序中尽可能避免使用DateTime
和TimeSpan
,前提是您可以在代码库中的任何位置使用Noda时间类型,并且仅在边界处的这些类型和BCL类型之间进行转换(例如,数据库访问)你会发现你需要做的工作要少得多
但如果您确实需要时间跨度
,则该方法如下所示:
TimeSpan GetTimeZoneOffset(字符串timeZoneId,DateTime dateTimeUtc)
{
Instant Instant=Instant.FromDateTimeUtc(dateTimeUtc);
DateTimeZone=DateTimeZoneProviders.Tzdb[timeZoneId];
偏移量=zone.GetUtcOffset(即时);
返回offset.ToTimeSpan();
}
请注意,IDateTimeZoneProvider[string]
索引器将在该提供程序中未找到时区时引发异常。如果您想以不同的方式处理此问题,请使用IDateTimeZoneProvider.GetZoneOrNull()
并检查结果是否为空。日期没有偏移量-特定的时间瞬间有偏移量。由于(例如)夏令时转换,单个日期可能跨越多个偏移。请澄清这个问题。好的,所以“对于某个日期时间”更合理一点-这是否总是DateTime
和类型的UTC?您的示例答案假设是这样,但这确实很重要。(如果它是一种未指定的类型,并且该值被跳过或不明确,该怎么办?作为一个更重要的说明,当您在整个代码库中使用它时,Noda Time提供了最大的价值-我建议您保持在Noda Time的上下文中(因此Instant
和Offset
而不是DateTime
和TimeSpan
)对于尽可能多的代码。如果需要兼容性,请仅在代码边界处转换为BCL类型。@JonSkeet,我正试图用很少的节点时间经验找到解决问题的方法。为此,我使用我已经知道的术语和我已经掌握的知识在谷歌上搜索。这对你有好处在一篇文章中使用正确的术语,但在有疑问的情况下,最好保持问题的原样(为有同样问题的人简化谷歌搜索)。如果我的问题中有错误,可以在回答中更正,并指出我不理解。好吧,我真的不想添加答案,直到问题中的假设得到澄清-主要是日期时间的类型你需要能够处理。它只会是UTC吗?我会回答推荐每次使用DateTimeZoneProviders.Tzdb
而不是创建一个新的DateTimeZoneCache
,如果区域ID未知,这将抛出一个NullReferenceException
。如果您想因异常而失败,只需使用索引器-这将抛出一个更清晰的异常。@jonsket在我的实际项目中,我将DateTimeZoneCache作为单例注入。此外,我确信timeZoneId是正确的,因为它是在数据流的早期阶段验证的。无论如何,使用索引器是一个很好的观点。
TimeSpan GetTimeZoneOffset(string timeZoneId, DateTime date) =>
new DateTimeZoneCache(TzdbDateTimeZoneSource.Default)
.GetZoneOrNull(timeZoneId)
.GetUtcOffset(Instant.FromDateTimeUtc(utcDay))
.ToTimeSpan();