当 kind 为 Utc 时从日期时间 UTC 转换为 datetimeoffset 时出错

Error converting from datetime UTC to datetimeoffset when kind is Utc

将 UTC 格式的 DateTime 转换为 DateTimeOffset 时出错 当种类是 Utc 时。 origDateTime 来自网络服务,所以我无法控制内容或格式。 在大多数情况下,它带有 Kind=Unspecified (即使时间在 Utc 中也很艰难)然后它就可以工作,但在极少数情况下 Kind=Utc 然后转换为 DateTimeOffset 抛出异常: "The UTC Offset for Utc DateTime instances must be 0.\r\nParameter name: offset" 我该如何解决?

        try {

            //cause error !!!!
            DateTime databaseUtcTime = DateTime.Parse("4/2/2016 6:25:20 PM");
            var localTimeTemp = databaseUtcTime.ToLocalTime();
            DateTime origDateTime = localTimeTemp.ToUniversalTime();

            //this is working
            //DateTime origDateTime = DateTime.Parse("4/2/2016 6:25:20 PM");

            string timeZoneName = "Pacific Standard Time";
            TimeZoneInfo localTimeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneName);
            DateTimeOffset localTime = new DateTimeOffset(origDateTime, localTimeZone.GetUtcOffset(origDateTime));
            return localTime;
        }
        catch (Exception ex) {
            string msg = ex.Message;
            return null;
        }

因此,如果您始终将 DateTimeKind 设置为 Unspecified,您的问题就会得到解决,不是吗?

试试这个:

DateTime origDateTime = new DateTime(origDateTimeUnspecifiedKind.Ticks, DateTimeKind.Unspecified);

与您的示例集成:

        try
        {

            //cause error !!!!
            DateTime databaseUtcTime = DateTime.Parse("4/2/2016 6:25:20 PM");
            var localTimeTemp = databaseUtcTime.ToLocalTime();
            DateTime origDateTimeUnspecifiedKind = localTimeTemp.ToUniversalTime();

            // FIX: specify the kind
            DateTime origDateTime = new DateTime(origDateTimeUnspecifiedKind.Ticks, DateTimeKind.Unspecified);

            //this is working
            //DateTime origDateTime = DateTime.Parse("4/2/2016 6:25:20 PM");

            string timeZoneName = "Pacific Standard Time";
            TimeZoneInfo localTimeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneName);
            DateTimeOffset localTime = new DateTimeOffset(origDateTime, localTimeZone.GetUtcOffset(origDateTime));
            return localTime;
        }
        catch (Exception ex)
        {
            string msg = ex.Message;
            return null;
        }

几件事:

  • 如果你真的需要切换DateTimeKind而不调整它的值,使用DateTime.SpecifyKind。它比处理蜱虫更干净。不过,我认为你真的不需要这样做。

  • 不要使用 ToLocalTimeToUniversalTime。这两个都会在转换过程中使用服务器的时区设置。

  • 我不确定您的真实代码是否真的在解析字符串,因为您指出它来自数据库。如果它来自数据库,则不应涉及字符串解析。只需执行以下操作:

    DateTime databaseUtcTime = (DateTime) yourDataReader["YourDataField"];
    
  • 输入后,您可以使用 TimeZoneInfo.ConvertTime 函数进行转换。您现有的代码没有正确转换时间,它只是分配了一个偏移量而没有正确调整时间值。

    由于您希望输出为 datetimeoffset,因此最简单的方法是首先将输入 datetime 转换为偏移量为零的 datetimeoffset(因为它来自来自 UTC)。

    DateTimeOffset dtoUtc = new DateTimeOffset(databaseUtcTime, TimeSpan.Zero);
    

    那么转换起来就相当简单了:

    string timeZoneName = "Pacific Standard Time";
    TimeZoneInfo localTimeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneName);
    DateTimeOffset dtoLocal = TimeZoneInfo.ConvertTime(dtoUtc, localTimeZone);