使用 NodaTime

问题描述

这是我第一次拿起 NodaTime 很长一段时间。

虽然围绕这个领域存在一些问题,但我只想让这个问题专注于使用 NodaTime 将字符串解析为某些日期时间对象。因此,我正在考虑处理分别包含 GMT 和 BST 的字符串。

奇怪的是,关于 BST 的一些琐事 here 有两种不同的含义。在我们的旧 Java 系统中,我们在大量自定义代码中使用 BST 和 GMT。

所以,我整理了一些快速而肮脏的测试来让我开始。最后一个测试用例失败了。

[Theory]
[InlineData("2021-03-28 00:00:00 GMT")]
[InlineData("2021-03-28 02:00:00 GMT")]
[InlineData("2021-03-28 02:00:00 BST")]
public void parsing_dates(string dateString)
{
    ZonedDateTimePattern pattern = ZonedDateTimePattern.CreateWithInvariantCulture("yyyy'-'MM'-'dd HH':'mm':'ss z",DateTimeZoneProviders.Tzdb);
    
    ParseResult<ZonedDateTime> parseResult = pattern.Parse(dateString);

    if (!parseResult.Success)
    {
        testOutputHelper.WriteLine(parseResult.Exception.ToString());
    }
    else
    {
        testOutputHelper.WriteLine(parseResult.Value.ToInstant().ToString());
    }
    
    parseResult.Success.Should().BeTrue();
}

带有“2021-03-28 02:00:00 BST”字符串的异常:

NodaTime.Text.UnparsableValueException: The specified time zone identifier is not recognized. Value being parsed: '2021-03-28 02:00:00 ^BST'. (^ indicates error position.)

我疲惫地浏览了文档,似乎找不到我要找的东西。
https://nodatime.org/3.0.x/userguide/text
https://nodatime.org/3.0.x/userguide/zoneddatetime-patterns

有没有办法将 GMT 和 BST 解析为 ZonedDateTime?

解决方法

不,解析时不能使用缩写。它们是模棱两可的,而且通常以各种方式可怕。 (“GMT”在这里是一个特例 - IANA 确实 将其作为时区 ID 包含在内,但我仍然建议避免使用它。)如果您可以以更好的方式获取数据,那么会很棒。

否则,您需要在请求 Noda Time 解析数据之前调整数据。

如果您的数据总是在欧洲/伦敦时区,并且只是“BST”或“GMT”,那么您可以基于此调整您的输入(包括用于消除歧义的 UTC 偏移量) ) 然后解析调整后的版本。

这是一个完整的例子。请注意,我不得不调整您的测试数据,因为“2021-03-28 02:00:00 GMT”无效。下面的示例显示了三月过渡前的一分钟、三月过渡的瞬间……以及十月的消歧。

using NodaTime;
using NodaTime.Text;
using System;

class Program
{
    static void Main()
    {
        string[] inputs =
        {
            "2021-03-28 00:00:00 GMT","2021-03-28 00:59:00 GMT","2021-03-28 02:00:00 BST","2021-10-31 01:59:00 BST","2021-10-31 01:59:00 GMT"
        };
        foreach (var input in inputs)
        {
            TweakAndParse(input);
        }
    }

    private static readonly ZonedDateTimePattern pattern =
        ZonedDateTimePattern.CreateWithInvariantCulture(
            "uuuu-MM-dd HH:mm:ss z '('o<g>')'",DateTimeZoneProviders.Tzdb);

    static void TweakAndParse(string input)
    {
        string tweaked = input.EndsWith("GMT") ? input[..^3] + "Europe/London (+00)"
            : input.EndsWith("BST") ? input[..^3] + "Europe/London (+01)"
            : throw new ArgumentException("Unexpected input");

        ZonedDateTime zdt = pattern.Parse(tweaked).Value;
        Console.WriteLine($"{input} => {zdt.ToInstant()}");
    }
}

输出:

2021-03-28 00:00:00 GMT => 2021-03-28T00:00:00Z
2021-03-28 00:59:00 GMT => 2021-03-28T00:59:00Z
2021-03-28 02:00:00 BST => 2021-03-28T01:00:00Z
2021-10-31 01:59:00 BST => 2021-10-31T00:59:00Z
2021-10-31 01:59:00 GMT => 2021-10-31T01:59:00Z

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...