即时转换为Unix时间戳。

3

我应该如何将Instant转换为带小数点的Unix时间戳字符串以获得亚秒级精度?

测试用例如下:

@Test
public void toStringUnixTime() throws Exception {
    assertEquals("0", TimeUtils.toStringUnixTime(Instant.EPOCH));
    assertEquals("1491327940.619", TimeUtils.toStringUnixTime(Instant.ofEpochMilli(1491327940619L)));
    assertEquals("1491327940.000012345", TimeUtils.toStringUnixTime(Instant.ofEpochSecond(1491327940, 12345)));
}

无法正常工作的提案(总是有尾随的0,总是有小数点)

public static String toStringUnixTime(Instant i){
    return i.getEpochSecond() + "." + String.format("%09d", i.getNano());
}
2个回答

3
这很困难,因为 java.time.* API 故意选择在 Instant 或 Duration 中不提供转换为 BigDecimal 的功能。其理由是,在将来某个时刻,值类型将被添加到 Java 中,并且可能会出现一种新的、更高效的十进制类型。
目前 Philipp 的答案是可以的。只需要在 TemporalQuery 中进行包装,如下所示:
public static TemporalQuery<String> UNIX_STRING = TimeUtils::toStringUnixTime;

private static String toStringUnixTime(TemporalAccessor temporal) {
  Instant i = Instant.from(temporal);
  BigDecimal nanos = BigDecimal.valueOf(i.getNano(), 9);
  BigDecimal seconds = BigDecimal.valueOf(i.getEpochSecond());
  BigDecimal total = seconds.add(nanos);
  DecimalFormat df = new DecimalFormat("#.#########");
  return df.format(total);
}

现在我们有了这个查询,我们可以将原始代码更改如下:
@Test
public void toStringUnixTime() throws Exception {
  assertEquals("0", Instant.EPOCH.query(UNIX_STRING));
  assertEquals("1491327940.619", Instant.ofEpochMilli(1491327940619L).query(UNIX_STRING));
  assertEquals("1491327940.000012345", Instant.ofEpochSecond(1491327940, 12345).query(UNIX_STRING));
}

使用这样的查询通常比使用静态实用程序类编写代码更加简洁。该查询还与OffsetDateTimeZonedDateTime一起使用。


我这样想是不是正确的:调用这个方法在任何其他 TemporalAccessor 上(比如 LocalDate)都会失败,但只有在运行时才会失败(编译可以通过)?难道静态方法的方式不是更安全吗? - Philipp
它可以在任何Instant.from()可以转换的类型上工作,例如ZonedDateTimeOffsetDateTime。但是,像LocalDate这样的其他情况下它将失败。取决于您认为什么是重要的。 - JodaStephen
值类型发生了什么?看了一下Java 10...还没有实现... - YoYo
值类型是一个重大任务。它们仍在进行中,并将持续数年。 - JodaStephen

1

过了一会儿,我想到了:

public static String toStringUnixTime(Instant i){
    BigDecimal nanos = BigDecimal.valueOf(i.getNano(), 9);
    BigDecimal seconds = BigDecimal.valueOf(i.getEpochSecond());
    BigDecimal total = seconds.add(nanos);
    DecimalFormat df = new DecimalFormat("#.#########");
    return df.format(total);
}

这似乎不是最佳选择,但能够完成工作。

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