【问题标题】:TimeUnit conversion from Milliseconds to Days not working for me从毫秒到天的 TimeUnit 转换不适合我
【发布时间】:2018-11-05 05:13:20
【问题描述】:

我正在尝试获取两个时间戳的天数之差,而 TimeUnit 为我返回的结果完全不正确。

这是我的代码:

long ts = 1522242239952L;
long now = 1527274162820L;
long difference = now - ts;
int ageInDays = (int) TimeUnit.MILLISECONDS.convert(difference, TimeUnit.DAYS);
int ageInDays2 = (int) (difference/(1000 * 60 * 60 * 24));
System.out.println(ageInDays);
System.out.println(ageInDays2);

输出是:

-1756844032
58

为什么 TimeUnit 计算这么不正确?

【问题讨论】:

    标签: java time timestamp timeunit


    【解决方案1】:

    因为您正在向后使用 TimeUnit.convert。试试

    TimeUnit.DAYS.convert(difference, TimeUnit.MILLISECONDS);
    

    或者只是

    TimeUnit.MILLISECONDS.toDays(difference);
    

    参考:https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/TimeUnit.html#convert(long,%20java.util.concurrent.TimeUnit)

    【讨论】:

      【解决方案2】:

      您误解了 TimeUnit 文档:

      long convert(long sourceDuration, TimeUnit sourceUnit)

      将给定单位中的给定持续时间转换为该单位。

      您的源单位是 MILLISECONDS,并且您需要 DAYS,因此该行应为

      int ageInDays = (int) TimeUnit.DAYS.convert(difference, TimeUnit.MILLISECONDS);
      

      【讨论】:

        【解决方案3】:

        为什么 TimeUnit 计算这么不正确?

        其他答案是正确的:您正在执行与预期相反的转换。 TimeUnit.MILLISECONDS.convert(difference, TimeUnit.DAYS); 从天转换为毫秒。

        但是你怎么得到一个负数?这是因为int 溢出。相反的转换正确执行并产生 434 758 135 795 200 000。这比 32 位 int 可以容纳的要大得多。因此,当您转换为 int 时,最高有效位将被切掉。偶然地,最终成为 int 符号位的位是 1,表示负数。我通常会避免在没有先进行范围检查的情况下进行这种转换。你可能想养成同样的习惯。 Math.toIntExact() 在这里很有帮助。

        如何修复:java.time

        其他答案基本还是正确的。我仍然想提供一些建议。

        如果您认为从一天 16:04 到第二天 16:04 的时间是 1 天,那么您需要考虑时区才能得到正确的结果。例如:

            ZoneId zone = ZoneId.of("Africa/Mogadishu");
            ZonedDateTime birth = Instant.ofEpochMilli(ts).atZone(zone);
            long ageInDays = ChronoUnit.DAYS.between(birth, ZonedDateTime.now(zone));
            System.out.println(ageInDays);
        

        在这种情况下,刚才运行代码的结果也是你预期的结果:

        58

        另一方面,如果您将 1 天定义为 24 小时,无论挂钟读数如何,这里有一种方法可以以亚秒级精度获取年龄。您可以随时转换为之后的几天。

            Instant birth = Instant.ofEpochMilli(ts);
            Duration age = Duration.between(birth, Instant.now());
            System.out.println(age);
            System.out.println(age.toDays());
        

        输出:

        PT1398H52M13.994841S
        58
        

        两行中的第一行表示年龄是 1398 小时 52 分 13.994841 秒。第二行与之前的结果一致。

        这两个sn-ps背后的想法也可以组合混合。总而言之,我认为java.time 提供了一些TimeUnit 难以获得的可能性,以及一些非常清晰且不言自明的代码,您不会轻易犯与问题中相同的错误。

        链接:

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-09-27
          • 2020-07-23
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多