我有下面的helper方法
private Date getDate(int year, int month, int day) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, month);
cal.set(Calendar.DAY_OF_MONTH, day);
cal.setTimeZone(TimeZone.getTimeZone("GMT"));
return cal.getTime();
}
我公司的一个人实现了这个方法:
public static int getDaysBetween(Date d1, Date d2) {
return (int)((d2.getTime() - d1.getTime()) / (1000 * 60 * 60 * 24));
}
有人能解释一下为什么下面的答案是28?
System.err.println(DateUtils.getDaysBetween(
getDate(2023, 01, 01), getDate(2023, 02, 01)));
2条答案
按热度按时间wqsoz72f1#
TL;医生
如果你真的想数秒的话。
但是如果你想计算日期之间的日历天数,你工作得太辛苦了。
详情
避免使用遗留的日期时间类
Answer by Zedki在技术上是正确的,但是使用了有严重缺陷的日期-时间类,这些类在几年前就被JSR 310定义的现代 java.time 类所取代。
Calendar
类的众多缺陷之一是,它通过从零开始的索引计数来计算月数。愚蠢且令人困惑:1月是0,12月是11。相比之下,java.time 类使用合理的计数。月份从1月到12月运行1-12。
java.time
java.util.Date
类被java.time.Instant
替换,两者都表示UTC中的时刻,即与UTC的偏移量为0小时-分钟-秒。输入的year-month-day可以替换为
java.time.LocalDate
对象。该类表示仅日期值,没有时间,也没有时区或偏移量。你的方法名
getDate
不是很有描述性。显然你想确定指定日期的第一个时刻,以UTC的形式显示(偏移量为零)。所以我们可以使用描述性名称firstMomentOfTheDayInUtc
。要确定一天的第一个时刻,总是让 java.time 来完成这项工作。永远不要假设一天从00:00开始。在某些时区的某些日期的某些日子从另一个时间开始,例如01:00。在UTC中,我们确实知道根据定义每天都从00:00开始,但我们仍然可以让 java.time 来计算。我们最终得到一个
ZonedDateTime
对象,表示通过特定时区的挂钟时间看到的时刻。Instant
类是 java.time 的基本构建块。因此,我们从ZonedDateTime
对象中提取Instant
,并从方法中返回该对象。然后你想得到两个
Instant
对象之间的运行时间,作为整秒的计数。不需要你的方法getDaysBetween
,因为代码在 java.time 中非常简单。Duration
类表示未附加到时间轴的时间跨度。然后询问总秒数。
如果你只是想知道已经过去的日历天数,可以使用枚举对象
ChronoUnit.DAYS
和它的between
方法。ncecgwcz2#
在遗留类
Calendar
中,月份是零索引的。这意味着1月表示为0,2月表示为1,依此类推。因此,当您调用getDate(2023,01,01)时,它实际上为2023年2月1日创建了一个java.util.Date对象,而不是2023年1月1日。类似地,当您调用getDate(2023,02,01)时,它将创建一个2023年3月1日的java.util.Date对象。
因此,当你减去这两个日期的时间戳,再除以一天中的毫秒数,你会得到28天的结果,这是2023年2月1日和2023年3月1日之间的正确天数。
要解决此问题,您应该更改getDate方法以使用零索引月份。例如: