我知道以前在这里已经多次询问过这个问题,但是我无法找到与我的案子有关的任何东西。我正在尝试查找当前日期时间和上一个日期时间之间的差异,两者的格式均为yyyy-MM-dd HH:mm:ss.s
。根据{{3}}给出的答案,我想出了以下代码:
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"
我在这里有两个问题:
答案 0 :(得分:1)
在我41年的计算中哪里出错了,并且数字为负?
因为分母将溢出。您需要使用Long:
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/
很难给出准确的答案,因为这个问题有点含糊。例如-如果一年中的某个年份是a年,并且您正在比较日期2020/03/28和2021/03/28,结果应该是什么? 1年还是1年零1天? (2020年是a年,因此03/28之后也为03/29)
答案 1 :(得分: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,但是由于int
无法保存该数字,因此您会得到-1 702 967 296
。由于这是一个负数,因此下面的除法会为您提供负数的月数。或者总结:您的错误是您尝试“手动”进行计算。日期和时间数学太复杂且容易出错。您应该始终将其留给经过充分验证的库类。
- 我有更好的方法吗?我目前的设定未考虑leap年或365天,因此我需要将这些纳入 帐户。
是的,还有更好的方法。最好的方法可能是使用ThreeTen Extra项目中的PeriodDuration
类,请参见下面的链接。我现在不打算在我的计算机上安装该库,因此我将使用内置的类来展示一种好的现代解决方案:
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中,Period
表示年,月和日,而Duration
表示小时,分钟,秒和分数秒(低至纳秒)。既然您都想要,我将同时使用这两个类。
我正在使用的toXxxPart
的{{1}}方法是在Java 9中引入的。如果您正在使用Java 8(或ThreeTen Backport),则打印分钟和秒会更加复杂。搜索Duration
或类似内容以了解操作方法。
我仍然没有考虑夏季时间。为此,我们需要知道最早的运行时间字符串的时区,然后使用java format duration
而不是ZonedDateTime
。否则,代码将非常相似。
答案 2 :(得分:0)
使用与您相同的方法,您需要将分母明确标识为长值。当前,它假定它们是整数,这会导致数字溢出-意味着计算出的值对于整数而言太大。这可以解释为什么您会得到负/任意值。修复很简单:
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();
}