Конверсии NodaTime (часть 2). Как?

После моего первого сообщения:

Преобразование DateTime с использованием NodaTime на веб-сайте ASP.Net MVC 3 Razor. Как?

Я пытаюсь найти простой способ конвертировать дату/время между локальным и UTC (в обоих направлениях), используя NodaTime.

Текущее изображение:

  • У меня есть дата/время, сохраненное как UTC в базе данных.
  • При отображении его пользователю я должен учитывать локальный часовой пояс и соответствующим образом преобразовывать его.
  • Когда пользователь предоставляет дату/время в качестве фильтра, мне нужно его вернуть обратно в UTC перед отправкой в ​​SQL-запрос.

Что я до сих пор:

Расширение для преобразования из UTC в локальный (эта часть работает нормально):

    public static DateTime UTCtoLocal(this DateTime dateTime)
    {
        IDateTimeZoneProvider timeZoneProvider = DateTimeZoneProviders.Tzdb;

        var utcTimeZone = timeZoneProvider["UTC"];
        var dateTimeFromDb = new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, dateTime.Hour, dateTime.Minute, dateTime.Second, dateTime.Millisecond);

        var zonedDbDateTime = utcTimeZone.AtLeniently(LocalDateTime.FromDateTime(dateTimeFromDb));

        var usersTimezoneId = "Europe/London"; //just an example
        var usersTimezone = timeZoneProvider[usersTimezoneId];

        var usersZonedDateTime = zonedDbDateTime.WithZone(usersTimezone);

        return usersZonedDateTime.ToDateTimeUnspecified();
    }

Расширение для преобразования из локальной базы в UTC (эта часть является проблемой):

    public static DateTime LocaltoUTC(this DateTime dateTime)
    {
        IDateTimeZoneProvider timeZoneProvider = DateTimeZoneProviders.Tzdb;
        var usersTimezoneId = "Europe/London";
        var usersTimezone = timeZoneProvider[usersTimezoneId];

        var dateTimeFromDb = new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, dateTime.Hour, dateTime.Minute, dateTime.Second, dateTime.Millisecond);
        var zonedDbDateTime = usersTimezone.AtLeniently(LocalDateTime.FromDateTime(dateTimeFromDb));

        var utcTimezoneId = "UTC";
        var utcTimezone = timeZoneProvider[utcTimezoneId];

        var utcZonedDateTime = zonedDbDateTime.WithZone(utcTimezone);

        return utcZonedDateTime.ToDateTimeUtc();
    }

Что я здесь делаю неправильно?

Ответы

Ответ 1

Ваш UTCToLocal выглядит, как будто он делает больше работы, чем нужно, если честно.

Это должно быть просто:

// Note: the DateTime here must have a "Kind" of Utc.
public static DateTime UTCtoLocal(this DateTime dateTime)
{
    Instant instant = Instant.FromDateTimeUtc(dateTime);
    IDateTimeZoneProvider timeZoneProvider = DateTimeZoneProviders.Tzdb;
    var usersTimezoneId = "Europe/London"; //just an example
    var usersTimezone = timeZoneProvider[usersTimezoneId];
    var usersZonedDateTime = instant.InZone(usersTimezone);
    return usersZonedDateTime.ToDateTimeUnspecified();
}

Аналогично, ваш LocalToUTC должен быть в следующих строках:

// The DateTime here should have a "Kind" of Unspecified
public static DateTime LocaltoUTC(this DateTime dateTime)
{
    LocalDateTime localDateTime = LocalDateTime.FromDateTime(dateTime);

    IDateTimeZoneProvider timeZoneProvider = DateTimeZoneProviders.Tzdb;
    var usersTimezoneId = "Europe/London";
    var usersTimezone = timeZoneProvider[usersTimezoneId];

    var zonedDbDateTime = usersTimezone.AtLeniently(localDateTime);
    return zonedDbDateTime.ToDateTimeUtc();
}

Вам не нужно преобразовывать его в другой часовой пояс: ZonedDateTime знает, что это такое, и ToDateTimeUtc будет делать все правильно. Обратите внимание, что здесь нет реального dateTimeFromDb, потому что если вы переходите от неуказанного DateTime, предположительно от пользователя...