.NET 为夏季夏令时增加了一小时

本文关键字:一小时 增加 夏令时 夏季 NET | 更新日期: 2023-09-27 18:37:17

我从 Web 服务2013-10-15T12:54:18+01:00那里得到一个以下字符串。这个日期是夏季夏令时,我的 .NET 代码(我认为是 Web 服务代理)会自动添加一个小时。如果返回值落在冬季 DST 内,则情况并非如此。返回的时间(12:54:18)是我想要显示的,我不希望进行任何形式的重新计算。

我用TimeSpan DateTime.TimeOfDay来显示时间。

我能做些什么来实现它?

.NET 为夏季夏令时增加了一小时

我正在尝试将您的问题和其他评论中的碎片放在一起。到目前为止,这是我的分析:

  1. 在网络上,您会看到两个不同的日期和时间字符串:

    • 如果没有夏令时(冬季),字符串2013-12-30T12:54:18

    • 使用夏令时(夏季),字符串2013-10-15T12:54:18+01:00

    这表明 Web 服务使用 GMT 标准时间作为时区。

  2. 您希望从日期和时间字符串中提取 GMT 时间戳。

  3. 但是,在您和 Web 服务之间有一些未指定的 Web 服务代理(我假设是某种 .NET 框架?),在您的代码中,您只能访问DateTime而且您的代码以中欧标准时区执行,如果我们忽略与日光之间的过渡的短暂时间,则在夏季和冬季基本上比 GMT 早一小时储蓄。

我希望到目前为止我是对的。

您可以使用以下代码将传入DateTime转换为 GMT:

// Framework code creates the DateTime.
var sourceDateTime = DateTime.Parse("2013-10-15T12:54:18+01:00");
// Application code can further process the DateTime.
var destinationTimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
var destinationDateTime = TimeZoneInfo.ConvertTime(sourceDateTime, destinationTimeZoneInfo);

此示例在夏令时给出正确答案。传入的日期和时间字符串包含偏移量,并正确解析为本地时区 (CET)。TimeZoneInfo.ConvertTime假定源DateTime位于本地时区,并且结果正确。

但是,代码在没有夏令时的冬季失败:

var sourceDateTime = DateTime.Parse("2013-12-30T12:54:18");

请注意,日期和时间字符串不再包含时区偏移量。偏移量+00:00,但由于某种原因,字符串中缺少偏移量。这意味着假定源DateTime位于本地时区 (CET),而不是从实际时区 (GMT) 转换而来。如果我的分析是正确的,这就是你问题的根源。

另一种解释方式:

       |服务器 (格林威治标准时间) |框架 |我的代码-------+---------------+---------------------------+----------------------------夏季 |+01:00 后缀 |格林威治标准时间 -> 欧洲中部时间增加 1 小时 |欧洲中部时间 -> 格林威治标准时间减去 1 小时-------+---------------+---------------------------+----------------------------冬季 |无后缀 |假设为欧洲中部时间 |欧洲中部时间 -> 格林威治标准时间减去 1 小时

这个问题没有简单的解决方法。如果您可以说服 Web 服务提供正确的偏移量,即使它+00:00我上面的代码在夏季和冬季都可以工作。更好的是,只使用 UTC,并且只在最终用户参与时转换为本地时间。但是我想您无法控制Web服务吗?

一种选择是在与服务器相同的时区(例如 GMT)执行代码。然后,您应该能够直接使用时间戳而无需进行任何转换。

另一个更丑陋的选择是确定 Web 服务是否在夏令时之外,然后相应地调整时间:

var destinationTimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
if (!destinationTimeZoneInfo.IsDaylightSavingTime(sourceDateTime)) {
  var sourceDateTimeOffset = new DateTimeOffset(sourceDateTime, destinationTimeZoneInfo.BaseUtcOffset);
  sourceDateTime = sourceDateTimeOffset.UtcDateTime;
}
var destinationDateTime = TimeZoneInfo.ConvertTime(sourceDateTime, destinationTimeZoneInfo);

我试图使代码尽可能通用,但实际上它只是试图解决缺少+00:00的情况,在这种情况下,destinationTimeZoneInfo.BaseUtcOffset正好是 0,所以这样做可能有点矫枉过正。

更重要的是,我不确定此代码在夏令时转换期间是否提供正确的结果。尽管我相信格林威治标准时间和CET在同一天过渡,欧洲中部时间仍然比格林威治标准时间早一个小时。您确实必须创建一些单元测试以确保获得所需的结果。

在此类示例中,DateTime 对象不包含偏移量。它只保存一个kind可以是:本地偏移量(运行时环境的偏移量)或UTC。这样做,因为DateTimeOffset是你想要的:

DateTimeOffset test = DateTimeOffset.Parse("2013-10-15T12:54:18+01:00");
Console.WriteLine(test.DateTime.TimeOfDay); // UTC
Console.WriteLine(test.LocalDateTime.TimeOfDay); // Localized with the offset parsed

将输出

12:54:18
11:54:18

您可能需要查看此 MSDN 文章,其中介绍了您的 TimeOfDay 当前返回的转换。

通过检查该文章,您可以找到如何更正它的方法。时区信息是你需要的类。

编辑,Jon Skeet提供的工作也可能有所帮助,请查看Noda Time博客以获取更多信息!