您的浮点值1.511554592277516E9 无疑表示自 1970 年 1 月 1 日 UTC 午夜以来的秒数,精度为微秒:1 511 554 592 秒和 277 516 微秒(百万分之一秒)。
我建议为此使用java.time,即现代 Java 日期和时间 API,也称为 JSR-310。它比过时的 Date 类和朋友要好得多,并且还提供纳秒精度(Date 只有毫秒精度,所以如果转换成一个精度会丢失)。更具体地说,我将首先创建一个 java.time.Instant 对象(转换为其他日期时间类型会很容易,我将在最后介绍一个示例)。
通过Instant 获得完整的精度需要一点思考。我用double 和long 玩了一点,但意识到(1)double 没有所需的全部精度,纳秒不会是正确的(2)转换为long 持有纳秒(不是唯一的方法,但肯定是最简单的方法)将产生“2262 年问题”,因此如果您要处理遥远未来的日期,它将不起作用。无论如何,我认为简单而安全的解决方案是在将数字输入Instant 之前使用BigDecimal 进行所需的数学运算。
String secondsSinceEpoch = "1.511554592277516E9";
BigDecimal decimalSeconds = new BigDecimal(secondsSinceEpoch);
long seconds = decimalSeconds.longValue();
long nanos = decimalSeconds.subtract(BigDecimal.valueOf(seconds))
.movePointRight(9)
.longValueExact();
Instant inst = Instant.ofEpochSecond(seconds, nanos);
System.out.println(inst);
打印出来:
2017-11-24T20:16:32.277516Z
打印的日期时间为 UTC。如果该值符合预期,我应该说它确认您的浮点值确实是自纪元以来的秒数。
您请求的日期时间格式为 yyyy-MM-dd HH:mm:ss。您需要决定日期时间在哪个时区。日期对象没有格式,因此您还需要在字符串中获取格式。例如:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
System.out.println(inst.atZone(ZoneId.of("America/Vancouver")).format(formatter));
打印出来
2017-11-24 12:16:32
当然,您可以替换所需的时区。 atZone() 将Instant 转换为ZonedDateTime,这是java.time 的另一个常用类。
编辑:如果您不想打扰 BigDecimal,您可以接受轻微的不准确和/或您将值作为双精度而不是字符串接收,这里有一个替代方案更少的代码行数:
double secondsSinceEpoch = 1.511554592277516E9;
long longSeconds = (long) secondsSinceEpoch;
long micros = Math.round((secondsSinceEpoch - longSeconds) * 1_000_000);
Instant inst = Instant.ofEpochSecond(longSeconds).plus(micros , ChronoUnit.MICROS);
在这种特殊情况下,它给出了完全相同的结果,精确到纳秒。我不确定是否使用其他输入,微秒最终可能会不准确,但另一方面,如果您收到一个双精度(不是字符串),那么无论如何您都无能为力。