.net 为夏季夏令时增加一小时 [重复]
Posted
技术标签:
【中文标题】.net 为夏季夏令时增加一小时 [重复]【英文标题】:.net adds one hour to summer dst [duplicate] 【发布时间】:2015-03-10 09:15:18 【问题描述】:我从 Web 服务 2013-10-15T12:54:18+01:00
获得以下字符串。这个日期是夏季 DST,我的 .NET 代码(我想是 Web 服务代理)会自动增加一小时。如果返回值落在冬季 DST 之内,则情况并非如此。返回的时间 (12:54:18
) 是我想要显示的,我不希望进行任何类型的重新计算。
我使用TimeSpan DateTime.TimeOfDay
来显示时间。
我能做些什么来实现它?
【问题讨论】:
“夏令时”是无用的信息。有许多“夏季”时区。 我在这里看不到任何“夏季夏令时”,只是一个偏移量为“1:00”的 DateTimeOffset 值。如果您尝试将其转换为 DateTime 对象,.NET 将检查您的本地时区偏移量并创建相应的 DateTime 值。您是否将时区偏移与夏令时混淆了? 您是否将 DateTimeOffset 值转换为 DateTime?夏季的 CE 时间为 +2:00,而冬季为 +1。2013-10-15T12:54:18+01:00
上的挂钟将显示 13:54。当 .NET 转换为本地时间时,它会考虑到这一点以创建正确的值。
换句话说,一架从 CE 机场在2013-10-15T12:54:18+01:00
起飞的飞机的本地起飞时间为13:54
。为了避免这种混淆,航空公司要么只发布当地时间,要么使用时区的名称,而不是偏移量。如果返回偏移量,它始终是实际的本地偏移量。
我正在从我的 C# 代码调用 Web 服务并取回该值(日期时间类型)。当我扫描网络流量时,我看到提到的字符串 2013-10-15T12:54:18+01:00
是通过网络发送的。
【参考方案1】:
我正在尝试将您的问题和其他 cmets 拼凑在一起。到目前为止,这是我的分析:
在网络上,您会看到两个不同的日期和时间字符串:
如果没有夏令时(冬季),字符串为 2013-12-30T12:54:18
使用夏令时(夏季),字符串为2013-10-15T12:54:18+01:00
这表明 Web 服务使用 GMT 标准时间 作为时区。
您想从日期和时间字符串中提取 GMT 时间戳。
但是,在您和 Web 服务之间存在一些未指定的 Web 服务代理(我假设是某种 .NET 框架?)并且在您的代码中您只能访问 @ 987654323@ 以及您的代码在 中欧标准时间 时区执行,如果我们忽略往返转换的短暂时间,该时区在夏季和冬季基本上都比格林威治标准时间早一小时夏令时。
我希望到目前为止我是正确的。
您可以使用此代码将传入的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) 转换而来。 如果我的分析是正确的,这就是你问题的根源。
另一种解释方式:
|服务器 (GMT) |框架 (CET) |我的代码 --------+---------------+------------------------- -+---------------------------- 夏季 | +01:00 后缀 | GMT -> CET 增加 1 小时 | CET -> GMT 减去 1 小时 --------+---------------+------------------------- -+---------------------------- 冬季 |无后缀 |假定为 CET | CET -> GMT 减去 1 小时这个问题没有简单的解决方法。如果您可以说服 Web 服务提供正确的偏移量,即使它是 +00:00
,我上面的代码也适用于夏季和冬季。更好的是,仅使用 UTC 并且仅在最终用户参与时转换为本地时间。但我猜你无法控制网络服务?
一种选择是在与服务器相同的时区(例如 GMT)中执行您的代码。那么你应该可以直接使用时间戳而无需任何转换。
另一个更难看的选择是确定网络服务是否在夏令时之外,然后相应地调整时间:
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,所以这样做可能有点矫枉过正这个。
更重要的是,我不确定这段代码在夏令时转换期间能否提供正确的结果。尽管我相信 GMT 和 CET 在同一日期转换 CET 仍然比 GMT 早一小时。您确实必须创建一些单元测试以确保获得所需的结果。
【讨论】:
相关网络服务检索到的时间值是在我所在的时区创建的。此外,我无法获取字符串2013-10-15T12:54:18+01:00
。我在扫描网络流量时看到了这个字符串,但在我的代码中,我只能访问 C# 类型的 DateTime(由 Web 服务代理提供)及其TimeOfDay
属性。有趣的是:所有包含冬季 DST 日期的时间戳(扫描网络流量时)都没有+01:00
。
“你的问题并不完全清楚你想做什么” - 对于提到的字符串(如在线上扫描的2013-10-15T12:54:18+01:00
),我想显示12:54:18
。对于冬季 DST 的日期,我得到2013-12-30T12:54:18
(注意缺少的+01:00
),对于这样的字符串,我还想显示12:54:18
。
@Robotron:我已经完全重写了我的答案,希望能更好地解决你的问题。
测试系统的工作方式似乎与生产系统不同。提到的+01:00
仅出现在测试环境中的夏季夏令时,而不是生产环境中。花了很多时间才弄明白这个。最后我只测试了DateTime.IsDaylightSavingTime()
。【参考方案2】:
在此类示例中,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
【讨论】:
【参考方案3】:您可能需要查看this MSDN article,它描述了您的 TimeOfDay 当前正在返回的转换。
通过检查那篇文章,您可以找到纠正它的方法。 TimeZoneInfo 是您需要的类。
编辑,Jon Skeet 提供的工作也可能有所帮助,请查看Noda Time blogspot 了解更多信息!
【讨论】:
以上是关于.net 为夏季夏令时增加一小时 [重复]的主要内容,如果未能解决你的问题,请参考以下文章