【问题标题】:Parse String into DateTimeOffset While Assuming TimeZone假设 TimeZone 时将字符串解析为 DateTimeOffset
【发布时间】:2020-11-19 01:20:34
【问题描述】:

可能是一个超级简单的解决方案,但我显然遗漏了一些东西。

我有一个值为“2020/07/29 13:30:00”的字符串对象。

如何将其解析为 DateTimeOffset 对象,并假设该解析时间的时区是“GMT 标准时间”,或者我希望指定的任何 TimeZoneInfo?

然后我怎样才能获取该 DateTimeOffset,并将其 Utc 时间返回到我选择的任何指定时区?

非常感谢

【问题讨论】:

    标签: c# datetime timezone datetimeoffset


    【解决方案1】:

    尝试接受DateTimeStyles 参数的DateTimeOffset.ParseExact 重载。

    这段代码:

    var dt=DateTimeOffset.ParseExact("2020/07/29 13:30:00","yyyy/MM/dd HH:mm:ss",
                         CultureInfo.InvariantCulture,DateTimeStyles.AssumeUniversal);
    

    返回2020-07-29T13:30:00.0000000+00:00

    没有GMT Standard Time,这是 Windows 中使用的一个非常不幸的名称,它以某种方式设法混淆了英国时间和 UTC 时间,以至于没有人不看文档就知道它的含义。在这个问题中对此进行了彻底的讨论和解释:Difference between UTC and GMT Standard Time in .NET。正如其中一个答案所解释的那样:

    格林威治标准时间和格林威治标准时间的名称在雷德蒙德之外是未知的。它们是只出现在名为 Windows 注册表的动物寓言中的神话动物。

    如果您想假设英国时间并且您的机器使用英国时区,您可以使用DateTimeStyles.AssumeLocal

    【讨论】:

    • 嘿 Panagiotis,而不是 DateTimeStyles.AssumeUniversal,是否可以指定 TimeZoneInfo?
    • 为什么?你问了格林威治标准时间。这是UTC 的另一个名称。还是您的意思是英国时间?你可以使用AssumeLocal
    • @PanagiotisKanavos “GMT 标准时间”实际上是欧洲/伦敦时区的 Windows 名称 - 即它是伦敦所在的任何时间。它在夏季切换到“GMT 夏令时间”。这与众所周知的“GMT”时区不同
    • @canton7 我已经添加了该讨论的链接和答案的摘录
    • 对,但我认为这不能回答 OP 的问题?我将问题解释为“鉴于在欧洲/伦敦工作的人记录的这个具有历史意义的挂钟时间,我如何将其转换为 DateTimeOffset / 转换为等效的 UTC 时间”
    【解决方案2】:

    我能找到的最简单的就是这样的。

    我找不到在特定给定时区解析DateTimeOffset 的任何方法,但您可以将您的字符串解析为DateTime(使用UnspecifiedKind,它只是充当容器对于字符串中的信息位,而不是尝试对其应用时区知识)。

    然后您可以在给定本地时间向TimeZoneInfo 询问给定时区的UTC 偏移量,并将其应用于DateTime 以创建DateTimeOffset

    获得DateTimeOffset 后,您可以使用它的ToOffset 方法和TimeZoneInfo.ConvertTime 来处理它。

    string input = "2020/07/29 13:30:00";
    var timezone = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
    
    // DateTime.Parse creates a DateTime with Kind == Unspecified
    var dateTime = DateTime.Parse(input);
    Console.WriteLine(dateTime); // 7/29/2020 1:30:00 PM
    
    // Since Kind == Unspecified, timezone.GetUtcOffset will give us the UTC offset in effect at
    // the given local time in timezone
    var dateTimeOffset = new DateTimeOffset(dateTime, timezone.GetUtcOffset(dateTime));
    Console.WriteLine(dateTimeOffset); // 7/29/2020 1:30:00 PM +01:00
    
    // Convert to UTC
    Console.WriteLine(dateTimeOffset.UtcDateTime); // 7/29/2020 12:30:00 PM
    Console.WriteLine(dateTimeOffset.ToOffset(TimeSpan.Zero)); // 7/29/2020 12:30:00 PM +00:00
    
    // Convert to another timezone
    var cst = TimeZoneInfo.FindSystemTimeZoneById("Central America Standard Time");
    Console.WriteLine(TimeZoneInfo.ConvertTime(dateTimeOffset, cst)); // 7/29/2020 6:30:00 AM -06:00
    

    【讨论】:

    • 嘿 Canton7,我刚刚测试了这个,这正是我想要的,谢谢!这似乎是完全可靠和可预测的:)
    • 一般来说,这是一个不错的方法。但是,有一个问题:输入的日期时间可能无效或不明确。这发生在转换附近,例如夏令时的开始或结束,或标准时间的变化。看看我作为this answer 的一部分提供的ToDateTimeOffset 扩展方法。它处理这些边缘情况。
    • 仅供参考 - GetUtcOffset 的默认行为与无效或不明确的时间是返回 标准时间 偏移量。将其与无效的日期时间相结合会导致给定时区中实际不存在的日期时间偏移量。将它与不明确的日期时间相结合会产生一个日期时间偏移量,它表示回退转换期间的 第二次 次出现,而在大多数情况下,您会想要 第一次 次出现。
    【解决方案3】:

    此函数应将您的日期时间字符串(假设这是 GMT 标准时间)转换为任何其他时区:

        public static DateTime? ToUTCTimeZone(string sDate, string timeZone)
        {
    
            DateTime utcDate = DateTime.Parse(sDate);
    
            DateTimeOffset localServerTime = DateTimeOffset.Now;
            utcDate = DateTime.SpecifyKind(utcDate, DateTimeKind.Utc);
    
            TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById(timeZone);
            if (cstZone == null)
                return null;
    
            return TimeZoneInfo.ConvertTimeFromUtc(utcDate, cstZone);
    
        }//ToUTCTimeZone
    

    【讨论】:

      猜你喜欢
      • 2018-12-16
      • 1970-01-01
      • 2010-12-08
      • 1970-01-01
      • 1970-01-01
      • 2018-10-28
      • 2019-09-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多