Вопрос по nodatime, timezone, timezone-offset, c#, datetime – Преобразование между часовыми поясами с помощью Noda Time

14

В настоящее время я пытаюсь убедиться, что наш унаследованный бэкэнд может поддерживать разрешение времени на основе данных пользователя.s текущий часовой пояс (или, более конкретно, смещение). Наши серверы находятся в восточном стандартном времени, и большинство наших дат происходит там. Однако для пользователей, которые находятся в других часовых поясах, преобразование в их часовой пояс (или, в этом случае, смещение) необходимо при получении этих дат. Кроме того, даты, приходящие от пользователя, должны быть переведены в восточное стандартное время перед сохранением на сервере. Учитывая, что интерфейс, который мы разрабатываем, является веб-интерфейсом, я могу получить пользователя.смещение в минутах и передать это значение в мой сервисный слой в заголовке. Я посмотрел на Noda Time и думаю, чтоотличный API. Это заставило меня задуматься о времени в более утонченном вопросе, но я все еще не уверен на 100%, что ямы правильно использовали его правильно. Вот методы, которые я написал для преобразований, описанных выше. Я'Я проверил их, и они, кажется, работают. Учитывая сценарий выше, похоже ли это на правильное использование библиотеки? Я правильно думаю о дате?

public static DateTime ConvertToUtcFromEasternTimeZone(DateTime easternDateTime)
{
    NodaTime.DateTimeZone easternTimeZone = NodaTime.DateTimeZoneProviders.Tzdb.GetZoneOrNull("America/New_York");
    ZoneLocalMappingResolver customResolver = Resolvers.CreateMappingResolver(Resolvers.ReturnLater, Resolvers.ReturnStartOfIntervalAfter);
    var easternLocalDateTime = LocalDateTime.FromDateTime(easternDateTime);
    var easternZonedDateTime = easternTimeZone.ResolveLocal(easternLocalDateTime, customResolver);
    return easternZonedDateTime.ToDateTimeUtc();
}

public static DateTime ConvertToEasternTimeZoneFromUtc(DateTime utcDateTime)
{
    NodaTime.DateTimeZone easternTimeZone = NodaTime.DateTimeZoneProviders.Tzdb.GetZoneOrNull("America/New_York");
    NodaTime.DateTimeZone utcTimeZone = NodaTime.DateTimeZoneProviders.Tzdb.GetZoneOrNull("UTC");
    ZoneLocalMappingResolver customResolver = Resolvers.CreateMappingResolver(Resolvers.ReturnLater, Resolvers.ReturnStartOfIntervalAfter);
    var utcLocal = LocalDateTime.FromDateTime(utcDateTime);
    var utcZonedDateTime = utcTimeZone.ResolveLocal(utcLocal, customResolver);
    var easternZonedDateTime = utcZonedDateTime.ToInstant().InZone(easternTimeZone);
    return easternZonedDateTime.ToDateTimeUnspecified();
}

public static DateTime ConvertToUtc(DateTime dateTime, int offsetInMinutes)
{
    LocalDateTime localDateTime = LocalDateTime.FromDateTime(dateTime);
    var convertedDateTime = localDateTime.PlusMinutes(offsetInMinutes).ToDateTimeUnspecified();
    return convertedDateTime;
}

public static DateTime ConvertFromUtc(DateTime dateTime, int offsetInMinutes)
{
    LocalDateTime localDateTime = LocalDateTime.FromDateTime(dateTime);
    var convertedDateTime = localDateTime.PlusMinutes(-offsetInMinutes).ToDateTimeUnspecified();
    return convertedDateTime;
}

Идея в том, что часовой пояс имеет значение, когда ям разрешение между временем UTC и часовым поясом в базе данных. Когда я'После разрешения времени клиента и времени UTC смещение имеет значение.

В будущем мы можем сохранять время UTC, и это будет легче. В настоящее время это решение является пробелом.

Идея в том, что мы собираемся идти от ...

клиент -> UTC +/- смещение -> UTC -> Восточное время -> база данных

база данных -> Восточное время -> UTC -> UTC +/- смещение -> клиент

в конце концов ...

клиент -> UTC +/- смещение -> UTC -> база данных

база данных -> UTC -> UTC +/- смещение -> клиент

Когда ты сказал "наши серверы в восточном стандартном времени Вы действительно имеете в виду "наши серверы в восточном времени (варьируется между EST и EDT в течение года)? Это имеет значение. Jon Skeet
Да, Джон Спасибо за разъяснения. Мне нужно учитывать летнее время. PureCognition

Ваш Ответ

1   ответ
35

Ваш первый метод выглядит хорошо, хотя мы нене знаю чтоcustomResolver является.

Ваш второй метод немного не подходит. Я'буду предлагать:

public static DateTime ConvertToEasternTimeZoneFromUtc(DateTime utcDateTime)
{
    var easternTimeZone = DateTimeZoneProviders.Tzdb["America/New_York"];
    return Instant.FromDateTimeUtc(utcDateTime)
                  .InZone(easternTimeZone)
                  .ToDateTimeUnspecified();
}

Обратите внимание, что вы неt нужно искать восточный часовой пояс при каждом вызове метода - просто имейте:

private static readonly DateTimeZone EasternTimeZone = 
    DateTimeZoneProviders.Tzdb["America/New_York"];

... тогда используйте это везде.

Ваш третий и четвертый методы нет яя думаю, что идиоматический - для третьего метода вы должны использовать:

public static DateTime ConvertToUtc(DateTime dateTime, int offsetInMinutes)
{
    var offset = Offset.FromMinutes(offsetInMinutes);
    var localDateTime = LocalDateTime.FromDateTime(dateTime);
    return new OffsetDateTime(localDateTime, offset).ToInstant()
                                                    .ToDateTimeUtc();
}

Четвертый метод кажется немного сложнее, так как мы нет все, что мы должны с точки зрения конверсий сOffsetDateTime, Код выЯ использовал, вероятно, хорошо, но это было бы чище, если бы вы могли использовать.OffsetDateTime

РЕДАКТИРОВАТЬ: ЯТеперь мы добавили методInstant сделать четвертый метод чище. Это будет часть 1.2.0, и вы можете использовать:

public static DateTime ConvertFromUtc(DateTime dateTime, int offsetInMinutes)
{
    var offset = Offset.FromMinutes(offsetInMinutes);
    var instant = Instant.FromDateTimeUtc(dateTime);
    return instant.WithOffset(offset)
                  .LocalDateTime
                  .ToDateTimeUnspecified();
}
Большое спасибо, Джон. Честно говоря, яЯ немного неясен относительно работы резольверов. Казалось, исходя из того, что яЧитали, что их можно использовать для учета перехода на летнее время. Тем не менее, я заметил, что вы неиспользовать его в вашей реализации ConvertToEasternTimeZoneFromUtc (). Я заинтересован в учете перехода на летнее время для преобразований между сохраненной датой и временем UTC. Я нене нужно беспокоиться об этом для преобразования между временем UTC и временем клиента, так как ям смещение в минутах от клиента (что неявно учитывает его DST). PureCognition
Кроме того, версия библиотеки у меня нетt Offset.FromMinutes (). Так что я'мы преобразовали его в Offset.FromHoursAndMinutes (0, offsetInMinutes). PureCognition

Похожие вопросы