Элегантный способ конвертировать отметку времени эпохи в восточное время и обратно с помощью Nodatime

Я работаю над написанием управляемой оболочки для API реального времени Управления транспорта Массачусетского залива (MBTA). У них есть API, который возвращает время сервера, которое является временной меткой unix (эпохой). Библиотека, в которой я это реализую, — PCL Profile 78, что означает, что у меня ограниченная поддержка BCL TimeZone, поэтому я прибегнул к использованию Nodatime

Я пытаюсь преобразовать время, возвращаемое с сервера, в восточное время, которое America/New_York является объектом DateTime и наоборот. Мой текущий код очень грязный

public static class TimeUtils
{
    static readonly DateTimeZone mbtaTimeZone = DateTimeZoneProviders.Tzdb["America/New_York"];
    static readonly DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

    public static DateTime GetMbtaDateTime (long unixTimestamp)
    {
        var mbtaEpochTime = epoch.AddSeconds (unixTimestamp);
        var instant = Instant.FromUtc (mbtaEpochTime.Year, mbtaEpochTime.Month,
            mbtaEpochTime.Day, mbtaEpochTime.Hour, mbtaEpochTime.Minute, mbtaEpochTime.Second);
        var nodaTime = instant.InZone (mbtaTimeZone);
        return nodaTime.ToDateTimeUnspecified ();
    }

    public static long MbtaDateTimeToUnixTimestamp (DateTime time)
    {
        TimeSpan secondsSinceEpochMbtaTz = time - epoch;
        var instant = Instant.FromUtc (time.Year, time.Month, time.Day, time.Hour, time.Minute, time.Second);
        var mbtaTzSpan = mbtaTimeZone.GetUtcOffset (instant).ToTimeSpan ();
        var epochDiff = secondsSinceEpochMbtaTz - mbtaTzSpan;
        return (long)epochDiff.TotalSeconds;
    }
}

Есть ли другой способ написать это просто. Я надеюсь, что Nodatime должен поддерживать преобразование времени эпохи в America/New_York DateTime и America/New_York DateTime в время эпохи. Мой метод MbtaDateTimeToUnixTimestamp - брутальный взлом


person Manish Sinha    schedule 01.11.2014    source источник
comment
Вам действительно нужно использовать DateTime вообще? Noda Time работает лучше всего, когда вы используете его во всем коде.   -  person Jon Skeet    schedule 01.11.2014


Ответы (1)


Во-первых, как упоминалось в комментариях, было бы лучше использовать типы Noda Time во всем коде — прибегайте к DateTime только тогда, когда вам действительно нужно. Это должно привести к значительно более чистому коду.

Преобразование временной метки Unix в Instant очень просто:

Instant instant = Instant.FromUnixTimeSeconds(seconds);

Затем вы можете преобразовать в ZonedDateTime в соответствии с вашим текущим кодом... и использование ToDateTimeUnspecified прекрасно, если вам действительно нужно использовать DateTime.

Что касается обратного, ваш текущий код выглядит для меня сломанным - вы предполагаете, что DateTime является значением UTC, фактически. Это противоречило бы вашему более позднему использованию часового пояса. Я подозреваю, что вы хотите преобразовать ввод в LocalDateTime, а затем применить часовой пояс. Например:

public static long MbtaDateTimeToUnixTimestamp(DateTime time)
{
    var local = LocalDateTime.FromDateTime(time);
    var zoned = local.InZoneStrictly(mbtaTimeZone);
    var instant = zoned.ToInstant();
    return instant.Ticks / NodaConstants.TicksPerSecond;
}

Обратите внимание на вызов InZoneStrictly. Это вызовет исключение, если вы передадите местное время, которое не существовало, или, которое существовало дважды — в обоих случаях из-за перехода на летнее время. Это вполне может быть не тем, что вам нужно — вам действительно нужно подумать о том, что вы хотите, чтобы произошло в таких случаях, или постараться избежать их реализации. Дополнительную информацию и опции.

person Jon Skeet    schedule 01.11.2014
comment
FromSecondsSinceUnixEpoch больше не определяется в Instance. РЕДАКТИРОВАТЬ: теперь он содержит файл FromUnixTimeSeconds. - person Crouching Kitten; 03.08.2020