优雅的方式将纪元时间戳转换为东部时间并使用Nodatime进行反向

Man*_*nha 2 c# timezone datetime portable-class-library nodatime

我正在编写围绕马萨诸塞州海湾运输管理局(MBTA)实时API的托管包装器.它们有一个API,它返回服务器时间,即unix时间戳(epoch).我正在实现它的库是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;
    }
}
Run Code Online (Sandbox Code Playgroud)

有没有其他方法可以简单地写这个.我希望Nodatime应该支持将纪元时间转换为America/New_YorkDateTime和America/New_YorkDateTime到纪元时间.我的方法MbtaDateTimeToUnixTimestamp是一个残酷的黑客

Jon*_*eet 7

首先,在注释中提到的那样,这将是最好用野田佳彦时间类型在你的代码-只能求助于DateTime当你真的不得不这样做.这应该会导致整个代码更加清晰.

将Unix时间戳转换为a Instant非常简单:

Instant instant = Instant.FromSecondsSinceUnixEpoch(seconds);
Run Code Online (Sandbox Code Playgroud)

然后,您可以ZonedDateTime根据当前代码转换为... ToDateTimeUnspecified如果您确实需要使用,则使用很好DateTime.

相反,您当前的代码看起来很糟糕 - 您假设DateTime有效的是UTC值.这与你以后使用时区不符.我怀疑你想将输入转换为a 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;
}
Run Code Online (Sandbox Code Playgroud)

记下InZoneStrictly电话.如果您传递的是不存在的本地时间存在两次的本地时间,则会抛出异常- 在这两种情况下都是由于DST转换.这可能不是你想要的 - 你真的需要考虑在那些情况下你想要发生什么,或者试图避免它们是可行的.有关更多详细信息和选项,请参阅文档时区部分.