【问题标题】:Create Java DateTime Instant from microseconds从微秒创建 Java DateTime Instant
【发布时间】:2019-12-16 02:56:41
【问题描述】:

自 Java 9 以来,Java 日期和时间 API 发生了变化。 LocalDateTime 现在具有微秒精度。

Java 9 有一个全新的 java.time.Clock 实现,能够以小于毫秒(小数点的三位数字)的分辨率捕获当前时刻。

我们从后端服务获取时间(以微秒为单位)。

System.currentTimeMillis  > 1565245051795    > 2019-08-08T06:17:31.795
Service.getTime           > 1565245051795306 > 2019-08-08T06:17:31.795306

为了构造一个在我们的应用程序中使用的 LocalDateTime,我们这样做

long timeMicros = service.getTime();
long timeMillis = timeMicros / 1000;
LocalDateTime ldt = Instant.ofEpochMilli(timeMillis).atZone(ZoneId.systemDefault()).toLocalDateTime();

为了查询服务,我们再次需要 time 微秒,然后我们这样做

long timeMillis = dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
long timeMicros = timeMillis * 1000;

问题是我们无法恢复时间微秒精度。

是否可以创建具有微秒精度的 Instant?
我们现在使用的是 Java 11。当我们的一个 JUnit 测试因微秒精度增加而失败时,我注意到了这一变化。

对于 JUnit 测试,我找到了一种解决方法:

private static final LocalDateTime START = LocalDateTime.now().truncatedTo(ChronoUnit.MILLIS);


我不确定这是解决方法还是实际解决方案,但添加时间戳的最后三微秒数字似乎可行。

long micros = 306L; //TODO get the last three digits from the timeMicros
ldt.plus(micros, ChronoUnit.MICROS));

【问题讨论】:

  • 使用 Instant.ofEpochSecond() 代替 Instant.ofEpochMilli()。一个有两个参数:自纪元以来的秒数,以及额外的纳秒。
  • 一种可能,但是如何从 timeMicros long 中获取 epochSeconds 和 nanoAdjustment?
  • 秒:将 timeMicros 除以一百万。纳秒:以 timeMicros 为模,以一百万为模得到微秒。然后将结果乘以一千。
  • 顺便说一句,以这种方式使用LocalDateTime 更像是不是你想要做的。使用ZonedDateTime 表示时刻,时间轴上的特定点,因为LocalDateTime 根据定义不能。我想不出任何用例调用LocalDateTime.now() 是正确的做法。见:What's the difference between Instant and LocalDateTime?

标签: java java-9 java-time java-11 java.time.instant


【解决方案1】:
    long timeMicros = 1_565_245_051_795_306L;
    Instant i = Instant.EPOCH.plus(timeMicros, ChronoUnit.MICROS);
    System.out.println(i);

输出是:

2019-08-08T06:17:31.795306Z

编辑:我更喜欢使用对微秒的内置支持,而不是通过除法和乘法将微秒转换为毫秒和/或秒。此外,当明确地将它们添加到 epoch 时感觉有点手持。

您已经知道如何将Instant 转换为LocalDateTime,您已经在问题中展示过,所以我不再重复。

编辑:

您有解决方案从 Instant 中恢复 timeMicros 吗?

有几个选项。这样计算就不是那么复杂了,所以我可能会这样做:

    long microsBack = TimeUnit.SECONDS.toMicros(i.getEpochSecond())
            + TimeUnit.NANOSECONDS.toMicros(i.getNano());
    System.out.println(microsBack);

1565245051795306

为了在第一次转换时更有风格,您可能更喜欢稍短一些:

    long microsBack = ChronoUnit.MICROS.between(Instant.EPOCH, i);

编辑: 可能是吹毛求疵,但也是为了避免任何人的误解:LocalDateTime 一直具有纳秒精度。只有 now 方法在 Java 8 上具有毫秒精度。我在某处读到 Java 9 的精度因平台而异,但您是对的,微秒精度似乎很典型。

【讨论】:

  • 一个很好的解决方案。那么为什么 Instant 不使用相同的 EPOCH 常量来创建带有 ofEpochMilli 的 Instant 呢?它使用 Math 类来创建具有秒数和 nanoOfSecond 的 Instant。
  • 你有解决办法从 Instant 中取回 timeMicros 吗?
  • 我在答案末尾添加了几个选项,用于转换回微量。为什么ofEpochMilli 没有以类似的方式实现,我不知道。这可能是效率方面的考虑,另一方面,我不一定相信实施是最有效的,所以我不确定。
  • 或者 ofEpochMilli 在项目早期被编码,在 ChronoUnit 枚举之前,之后没有更改。
猜你喜欢
  • 2019-09-27
  • 2017-11-06
  • 2017-11-18
  • 2010-09-15
  • 2020-04-25
  • 2021-09-06
  • 2013-04-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多