c# - 你如何处理 .net 中的 'Ambiguous Time'?

标签 c# timezone nodatime

我需要将不同时区的“DateTime”值转换为 UTC,反之亦然。我使用 TimeZoneInfo 来执行此操作。但是,问题在于“夏令时”时间更改发生的时间。

例如,今年,下一次时间更改发生在 11 月 3 日凌晨 2 点 [CDT]。因此,在 11 月 3 日,凌晨 1 点 [CDT] 转换为早上 6 点,并且随着下一个小时发生时间更改,我们得到凌晨 1 点[现在它的 CST] 并且它也被转换为早上 6 点。我在 this 上试过代码页面,但它没有说明如何处理这个问题。那么如何处理这个问题呢???

编辑:

我试过 NodaTime,当我像这样进行转换时

 DateTimeZoneProviders.Tzdb["America/Chicago"].AtStrictly(<localDateTime>) 

它抛出 AmbiguousTimeException。这很好,我也可以使用 TimeZoneInfo 来做到这一点。但是我怎么知道我需要选择哪个 localTime 值?

编辑 2:

这里是 link用于与 Matt 的聊天讨论。

最佳答案

如果您只有本地时间,并且该时间不明确,那么您不能将其转换为精确的 UTC 时刻。这就是为什么我们说“模棱两可”。

例如,在美国中部时区,其具有 IANA 区域名称 America/Chicago 和 Windows 区域 ID Central Standard Time - 涵盖“Central Standard”时间”和“中央夏令时”。如果我只知道现在是 2013 年 11 月 3 日凌晨 1:00,那么这个时间就是模棱两可的,而且绝对没有办法知道这是否是中部夏令时的第一个凌晨 1:00 (UTC-5),或中央标准时间 (UTC-6)。

当被要求将模糊时间转换为 UTC 时,不同的平台会执行不同的操作。有些选择第一个时间,通常是夏令时。有些使用标准时间,通常是第二个时间。有些抛出异常,有些(如 NodaTime)让您选择想要发生的事情。

让我们先从 TimeZoneInfo 开始。

// Despite the name, this zone covers both CST and CDT.
var tz = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
var dt = new DateTime(2013, 11, 3, 1, 0, 0);
var utc = TimeZoneInfo.ConvertTimeToUtc(dt, tz);
Debug.WriteLine(utc); // 11/3/2013 7:00:00 AM

如您所见,.net 选择使用“标准”时间,即 UTC-6。 (将 6 小时添加到凌晨 1 点,您将到达早上 7 点)。它没有给你任何时间不明确的警告。您可以像这样检查自己:

if (tz.IsAmbiguousTime(dt))
{
    throw new Exception("Ambiguous Time!");
}

但是没有任何东西可以强制执行此操作。您必须自己检查。

避免歧义的唯一方法是使用DateTime 类型。相反,您可以使用 DateTimeOffset。观察:

// Central Standard Time
var dto = new DateTimeOffset(2013, 11, 3, 1, 0, 0, TimeSpan.FromHours(-6));
var utc = dto.ToUniversalTime();
Debug.WriteLine(utc); // 11/3/2013 7:00:00 AM +00:00

// Central Daylight Time
var dto = new DateTimeOffset(2013, 11, 3, 1, 0, 0, TimeSpan.FromHours(-5));
var utc = dto.ToUniversalTime();
Debug.WriteLine(utc); // 11/3/2013 6:00:00 AM +00:00

现在,将其与 NodaTime 进行比较:

var tz = DateTimeZoneProviders.Tzdb["America/Chicago"];
var ldt = new LocalDateTime(2013, 11, 3, 1, 0, 0);

// will throw an exception, only because the value is ambiguous.
var zdt = tz.AtStrictly(ldt);

// will pick the standard time, like TimeZoneInfo did
var zdt = tz.AtLeniently(ldt);

// manually specify the offset for CST
var zdt = new ZonedDateTime(ldt, tz, Offset.FromHours(-6));

// manually specify the offset for CDT
var zdt = new ZonedDateTime(ldt, tz, Offset.FromHours(-5));


// with any of the above, once you have a ZonedDateTime
// you can get an instant which represents UTC
var instant = zdt.ToInstant();

如您所见,有很多选项。都是有效的,这取决于你想做什么。

如果您想完全避免歧义,请始终保留 DateTimeOffset,或者在使用 NodaTime 时使用 ZonedDateTimeOffsetDateTime。如果您使用 DateTimeLocalDateTime,则无法避免歧义。

关于c# - 你如何处理 .net 中的 'Ambiguous Time'?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16993591/

相关文章:

c# - 内存不足故障自动化 VSTO Powerpoint API

php - 如何在多个不同的 php 环境中运行 PHPunit 测试套件?

c# - 野田时间倒计时

c# - 如何在 C# 中从 TCP 服务器发送\接收文件流?

c# - 使用组合框中选定的文本更改 SQL 查询

c# - 在固定网格上拖动对象的算法

c# - 获取一个国家的默认时区(通过 CultureInfo)

python - 如何从本地时间戳获取 UTC 纪元值

nodatime - 使用 `Period.Between` 和减去两个本地日期之间的区别

c# - DateTime.Now 和文化/时区特定