即时到 Unix 时间戳

Instant to Unix timestamp

我应该如何将 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());
}

过了一会儿我想到了

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);
}

这似乎不是最理想的,但确实有效。

这很难,因为 java.time.* API 故意选择不在 InstantDuration 中提供到 BigDecimal 的转换。理由是在未来的某个时候,值类型将被添加到 Java 并且可能会有一个新的、更高效的 decimal 类型。

目前 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.