【问题标题】:Cannot convert from java Double to java Date无法从 java Double 转换为 java Date
【发布时间】:2017-12-07 18:56:24
【问题描述】:

我在将双精度转换为 Java 日期对象时遇到问题:yyyy-MM-dd HH:mm:ss

我尝试将此双精度值转换为长值,然后用结果实例化一个 Date 对象,但我收到错误消息,提示我无法从双精度值转换为长值。

我的时间戳双精度值采用以下格式:

1.511554592277516E9

谁能帮我解决这个问题,提前谢谢。

【问题讨论】:

  • 你能分享一下你到目前为止所尝试的吗?您使用的是原语还是 DoubleLong 类型?
  • 您是否在做类似...计算时代过去的秒数之类的事情?
  • 我从这样的地图对象中读取时间戳:double timestamp = (double) Map.get("ts");然后将其转换为 long 使用: long timestampLong = (long) timestamp;最后创建一个这样的日期对象: Date date = new Date(timestampLong);它给了我这样的结果:Sun Jan 18 06:52:11 EST 1970
  • 你为什么要用双精度表示时间呢?并不是说它被禁止,而是您通常会计算自标准时间以来经过的毫秒数。一个长的将适合那个。你使用 double 是因为某些系统有这样的强制吗?
  • 这不是我的选择,我在日志文件中接收数据并以这种方式存储:1.511531688957562E9

标签: java date double


【解决方案1】:

假设这个浮点值是 1970 年 1 月 1 日 0:00 GMT 的 Unix 纪元之后的秒数,这将提供到具有该偏移量的 LocalDateTime 的转换:

LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(
                Double.valueOf(1.511554592277516E9).longValue(), 0, ZoneOffset.UTC);
System.out.println(localDateTime);

我将把它转换为Date 作为读者的练习。

【讨论】:

  • 我想我会选择Instant 而不是LocalDateTimeInstant 也有一个ofEpochSecond 方法,它保留了long 表示的时间轴上的点。转换为Date,如果我看到方法,我会避免它。现代 API 更易于使用。
  • @AnissCohra 所以你的日志文件记录了 1970 年第一刻的纪元参考日期之后一秒半的时刻?很难相信。这些日志文件是否取自 Back to the Future 电影?
  • @BasilBourque:我会给你一个 C- 表示努力,但这个数字更接近 1,511,554,592.277516,与 1970 年相差不到一秒半。
【解决方案2】:

您的浮点值1.511554592277516E9 无疑表示自 1970 年 1 月 1 日 UTC 午夜以来的秒数,精度为微秒:1 511 554 592 秒和 277 516 微秒(百万分之一秒)。

我建议为此使用java.time,即现代 Java 日期和时间 API,也称为 JSR-310。它比过时的 Date 类和朋友要好得多,并且还提供纳秒精度(Date 只有毫秒精度,所以如果转换成一个精度会丢失)。更具体地说,我将首先创建一个 java.time.Instant 对象(转换为其他日期时间类型会很容易,我将在最后介绍一个示例)。

通过Instant 获得完整的精度需要一点思考。我用doublelong 玩了一点,但意识到(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);

在这种特殊情况下,它给出了完全相同的结果,精确到纳秒。我不确定是否使用其他输入,微秒最终可能会不准确,但另一方面,如果您收到一个双精度(不是字符串),那么无论如何您都无能为力。

【讨论】:

    猜你喜欢
    • 2016-12-20
    • 1970-01-01
    • 1970-01-01
    • 2013-12-08
    • 2013-11-23
    • 1970-01-01
    • 1970-01-01
    • 2011-08-26
    • 1970-01-01
    相关资源
    最近更新 更多