Java当前日期和过去日期之间的差值,以年、月、日、小时、分、秒为单位
我知道这个问题以前在这里被问过很多次,但是我还没有找到任何与我的情况相关的东西。我试图找出当前日期时间和前一个日期时间之间的差异,每个日期时间的格式为yyyy-MM-dd HH:MM:ss.s。根据给出的答案,我得出了以下代码:Java当前日期和过去日期之间的差值,以年、月、日、小时、分、秒为单位,java,date,datetime,difference,date-difference,Java,Date,Datetime,Difference,Date Difference,我知道这个问题以前在这里被问过很多次,但是我还没有找到任何与我的情况相关的东西。我试图找出当前日期时间和前一个日期时间之间的差异,每个日期时间的格式为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 current
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天一年,我需要考虑到这些。
我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是一年中天数的一个非常糟糕的近似值
有没有更好的方法让我这么做
对。使用Java8中的DurationAPI
很难给出准确的答案,因为这个问题有点模糊。例如,如果一年中有一年是闰年,而您正在比较日期2020/03/28和2021/03/28,结果应该是什么?1年还是1年1天?2020年是闰年,所以在03/28之后,也有03/29,使用与您相同的方法,您需要明确地将分母标识为长值。目前,它假定它们是整数,这会导致数字溢出-这意味着计算的值对于整数来说太大。这可以解释为什么会得到负值/任意值。解决方法很简单:
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();
}
我41岁和一个负数的计算错在哪里?
除了使用臭名昭著的麻烦且早已过时的SimpleDataFormat类和同样过时的日期之外,您的代码中还存在以下错误:
您正在将08.0解析为8秒0秒。在我的JDK-11上,SimpleDataFormat选择0秒,放弃我认为正确的8秒。SimpleDateFormat无法解析秒上的一个小数,只能解析三个小数,因此此错误的解决方案是完全放弃SimpleDateFormat。
正如其他人所说,乘法中存在int溢出。例如,30*24*60*60*1000应该给出2592000000,但是由于int不能容纳这个数字,因此得到的是-170297296。由于这是一个负数,下面的除法给出的月数为负数。
所罗门·斯洛在评论中指出,一个月可能是28天、29天、30天或31天。当将所有月份设置为30天时,您可能会面临天数和月份不正确的风险,最后可能会出现年份错误的风险。当我今天运行你的代码时,正确答案应该是1年4个月13天,但我得到了19天,6天太多了。
您没有考虑夏季DST和其他时间异常。这可能会导致一天的时间为23或25小时,从而产生错误。
或者总结一下:你的错误是你试图“手工”计算。日期和时间的数学太复杂,容易出错。您应该始终将其留给经过充分验证的库类
有没有更好的方法让我这么做?我目前的设置不考虑闰年或365天一年,我需要把这些纳入
账户
是的,有一个更好的方法。最好的方法可能是使用ThreeTen额外项目中的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中,周期是年、月和天的数量,持续时间是小时、分钟、秒和秒到纳秒的分数。既然你想要两者,我就使用这两个类
我使用的Duration的toxxpart方法是在Java9中引入的。如果您使用的是Java8或Three-Ten Backport,打印分钟和秒的过程会稍微复杂一些。搜索java格式持续时间或类似内容以了解如何使用
我仍然没有把夏天的时间考虑在内。为此,我们需要知道最早运行时字符串的时区,然后使用ZonedDateTime而不是LocalDateTime。否则代码将非常相似
链接
解释如何使用java.time
结果应该是怎样的?如果差异为1年,您是要打印1年、12个月、365天还是1年、0个月、0天?只是想一想:如果向下报告到第二个很重要,但时间跨度可以包括28、29、30或31天的月份,那么也许你需要重新思考你的用例。@NeplatnyUdaj理想情况下,差异应该是1年,0个月,0天。@SolomonSlow很好,我甚至不认为
你使用的是几年前被java.time取代的糟糕类。切勿使用日期。闰年应处理为1年1天。