【问题标题】:Error converting from datetime UTC to datetimeoffset when kind is Utc当 kind 为 Utc 时,从 datetime UTC 转换为 datetimeoffset 时出错
【发布时间】:2016-07-22 21:26:58
【问题描述】:

将 UTC 中的 DateTime 转换为 DateTimeOffset 时出错 当种类是UTC时。 origDateTime 来自网络服务,因此我无法控制内容或格式。 在大多数情况下,它带有 Kind=Unspecified (即使是艰难的时间在 Utc 中)然后它就可以工作,但在极少数情况下 Kind=Utc 然后转换为 DateTimeOffset 抛出异常: "Utc DateTime 实例的 UTC 偏移量必须为 0。\r\n参数名称: 偏移量" 我该如何解决?

        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;
        }

【问题讨论】:

  • DataTime Parse 使用时区设置自动转换为 UTC 时间,因此无需转换。与数据库的连接也会自动使用 UTC 时间,因此您的代码没有多大意义。仅当输入在另一个时区收集的数据或要在另一个时区显示时间时才使用时区偏移量。 Net库函数将时间以UTC数字形式存储在计算机中,并在输入或输出时自动转换为UTC。
  • 我需要使用不同的时区(根据另一个字段)将每个日期时间转换为日期时间偏移量,以便能够在不同的时区显示。泽维尔的回答解决了这个问题。谢谢。

标签: c# datetime timezone datetimeoffset


【解决方案1】:

一些事情:

  • 如果您确实需要在不调整其值的情况下切换DateTimeKind,请使用DateTime.SpecifyKind。它比处理蜱更清洁。不过,我认为你真的不需要这样做。

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

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

    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);
    

【讨论】:

  • 字符串的使用只是为了测试目的,ToUniversalTime也是如此。这只是为了模拟来自服务器的数据。你能解释一下我在构造函数 DateTimeOffset localTime = new DateTimeOffset(origDateTime, localTimeZone.GetUtcOffset(origDateTime)) 中添加偏移量的区别吗?以及使用 ConvertTime 的代码?
  • 我看到了不同之处,您的代码确实采用日期并将其修改为 {4/2/2016 11:25:20 AM -07:00} 根据定义我只需要进行偏移,否则我会使用你的代码。谢谢。
  • DateTimeOffset 中的日期和时间是 本地 时间,已针对该偏移量进行了调整。这不仅仅是一个 .NET 的东西——它是 ISO8601 约定的。时间戳2016-04-02T18:25:20+00:00 等价于2016-04-02T11:25:20-07:00。如果您只是应用偏移量而不调整时间值,那么您实际上指的是完全不同的时间点。
  • 看来你是对的,非常感谢你的洞察力。这对我帮助很大。既然我使用了您的代码,如何在不考虑夏令时的情况下转换为当地时间?使用偏移量,以防我只有没有日期的时间 ​​- 按最小年份的日期传递给我,例如 {1/1/0001 2:00:00 PM} 我使用了以下内容:localTime = new DateTimeOffset(origDateTime, localTimeZone .BaseUtcOffset);我怎样才能对你的代码做类似的事情?
  • 为什么您希望它考虑夏令时?这是在指定区域中实际遵循的时间。将没有日期的时间转换为不同的时区是无稽之谈。你必须选择一些日期来修复它。
【解决方案2】:

因此,如果您始终将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;
        }

【讨论】:

    猜你喜欢
    • 2012-12-05
    • 2014-12-05
    • 1970-01-01
    • 2011-09-29
    • 2011-02-02
    • 1970-01-01
    • 2021-02-14
    • 1970-01-01
    • 2011-02-11
    相关资源
    最近更新 更多