Элегантный способ конвертировать временную метку эпохи в восточное и обратно с помощью 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
это жестокий взлом
1 ответ
Во-первых, как уже упоминалось в комментариях, было бы лучше использовать типы кода Noda во всем коде - прибегать только к DateTime
когда ты действительно должен. Это должно привести к значительно более чистому коду.
Преобразование метки времени Unix в Instant
это действительно легко:
Instant instant = Instant.FromSecondsSinceUnixEpoch(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
вызов. Это вызовет исключение, если вы либо укажете местное время, которого не было, либо время, которое существовало дважды - в обоих случаях из-за переходов DST. Возможно, это не то, чего вы хотите - вам действительно нужно подумать о том, что вы хотите, чтобы произошло в этих случаях, или попытаться избежать их осуществимости. См. Раздел часовых поясов документации для более подробной информации и опций.