Java的long类型是否足够存储微秒级别的时间戳?

4

我可以使用Java的long类型来存储微秒级别的时刻,并且不需要任何特殊的有符号到无符号转换技巧,以合理的精度存储。如果可以,我该如何计算结束日期范围?

这是通常的8字节日期范围:-9,223,372,036,854,775,808到9,223,372,036,854,775,807。

更新:

根据建议使用:

new Date(Long.MAX_VALUE)

这是UM的结束日期:

new Date(Long.MAX_VALUE/1_000)

Sat Jan 09 20:00:54 PST 294247

这是使用正长整型纳秒表示的结束日期:

new Date(Long.MAX_VALUE/1_000_000)

Fri Apr 11 16:47:16 PDT 2262

1
那么你是在问关于微秒还是纳秒的问题? - PM 77-1
3
这个答案是针对毫秒的。将其结果除以1000000即可得到纳秒数。System.out.println(new Date(Long.MAX_VALUE / 1000000L)); - Elliott Frisch
@ElliottFrisch 为什么要除以1000000而不是1000?我认为毫秒和纳秒只相差1000倍,而Java Date()类将以毫秒为单位。 - simgineer
谷歌:“纳秒每毫秒”,答案:“将时间值乘以1e + 6”。 - Elliott Frisch
1
抱歉让您感到困惑,我只是在询问微秒而已。我不小心说成了纳秒。 - simgineer
2
它将一直正常工作,直到2262年4月11日星期五晚上11:47:16.854。 - Ismail Sabry
1个回答

14

简述

  • 纳秒只能跟踪三个世纪。
  • 永远不要自己编写时间记录代码。☛ 使用 java.time
  • 在交换日期时间值时,永远不要使用从纪元开始的计数,而应使用标准 ISO 8601 格式的文本。

做数学运算

您必须选择一个纪元参考日期。尽管行业中使用了数十种不同的纪元,但其中一种更常见的是通常称为Unix 时间:UTC 中的 1970 年第一个时刻,即 1970-01-01T00:00:00Z。该点之后的时刻使用正数计数,之前的时刻使用负数计数。

当然,一年的长度因闰年而异,但我们可以轻松地近似。使用 TimeUnit 类及其方便的转换方法获取一年中的纳秒数

进行一些计算。

long nanosPerDay = TimeUnit.DAYS.toNanos( 1L );
long nanosPerYear = ( long ) ( nanosPerDay * 365.25 );
long maximumYears = ( Long.MAX_VALUE / nanosPerYear );

将内容输出到控制台。

System.out.println( "nanosPerDay: " + nanosPerDay );
System.out.println( "nanosPerYear: " + nanosPerYear );
System.out.println( "Long.MAX_VALUE: " + Long.MAX_VALUE + " provides for maximumYears: " + maximumYears );

请看这段代码在IdeOne.com上的实时运行code run live at IdeOne.com

nanosPerDay: 86400000000000

nanosPerYear: 31557600000000000

Long.MAX_VALUE: 9223372036854775807提供了最大年数:292

所以我们可以获得1970年前后不到±3个世纪。如果几个世纪对您的应用程序足够好,那么这种方法确实有效。至少当日历耗尽时,您将无法修复它。 ;-)

Instant

幸运的是,我们不需要自己进行这些计算。

现代Java恰好带有业务导向应用程序可用的最先进的日期时间处理框架:JSR 310中定义的java.time类。

java.time.Instant类使用不同的策略来跟踪时间。该类在1970年UTC时期之前/之后保持整个秒的计数,加上瞬间的分数纳秒的单独计数。

把它想象成:

moment = ( whole-seconds + fractional-second ) ; // Since 1970-01-01T00:00:00Z.

这使得最小值/最大值为:

请注意,java.time类具有纳秒的分辨率,而它们替代的遗留类(DateCalendar等)的分辨率为毫秒

有关详细信息,请参见class JavaDoc和OpenJDK source code(在Mercurial中)。

提示:对于业务目的,最适合使用java.time类。如果您从事科学、工程、考古或历史工作,请使用适用于该领域的其他符号,通常为String类型。

粒度

请注意,不同的计算机系统在其时间记录中使用不同的粒度。
如上所述,java.time类解析为纳秒,有九个数字的小数秒。旧版类使用毫秒,有三个数字的小数秒。其他系统,例如Postgres数据库,使用微秒,有六个数字的小数秒。在跨系统交换或比较数据时,您可能需要在各种java.time类上使用truncatedTo方法。
当前常规计算机硬件时钟仅精确到微秒或更粗糙。它们可能报告纳秒,但精度不到那个程度。因此,您将发现Java 9、10和11中的Instant.now()方法捕获当前时刻到微秒(虽然数据类型可以处理纳秒,但它检测当前时间是以微秒为单位)。

Instant.now().toString(): 2019-01-23T12:34:56.123456Z


关于java.time

java.time框架内置于Java 8及更高版本中。这些类取代了令人头疼的旧legacy日期时间类,如java.util.DateCalendarSimpleDateFormat

要了解更多信息,请参见Oracle教程。并在Stack Overflow上搜索许多示例和解释。规范是JSR 310

Joda-Time项目现在处于维护模式,建议迁移到java.time类。

您可以直接使用java.time对象与数据库交换。使用符合JDBC 4.2或更高版本的JDBC驱动程序。无需字符串,无需java.sql.*类。Hibernate 5和JPA 2.2支持java.time

如何获取java.time类?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接