为了账号安全,请及时绑定邮箱和手机立即绑定

Java当前日期和过去日期之间的年,月,日,小时,分钟,秒之间的差异

Java当前日期和过去日期之间的年,月,日,小时,分钟,秒之间的差异

白衣染霜花 2022-10-20 15:14:46
我知道这已经在这里被问过很多次了,但我一直无法找到任何特定于我的案例的东西。我试图找出当前日期时间和以前的日期时间之间的区别,每个日期时间的格式都是yyyy-MM-dd HH:mm:ss.s. 根据此处给出的答案,我提出了以下代码:SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.s");String earliestRunTime = "2017-12-16 01:30:08.0";Date currentDate = new Date();log.info("Current Date: {}", format.format(currentDate));try {    Date earliestDate = format.parse(earliestRunTime);    long diff = currentDate.getTime() - earliestDate.getTime();    long diffSeconds = diff / 1000 % 60;    long diffMinutes = diff / (60 * 1000) % 60;    long diffHours = diff / (60 * 60 * 1000) % 24;    long diffDays = diff / (24 * 60 * 60 * 1000) % 30;    long diffMonths = diff / (30 * 24 * 60 * 60 * 1000) % 12;    long diffYears = diff / (12 * 30 * 24 * 60 * 60 * 1000);    return String.format("%s years, %s months, %s days, %s hours, %s minutes, %s seconds",            diffYears, diffMonths, diffDays, diffHours, diffMinutes, diffSeconds);    }catch (Exception e) {    e.printStackTrace();    return e.getMessage();}当我运行代码时,JSON 返回以下结果:lifetime: "41 years, -1 months, 14 days, 9 hours, 42 minutes, 37 seconds"我在这里有两个问题:我在 41 年和负数的计算中哪里出错了?我有更好的方法吗?我当前的设置不考虑闰年或 365 天一年,我需要将这些考虑在内。
查看完整描述

3 回答

?
阿波罗的战车

TA贡献1862条经验 获得超6个赞

  1. 我在 41 年和负数的计算中哪里出错了?

除了使用臭名昭著的麻烦和过时SimpleDateFormat的类以及同样过时的类之外Date,您的代码中还有以下错误:

  • 您正在解析08.0为 8 秒 0 秒。在我的 JDK-11 上SimpleDateFormat选择 0 秒并丢弃我认为正确的 8 秒。SimpleDateFormat无法解析秒上的一位小数(仅精确三位小数),因此该错误的解决方案是完全丢弃SimpleDateFormat

  • 正如其他人所说int,您的乘法溢出。例如,30 * 24 * 60 * 60 * 1000应该给出 2 592 000 000,但由于 anint不能保存这个数字,所以你得到-1 702 967 296了。因为这是一个负数,所以下面的除法给你一个负数的月数。

  • 正如 Solomon Slow 在评论中指出的那样,一个月可能是 28、29、30 或 31 天。将所有月份设置为 30 天时,您将面临不正确的天数和月份数以及最终年份数的风险。当我今天运行你的代码时,正确的答案是 1 年 4 个月 13 天,但我得到了 19 天,6 天太多了。

  • 您没有考虑夏令时 (DST) 和其他时间异常。这些可能会导致一天为例如 23 或 25 小时,从而产生错误。

或者总结一下:您的错误是您试图“手动”进行计算。日期和时间数学太复杂且容易出错,无法执行此操作。您应该始终将其留给经过充分验证的库类。

  1. 我有更好的方法吗?我当前的设置不考虑闰年或 365 天一年,我需要将这些考虑在内。

