不明确的 DateTimeOffset 示例

Example of ambiguous DateTimeOffset

我们在 Database/Model 中有 DateTimeOffsets。为了在 Web 中显示这些值,我们将 DateTimeOffsets 转换为当前用户的时区。

根据 MSDN,DateTimeOffset 在特定时区中可能不明确:

TimeZoneInfo.IsAmbiguousTime Method (DateTimeOffset)

这对我来说完全没有意义。有人可以给我一个不明确的 示例 DateTimeOffset 吗?
我们在时区 "W. Europe Standard Time"。

文档说的不明白吗?

Typically, ambiguous times result when the clock is set to return to standard time from daylight saving time

即如果你在凌晨 2 点离开夏令时并将时钟重置为凌晨 1 点,那么如果有人开始谈论凌晨 1.30,你不知道那是从现在开始 30 分钟还是过去 30 分钟。

有一组值(通常为一小时)映射到 UTC 时间的两组不同时刻。

样本是(去年 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");

A​​mbiguous相反的时间是Invalid时间(最后一个三月的周日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");

我认为混淆来自此处定义 "ambiguous" 的方式。

需要说明的是,DateTimeOffset 本身永远不会有歧义。它 总是 代表绝对瞬时时间中的特定时刻。给定日期、时间和偏移量,我可以告诉你本地 wall-time 和精确的 UTC 时间(通过应用偏移量)。

但是,值的 wall-time 部分在特定时区内可能不明确。也就是说,日期和时间仅在您忽略偏移量时。这就是 TimeZoneInfo.IsAmbiguousTime 告诉你的。那个如果不是偏移量,这个值就会有歧义。 wall-time 可能会让那个时区的人感到困惑。

考虑到此方法有两个重载,一个需要 DateTime,一个需要 DateTimeOffset.

  • .KindDateTimeKind.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 不适用时以快捷方式开头以获得更好的性能,但这就是它的作用。