Анализ строк даты и времени, содержащих BST и GMT, с помощью NodaTime

Это первый раз, когда я выбрал NodaTime за долгое время.

Хотя в этой области есть некоторые вопросы, я просто хотел, чтобы этот вопрос был сосредоточен на синтаксическом анализе строк для некоторых объектов даты и времени с использованием NodaTime. Таким образом, я рассматриваю работу со строками, содержащими GMT и BST соответственно.

Любопытно, что здесь есть кое-что о BST, имеющее два разных значения. В нашей устаревшей системе 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?


person Andez    schedule 27.02.2021    source источник
comment
Не зная NodaTime, вы можете попробовать культуру, в которой вы знаете, что BST и GMT называются так.   -  person Ole V.V.    schedule 27.02.2021


Ответы (1)


Нет, при разборе нельзя использовать сокращения. Они неоднозначны и, как правило, ужасны по-разному. (Здесь особый случай — GMT — IANA включает его в качестве идентификатора часового пояса, но я все же рекомендую избегать его.) Если вы можете получить свои данные лучшим способом, это будет здорово.

В противном случае вам нужно будет настроить свои данные, прежде чем просить 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
person Jon Skeet    schedule 01.03.2021
comment
Отлично, спасибо Джон. Спасибо, что включили октябрьские изменения часов. - person Andez; 01.03.2021