【问题标题】:Unix timestamp conversion accuracy for big numbers on AndroidAndroid 上大数字的 Unix 时间戳转换精度
【发布时间】:2016-10-09 19:30:25
【问题描述】:

我正在测试来自the list on this site 的以下值:

常规日期:500,1 月 1 日 = Unix 时间戳:-46388678400

但是,在 Android 上运行以下 Java 代码:

GregorianCalendar calendar = new GregorianCalendar(500, 0, 1, 0, 0, 0);
calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
Log.d("timestamp", String.valueOf(calendar.getTimeInMillis() / 1000L));
Log.d("date", String.valueOf(calendar.getTime()));

输出以下结果:

-46388592000
Sat Jan 01 02:00:00 GMT+02:00 500

尝试the same online converter 和其他一些带有我从 Android 程序获得的 Unix 时间戳的网站,我得到了一整天的差异:

Android app:  -46388592000 = Sat Jan 01 00:00:00 GMT
Online sites: -46388592000 = Sat Jan 02 00:00:00 GMT

我的问题是:谁错了?在线转换器,还是 Android 上的 Java 代码?

Android/Java 在如此大的数字上是否会降低准确性?还是因为闰秒?

【问题讨论】:

    标签: java android datetime unix unix-timestamp


    【解决方案1】:

    避免使用旧的日期时间类

    您正在使用麻烦的旧日期时间类,现在是旧类。避开他们。被 java.time 类取代。

    古代价值不可靠

    不要在 java.time(也不是旧的类)中使用日期时间值来表示古老的值,例如几个世纪以前。 date-time 类型在内部计算自 1970 UTC 第一个时刻以来的秒数。在过去的许多世纪中计算秒数会引发诸如Julian-Gregorian calendar 切换之类的问题。基本上这些古老的价值观是没有意义的。

    如果您想表示历史中的日期,请改用LocalDate

    LocalDate columbusAttacksAmerica = LocalDate.of( "1492-10-12" );
    

    Instant

    虽然我不建议使用历史值这样做,但您可以将那个大整数解析为 InstantInstant 类代表UTC 时间线上的时刻,分辨率为nanoseconds(最多九 (9) 位小数)。

    long secondsSinceEpoch = -46_388_678_400L;
    Instant instant = Instant.ofEpochSecond ( secondsSinceEpoch );
    

    转储到控制台。

    System.out.println ( "secondsSinceEpoch: " + secondsSinceEpoch + " | instant: " + instant );
    

    secondsSinceEpoch:-46388678400 |瞬间:0500-01-01T00:00:00Z

    关于java.time

    java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧日期时间类,例如 java.util.Date.Calendarjava.text.SimpleDateFormat

    Joda-Time 项目现在位于maintenance mode,建议迁移到 java.time。

    要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。

    从哪里获得 java.time 类?

    ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

    【讨论】:

    • 感谢您的详细回答以及 ThreeTenABP 信息。作为替代方案,在重新阅读the documentation 并将calendar.setGregorianChange(new Date(Long.MIN_VALUE)); 添加到我的代码后,我得到与在线站点相同(正确?)的结果,并且您的代码使用Instant。这意味着他们对所有日期都使用纯公历,这实际上在历史上是不正确的(它是在 1582 年制定的)。在这种情况下,您认为哪种方法是正确的?
    猜你喜欢
    • 2018-10-10
    • 1970-01-01
    • 1970-01-01
    • 2015-01-08
    • 1970-01-01
    • 1970-01-01
    • 2014-08-07
    • 1970-01-01
    • 2015-01-17
    相关资源
    最近更新 更多