如何在夏令时期间使用TimeZoneInfo获取本地时间?


84

我试图用来DateTimeOffset在任何时区传达特定的时间点。我不知道如何用它TimeZoneInfo来处理夏时制。

var dt = DateTime.UtcNow;
Console.WriteLine(dt.ToLocalTime());

var tz = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
var utcOffset = new DateTimeOffset(dt, TimeSpan.Zero);
Console.WriteLine(utcOffset.ToOffset(tz.BaseUtcOffset));

打印输出:

2010/6/2下午4:37:19
2010/6/2下午3:37:19 -06:00

我在中央时区,我们目前处于夏令时。我试图让第二行读取:

2010/6/2下午4:37:19 -05:00

BaseUtcOffset 显然不会根据DST进行更改。

如何获得具有正确偏移值的正确时间?


13
+1-这让我发疯,因为TimeZoneInfo.ConvertTimeBySystemTimeZoneId不适用于此:)
James Manning 2010年

@JamesManning-这样做,假设dt.Kind设置正确。
马特·约翰逊·品脱

Answers:


61

您需要从TimeZoneInfo获取UtcOffset,然后将其传递给ToOffset()方法:

var dt = DateTime.UtcNow;
Console.WriteLine(dt.ToLocalTime());

var tz = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
var utcOffset = new DateTimeOffset(dt, TimeSpan.Zero);
Console.WriteLine(utcOffset.ToOffset(tz.GetUtcOffset(utcOffset)));

我知道...您必须获取时区中该特定日期的UTC偏移量。谢谢。
jaminto 2010年

5
卡尔·吉特森(Karl Gjertsen)的答案相比,这不是最佳方法,后者使用单个.Net函数来完成工作,而不是通过创建新的一次性扔掉来提取偏移量DateTimeOffset
ErikE

59

您还可以使用TimeZoneInfo.ConvertTimeFromUtc,这将允许夏令时:

DateTime utc = DateTime.UtcNow;
TimeZoneInfo zone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
DateTime localDateTime = TimeZoneInfo.ConvertTimeFromUtc(utc, zone);

如果我国的时区在夏天为EEST,在冬天为EET,该怎么办?夏令时如何使用?
拉米·泽比亚

1
Windows知道时区信息以及夏令时日期。如果您选择了一个预定义的时区,它应该可以解决。
Karl Gjertsen '18

11

或更妙的是,如果您不想硬编码时区标识符

TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById(TimeZoneInfo.Local.Id);
DateTime localDateTime = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, tzi);

2
您不能TimeZoneInfo.Local直接使用吗?为什么需要打给FindSystemTimeZoneById
CoderDennis

4
您说得对,我们不需要。我们可以这样做DateTime localDateTime = TimeZoneInfo.ConvertTimeFromUtc(networkDateTime, TimeZoneInfo.Local);
Pabinator

1
但随后您将被固定在一个时区。取决于您要如何使用我猜的代码。:-)
Karl Gjertsen

9
这不是很安全。如果您将应用程序外包到云环境,则您实际上不知道哪个时区是本地的。
汤姆(Tom)

5

我是.NET和stackoverflow的初学者,所以我可能是错的,但是这里有:

使用TimeZoneInfo.ConvertTimeFromUtc将允许夏令时,并根据时区+可能的DST偏移将其转换为正确的时间。但是,结果对象中的偏移量本身将显示标准时间的偏移量,而不考虑夏时制。因此,如果要在对象上执行ToString,最终将得到正确的时间(以小时和分钟为单位),但是夏令时期间的偏移量会错误,这可能会导致代码稍后的错误时刻。

如果改为使用GetUtcOffset获取特定时间的偏移量,然后对DateTimeOffset对象执行ToOffset,则小时/分钟和偏移量本身都将正确转换,并且可以安全地执行ToString。

string ExpectedDateTimePattern = "yyyy'-'MM'-'dd'T'HH':'mm':'ss''zzz";
string timeZoneId = "FLE Standard Time";
string dateTimestr = "2017-10-09T09:00:00+02:00";

DateTimeOffset dto = DateTimeOffset.Parse(dateTimeStr);
TimeZoneInfo zone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
TimeSpan offset = zone.GetUtcOffset(dto);
dto = dto.ToOffset(offset);
string localTime = dto.ToString(ExpectedDateTimePattern);

localTime将返回“ 2017-10-09T10:00:00 + 03:00”。


根据《任择议定书》,这是正确的答案。要了解的主要问题是,针对时区的UtcOffset不是恒定的,而是由于夏令时规则,它取决于日期本身。因此,OP所做的唯一错误是他使用常量BaseUtcOffset而不是GetUtcOffset(myDate)
g.pickardou,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.