是的,有一个更好的方法。最好的方法可能是使用PeriodDurationThreeTen Extra 项目中的类,请参见下面的链接。我现在不打算在我的计算机上安装那个库,所以我将只展示使用内置类的好的和现代的解决方案:

    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.S");

    LocalDateTime currentDateTime = LocalDateTime.now(ZoneId.of("Australia/Sydney"));

    String earliestRunTime = "2017-12-16 01:30:08.0";

    LocalDateTime earliestDateTime = LocalDateTime.parse(earliestRunTime, dtf);


    // We want to find a period (years, months, days) and a duration (hours, minutes, seconds).

    // To do that we cut at the greatest possible whole number of days

    // and then measure the period before the cut and the duration after it.

    LocalDateTime cut = earliestDateTime.plusDays(

            ChronoUnit.DAYS.between(earliestDateTime, currentDateTime));


    Period p = Period.between(earliestDateTime.toLocalDate(), cut.toLocalDate());

    Duration d = Duration.between(cut, currentDateTime);


    String result = String.format("%s years, %s months, %s days, %s hours, %s minutes, %s seconds",

            p.getYears(), p.getMonths(), p.getDays(),

            d.toHours(), d.toMinutesPart(), d.toSecondsPart());


    System.out.println(result);

当我刚刚运行代码时,我得到了:

1年4个月13天19小时26分7秒

在现代 Java 日期和时间 API java.time 中,aPeriod是年、月和日Duration的数量,a 是小时、分钟、秒和秒的小数部分(低至纳秒)。既然你想要两者,我正在使用这两个类。

我使用的toXxxPart方法Duration是在 Java 9 中引入的。如果您使用的是 Java 8(或 ThreeTen Backport),打印分钟和秒会稍微复杂一些。搜索java format duration或类似内容以了解如何操作。

我仍然没有考虑夏季时间。为此,我们需要知道最早运行时间字符串的时区,然后使用ZonedDateTime而不是LocalDateTime. 否则代码将非常相似。


查看完整回答
反对 回复 2022-10-20
?
智慧大石

TA贡献1946条经验 获得超3个赞

我在 41 年和负数的计算中哪里出错了?

因为分母会溢出。您需要使用长:

long diffMonths = diff / (30 * 24 * 60 * 60 * 1000L) % 12; //Notice the L at the end
long diffYears = diff / (12 * 30 * 24 * 60 * 60 * 1000L); //Notice the L at the end

另请注意,这12 * 30是一年中天数的一个非常糟糕的近似值。

我有更好的方法吗?

是的。使用 Java 8 中的 Duration api。https://www.mkyong.com/java8/java-8-period-and-duration-examples/

很难给出准确的答案,因为这个问题有点模糊。例如 - 如果某一年是闰年,并且您正在比较日期 2020/03/28 和 2021/03/28,结果应该是什么?1年还是1年1天?(2020 年是闰年,所以 03/28 之后还有 03/29)


查看完整回答
反对 回复 2022-10-20
?
扬帆大鱼

TA贡献1799条经验 获得超9个赞

使用与您相同的方法,您需要将分母明确标识为长值。目前,它假定它们是整数,这会导致数字溢出——这意味着计算的值对于整数来说太大了。这可以解释为什么你会得到负值/任意值。修复很简单:


SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.s");

String earliestRunTime = "2017-12-16 01:30:08.0";

Date currentDate = new Date();

log.info("Current Date: {}" + format.format(currentDate));


try {

    Date earliestDate = format.parse(earliestRunTime);


    long diff = currentDate.getTime() - earliestDate.getTime();


    long diffSeconds = diff / 1000L % 60L;

    long diffMinutes = diff / (60L * 1000L) % 60L;

    long diffHours = diff / (60L * 60L * 1000L) % 24L;

    long diffDays = diff / (24L * 60L * 60L * 1000L) % 30L;

    long diffMonths = diff / (30L * 24L * 60L * 60L * 1000L) % 12L;

    long diffYears = diff / (12L * 30L * 24L * 60L * 60L * 1000L);


    return String.format("%s years, %s months, %s days, %s hours, %s minutes, %s seconds",

            diffYears, diffMonths, diffDays, diffHours, diffMinutes, diffSeconds);



}

catch (Exception e) {

    e.printStackTrace();

    return e.getMessage();

}


查看完整回答
反对 回复 2022-10-20
  • 3 回答
  • 0 关注
  • 106 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信