关于c#:从DateTime(utc)和TimeZoneInfo获取DateTimeOffset

get DateTimeOffset from DateTime (utc) and TimeZoneInfo

我需要将DateTime + TimeZoneInfo转换为DateTimeOffset。

我该怎么做呢? 我假设我必须通过TimeSpan,但后来我不确定夏令时是否会得到妥善处理..

谢谢!

UPDATE

1
2
TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById("Mountain Standard Time");
return new DateTimeOffset(DateTime.UtcNow, timeZone.BaseUtcOffset);

此代码抛出异常..

The UTC Offset for Utc DateTime
instances must be 0.

Parameter
name: offset

更新2

对不起,我没有意识到DateTimeOffset只包含偏移量,它不包含实际的区域信息 - 所以我接受@Dave的回答,因为它是我将要使用的..


您应该在DateTime.UtcNow和DateTime.Now之间找到区别

1
2
3
var now = DateTime.Now;
var utcNow = now.ToUniversalTime();
var ts = utcNow - now;

如果要保存偏移量,通常有利于以UTC格式保存所有日期(特别是在数据库中),因此您不必处理偏移量。您只需在显示之前转换它们,但以UTC进行所有计算。

编辑:如果您有TimeZone对象,则可以将UTC日期转换为该时区的本地时间。

1
TimeZone.CurrentTimeZone.ToLocalTime()

要么

1
DateTime dt = TimeZoneInfo.ConvertTimeFromUtc()

以下是一些示例代码,它将列出所有时区的日期。

1
2
3
4
5
var dt = new DateTime(2011, 5, 21, 11, 0, 0);
foreach (var tzi in TimeZoneInfo.GetSystemTimeZones())
{
    Console.WriteLine(string.Format("Time in {0} is {1}", tzi.DisplayName, TimeZoneInfo.ConvertTimeFromUtc(dt, tzi)));
}


TimeZoneInfo具有BaseUtcOffset属性,该属性是表示偏移量的TimeSpan

这是DateTimeOffset构造函数所期望的偏移量:

1
var myDTOffset = new DateTimeOffset(myDatetime, mytzInfo.BaseUtcOffset);


我认为可能有一个更简单的解决方案来消除错误。你试过:

1
2
TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById("Mountain Standard Time");
return new DateTimeOffset(DateTime.UtcNow, timeZone.BaseUtcOffset);

DateTimeOffset抛出异常。你想要的是这个:

1
2
TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById("Mountain Standard Time");
return new DateTimeOffset(DateTime.UtcNow).ToOffset(timeZone.BaseUtcOffset);

这不会抛出异常。我不确定为什么接受TimeSpan的构造函数甚至存在,因为它只有在匹配DateTime对象中给出的local或utc偏移时才有效。但它仍然可以减轻头痛。


对于我们这些使用遗留系统的人来说,并不总是可以改变数据的存储方式。如果您只对运行代码的计算机上的特定时区感兴趣,则可以使用以下扩展方法。 DateTime和DateTimeOffset之间存在隐式转换,它考虑了"DateTime.Kind"属性。

1
2
3
4
public static DateTimeOffset ToDateTimeOffset(this DateTime dt)
{
    return DateTime.SpecifyKind(dt, DateTimeKind.Local);
}