简体   繁体   English

C# DateTime - 将 DateTimeOffset 转换为另一个 TimeZone

[英]C# DateTime - converting a DateTimeOffset to another TimeZone

When converting a DateTimeOffset to another TimeZone, the OffSet is incorrect.将 DateTimeOffset 转换为另一个 TimeZone 时,OffSet 不正确。

I've read many articles and experimented for too many hours, but can't see what I'm missing here:我已经阅读了很多文章并进行了太多小时的实验,但看不到我在这里缺少什么:

// It's June in the UK and we're in British Summer Time, which is 1 hour ahead of UTC (GMT)
var UKoffsetUtc = new TimeSpan(1, 0, 0);

// It's 4pm - declare local time as a DateTimeOffset
var UKdateTimeOffset = new DateTimeOffset(2020, 6, 17, 16, 0, 0, UKoffsetUtc);

// Convert to UTC as a date
var utc = DateTime.SpecifyKind(UKdateTimeOffset.UtcDateTime, DateTimeKind.Utc);

// Get Aus TimeZoneInfo
var AUSTimeZone = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time");

// Check the Aus offset from UTC
var AUSOffset = AUSTimeZone.GetUtcOffset(utc);
Console.WriteLine(AUSOffset); // Output is 10 as expected

// Declare Aus Time as DateTimeOffset
var AUSDateTimeOffset = TimeZoneInfo.ConvertTimeFromUtc(utc, AUSTimeZone);

// The Aus Offset from UTC is not correct 
Console.WriteLine(AUSDateTimeOffset.ToString("dd MM yyyy HH:mm zzz"));

The output is 18 06 2020 01:00 +01:00 output 是 18 06 2020 01:00 +01:00

Aus are 10 hours ahead of UTC (9 hours ahead of GMT) so the date and time are correct, but not the offset. Aus 比 UTC 早 10 小时(比 GMT 早 9 小时),因此日期和时间是正确的,但不是偏移量。

How can I get the correct offset in AUSDateTimeOffset?如何在 AUSDateTimeOffset 中获得正确的偏移量?

The error is in this part:错误在这部分:

var AUSDateTimeOffset = TimeZoneInfo.ConvertTimeFromUtc(utc, AUSTimeZone);

In that code, utc is a DateTime , and thus the resulting AUSDateTimeOffset is actually a DateTime .在该代码中, utcDateTime ,因此生成的AUSDateTimeOffset实际上是DateTime Its Kind will be DateTimeKind.Unspecified .它的Kind将是DateTimeKind.Unspecified

The conversion will have been done correctly, and thus you see the correct date and time in the result.转换将正确完成,因此您会在结果中看到正确的日期和时间。 However, the offset is wrong because it is not part of a DateTime .但是,偏移量是错误的,因为它不是DateTime的一部分。 The documentation about the zzz specifier says: 关于zzz说明符的文档说:

With DateTime values, the "zzz" custom format specifier represents the signed offset of the local operating system's time zone from UTC, measured in hours and minutes.对于DateTime值,“zzz”自定义格式说明符表示本地操作系统时区与 UTC 的有符号偏移量,以小时和分钟为单位。 It doesn't reflect the value of an instance's DateTime.Kind property.它不反映实例的DateTime.Kind属性的值。 For this reason, the "zzz" format specifier is not recommended for use with DateTime values.因此,不建议将“zzz”格式说明符与DateTime值一起使用。

Thus, the +01:00 is coming from your local time zone, not from the target time zone.因此, +01:00来自您当地的时区,而不是来自目标时区。

There are a few ways you could fix this:有几种方法可以解决此问题:

  • You could make AUSDateTimeOffset a DateTimeOffset with the correct offset:您可以使用正确的偏移量将AUSDateTimeOffset DateTimeOffset

     DateTime AUSDateTime = TimeZoneInfo.ConvertTimeFromUtc(utc, AUSTimeZone); TimeSpan AUSOffset = AUSTimeZone.GetUtcOffset(utc); DateTimeOffset AUSDateTimeOffset = new DateTimeOffset(AUSDateTime, AUSOffset);
  • You could use a UTC-based DateTimeOffset instead of a UTC-based DateTime :您可以使用基于 UTC 的DateTimeOffset而不是基于 UTC 的DateTime

     DateTimeOffset utc = UKdateTimeOffset.ToUniversalTime(); DateTimeOffset AUSDateTimeOffset = TimeZoneInfo.ConvertTime(utc, AUSTimeZone);
  • You could just convert the orignal DateTimeOffset , as there's no need to convert to UTC first:您可以只转换原始DateTimeOffset ,因为无需先转换为 UTC:

     DateTimeOffset AUSDateTimeOffset = TimeZoneInfo.ConvertTime(UKdateTimeOffset, AUSTimeZone);
  • As Jimi pointed out in comments, you can even convert without constructing a TimeZoneInfo object at all:正如 Jimi 在评论中指出的那样,您甚至可以在不构建TimeZoneInfo object 的情况下进行转换:

     DateTimeOffset AUSDateTimeOffset = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(UKdateTimeOffset, "AUS Eastern Standard Time");

Any of the above will give the same, correct response.以上任何一项都会给出相同的正确响应。

You can create new offset and use it -您可以创建新的偏移量并使用它 -

    // Create new offset for UTC
    var AUSOffset = new DateTimeOffset(utc, TimeSpan.Zero);

    // Declare Aus Time as DateTimeOffset
    var AUSDateTimeOffset = UKdateTimeOffset.ToOffset(AUSTimeZone.GetUtcOffset(AUSOffset));                              
    Console.WriteLine(AUSDateTimeOffset.ToString("dd MM yyyy HH:mm zzz"));

Or:或者:

Use ConvertTimeBySystemTimeZoneId as suggested by Jimi in the comment!按照 Jimi 在评论中的建议使用ConvertTimeBySystemTimeZoneId

    var finalDate = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(UKdateTimeOffset, "AUS Eastern Standard Time");
    Console.WriteLine(finalDate.ToString("dd MM yyyy HH:mm zzz"));

It's easy to get around:很容易绕过:

var fromTime = DateTimeOffset.Parse("2020-06-17T16:00:00+01:00");
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time");//TZConvert.GetTimeZoneInfo("Australia/Sydney");//for Mac
var toTime = fromTime.ToOffset(timeZoneInfo.GetUtcOffset(fromTime.UtcDateTime));
Console.Write(toTime.ToString("yyyy-MM-ddTHH:mm:sszzz")); //2020-06-18T01:00:00+10:00

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM