模棱两可的 DateTimeOffset 示例
Posted
技术标签:
【中文标题】模棱两可的 DateTimeOffset 示例【英文标题】:Example of ambiguous DateTimeOffset 【发布时间】:2016-04-18 13:50:35 【问题描述】:我们在数据库/模型中有 DateTimeOffsets。为了在 Web 中显示这些值,我们将 DateTimeOffsets 转换为当前用户的时区。
根据 MSDN,DateTimeOffset 在特定的 TimeZone 中可能是不明确的:
TimeZoneInfo.IsAmbiguousTime Method (DateTimeOffset)
这对我来说根本没有意义。谁能给我一个模棱两可的示例 DateTimeOffset? 我们在时区“西欧标准时间”。
【问题讨论】:
注意,DateTimeOffset
是时区 awareness。它只有日期、时间和 Utc 偏移值。
【参考方案1】:
文档中所说的内容是否不清楚?
通常,当时钟设置为从夏令时返回标准时间时,会产生不明确的时间
即如果您在凌晨 2 点离开 DST 并将时钟重置为凌晨 1 点,那么如果有人开始谈论凌晨 1.30,您不知道那是从现在开始的 30 分钟还是过去 30 分钟发生的事情。
有一组值(通常为一小时长)映射到 UTC 时间中的两组不同时刻。
【讨论】:
【参考方案2】:示例是(去年 10 月的星期日 2:00-3:00)
DateTimeOffset example = new DateTimeOffset(2015, 10, 25, 2, 30, 0,
new TimeSpan(0, 2, 0, 0));
TimeZoneInfo tst = TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time");
if (tst.IsAmbiguousTime(example))
Console.Write("Ambiguous time");
与不明确时间相反的是无效时间(去年三月的星期日2:00-3:00):
TimeZoneInfo tst = TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time");
if (tst.IsInvalidTime(new DateTime(2016, 03, 27, 2, 30, 0)))
Console.Write("Invalid time");
【讨论】:
【参考方案3】:我认为混淆来自这里定义“模棱两可”的方式。
需要明确的是,DateTimeOffset
本身永远不会模棱两可。它总是代表绝对瞬时时间中的特定时刻。给定日期、时间和偏移量,我可以告诉你当地的挂钟时间和精确的 UTC 时间(通过应用偏移量)。
但是,值的挂起时间部分在特定时区内可能不明确。也就是说,日期和时间只有您忽略偏移量时。这就是TimeZoneInfo.IsAmbiguousTime
告诉你的。那如果不是偏移量,这个值就会是模棱两可的。墙上时间可能是那个时区的人可能会感到困惑的时间。
考虑这个方法有两种重载,一种采用DateTime
,另一种采用DateTimeOffset
。
当.Kind
是DateTimeKind.Unspecified
时,DateTime
非常有意义。
DateTime dt = new DateTime(2016, 10, 30, 2, 0, 0);
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time");
bool ambiguous = tz.IsAmbiguousTime(dt); // true
对于其他类型来说意义不大,因为它首先会转换到给定的时区 - 但它仍然会做同样的事情:
DateTime dt = new DateTime(2016, 10, 30, 1, 0, 0, DateTimeKind.Utc);
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time");
bool ambiguous = tz.IsAmbiguousTime(dt); // true
DateTimeOffset
重载本质上与前面的示例执行相同的操作。无论偏移量是多少,它都会应用于日期和时间,然后仅在生成的日期和时间上检查歧义 - 就像在第一个示例中一样。
DateTimeOffset dto = new DateTimeOffset(2016, 10, 30, 2, 0, 0, TimeSpan.FromHours(1));
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time");
bool ambiguous = tz.IsAmbiguousTime(dto); // true
即使偏移量对该时区没有意义,它仍然会在比较之前应用。
DateTimeOffset dto = new DateTimeOffset(2016, 10, 29, 19, 0, 0, TimeSpan.FromHours(-5));
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time");
bool ambiguous = tz.IsAmbiguousTime(dto); // true
归结为重载的实现,本质上是:
// Make sure the dto is adjusted to the tz. This could be a no-op if it already is.
DateTimeOffset adjusted = TimeZoneInfo.ConvertTime(dto, tz);
// Then just get the wall time, stripping away the offset.
// The resulting datetime has unspecified kind.
DateTime dt = adjusted.DateTime;
// Finally, call the datetime version of the function
bool ambiguous = tz.IsAmbiguousTime(dt);
你可以看到这个in the .net reference source here。他们将其压缩为两行,并在不适用 DST 时使用快捷方式作为开头以获得更好的性能,但这就是它的作用。
【讨论】:
很好的答案!您对墙上时间部分的解释和对时区值的无知有很大帮助!我不知道框架只使用 DateTimeOffset 的 DateTime 部分。 这只是关于 this 功能。还有很多其他地方确实考虑了偏移量。以上是关于模棱两可的 DateTimeOffset 示例的主要内容,如果未能解决你的问题,请参考以下文章
选择 SQL Server DatetimeOffset 作为 .Net DateTimeOffset.Ticks