Java日历:将两个日期/时间之间的差减一
我看到了很多关于这个话题的问题和答案,但没有一个能解决我的问题。我扩展了java Calendar类(标准——没有第三方库),需要找出两个任意日期之间天的差异 方法:Java日历:将两个日期/时间之间的差减一,java,date,calendar,datediff,Java,Date,Calendar,Datediff,我看到了很多关于这个话题的问题和答案,但没有一个能解决我的问题。我扩展了java Calendar类(标准——没有第三方库),需要找出两个任意日期之间天的差异 方法: 将两个日期的时间更改为午夜 将日期转换为毫秒 找出两个日期之间的差异 将结果除以一天中的毫秒数(24*60* 60*1000) 结果应该是以天为单位的差异 有时是,有时不是。即使是在同一天进行的测试也可能被取消一次。发生了什么事?您在第一步中通过将时间设置为午夜来识别问题:这确保了所有的小时、分钟和秒都为零。但你走得不够远!您还必
有时是,有时不是。即使是在同一天进行的测试也可能被取消一次。发生了什么事?您在第一步中通过将时间设置为午夜来识别问题:这确保了所有的小时、分钟和秒都为零。但你走得不够远!您还必须确保毫秒也归零 这里有一些代码可以做到这一点
protected long truncate_to_seconds (long date_in_millis) {
long l = date_in_millis / 1000L;
l *= 1000L;
return l;
}
我认为,在计算差异之前,您需要从日期开始截断时间部分,如下所示:
DateFormat formatter= new SimpleDateFormat("MM/dd/yyyy");
String truncatedDateString1 = formatter.format(date1);
Date truncatedDate1 = formatter.parse(truncatedDateString1);
String truncatedDateString2 = formatter.format(date2);
Date truncatedDate2 = formatter.parse(truncatedDateString2);
long timeDifference = truncatedDate2.getTime()- truncatedDate1.getTime();
int daysInBetween = timeDifference / (24*60*60*1000);
希望这能起作用。该库对此类问题提供了很好的支持:
LocalDate d1 = new LocalDate(calendar1.getTimeInMillis());
LocalDate d2 = new LocalDate(calendar2.getTimeInMillis());
int days = Days.daysBetween(d1, d2).getDays();
更新(来自@basil bourque的反馈):
从Java 8开始,新的时间库Java.time
已经引入,现在可以使用一个没有外部依赖项的类似选项:
int days = Duration.between(calendar1.toInstant(), calendar2.toInstant()).toDays();
正如其他用户所建议的,您还需要将日历的毫秒值设置为零,以便只比较日期。这可以通过以下代码段实现:
someCalendar.set(Calendar.MILLISECOND, 0)
另外,请注意,时区的变化(例如,从冬季时间移到夏季时间)可能意味着一天中的时间大于或小于86400000毫秒。应您的要求,我有自己的功能。我使用日历,在比较之前,我将所有时间部分设置为0
int countDays(Date dateBegin, Date dateEnd) {
if (dateBegin == null || dateEnd == null)
return 0;
Calendar from = asCalendar(dateBegin); // asCalendar() Initialise a Calendar from a Date
Calendar to = asCalendar(dateEnd);
// Set the time part to 0
from.set(Calendar.MILLISECOND, 0);
from.set(Calendar.SECOND, 0);
from.set(Calendar.MINUTE, 0);
from.set(Calendar.HOUR_OF_DAY, 0);
to.set(Calendar.MILLISECOND, 0);
to.set(Calendar.SECOND, 0);
to.set(Calendar.MINUTE, 0);
to.set(Calendar.HOUR_OF_DAY, 0);
int nbJours = 0;
for (Calendar c = from ; c.before(to) ; c.add(Calendar.DATE, +1))
{
nbJours++;
}
for (Calendar c = from ; c.after(to) ; c.add(Calendar.DATE, -1))
{
nbJours--;
}
return nbJours;
}
tl;博士
天真的计算
您在代码中假设每天正好24小时。不是真的。异常情况,如表示天数可能不同,如23小时长、25小时或其他数字。时区的真正含义是跟踪这些异常的历史
另外,假设一天从午夜开始。不是真的。由于异常情况,有些日子从一天中的其他时间开始,如01:00
避免遗留日期时间类
您使用的是麻烦的旧日期时间类,例如,和java.text.SimpleTextFormat
现在已被这些类取代
时区
以大陆/地区
的格式指定,例如,或太平洋/奥克兰
。切勿使用3-4个字母的缩写,如EST
或IST
,因为它们不是真正的时区,也不是标准化的,甚至不是唯一的(!)
不要扩展java.time
不要扩展java.time类(子类)(它们被标记为final
)
不要将它们的接口概括为您的业务逻辑;坚持这个框架的具体类。虽然在其他框架(如java.time)中,泛化是有意义的,但在java.time中则不然
使用java.time
使用java.time类,这项工作要容易得多
表示时间线上具有指定tim区域(ZoneId
)的时刻
枚举可以计算一对时刻之间经过的时间
long days = ChronoUnit.DAYS.between( then , now );
看
然后.toString():2017-01-23T12:34:56.123456789-05:00[美国/蒙特利尔]
now.toString():2017-03-01T21:26:04.884-05:00[美国/蒙特利尔]
天数:37
将遗留实例转换为java.time
如果给定了对象,请使用添加到旧类中的新方法将其转换为java.time
ZonedDateTime zdt = myGregCal.toZonedDateTime() ;
如果您知道一个日历
实例实际上是一个格里高利安日历
,请将其强制转换
GregorianCalendar myGregCal = (GregorianCalendar) myCal ;
半开
time类通过半开放方法定义时间跨度,其中开始是包含的,而结束是独占的
关于java.time 该框架内置于Java8及更高版本中。这些类取代了麻烦的旧日期时间类,例如,& 该项目现已启动,建议迁移到类 要了解更多信息,请参阅。并搜索堆栈溢出以获得许多示例和解释。规格是 从哪里获得java.time类
- 后来
- 内置的李>
- 标准JavaAPI的一部分,带有捆绑实现
- Java9添加了一些次要功能和修复
- 及
- 大部分java.time功能都在中向后移植到Java6和Java7
-
- 该项目专门为Android采用了ThreeTen Backport(如上所述)
- 看
该项目使用其他类扩展了java.time。这个项目是java.time将来可能添加的一个试验场。您可以在这里找到一些有用的类,如、、和。我已经编写了一种更简单的方法来解决这个问题,即使我遇到了同样的问题,在某些日期额外安排一天 这是我目前的做法,
public long getDays(long currentTime, long endDateTime) {
Calendar endDateCalendar;
Calendar currentDayCalendar;
//expiration day
endDateCalendar = Calendar.getInstance(TimeZone.getTimeZone("EST"));
endDateCalendar.setTimeInMillis(endDateTime);
endDateCalendar.set(Calendar.MILLISECOND, 0);
endDateCalendar.set(Calendar.MINUTE, 0);
endDateCalendar.set(Calendar.HOUR, 0);
//current day
currentDayCalendar = Calendar.getInstance(TimeZone.getTimeZone("EST"));
currentDayCalendar.setTimeInMillis(currentTime);
currentDayCalendar.set(Calendar.MILLISECOND, 0);
currentDayCalendar.set(Calendar.MINUTE, 0);
currentDayCalendar.set(Calendar.HOUR, 0);
long remainingDays = Math.round((float) (endDateCalendar.getTimeInMillis() - currentDayCalendar.getTimeInMillis()) / (24 * 60 * 60 * 1000));
return remainingDays;
}
之前我用的是这条线,其余的都一样:-
long remainingDays = TimeUnit.MILLISECONDS.toDays(
Math.abs(expiryCalendar.getTimeInMillis() - currentDayCalendar.getTimeInMillis()));
但似乎对我不起作用。另一方面,您确定扩展
日历
而不是生成在日历
实例上运行的帮助程序库是一个好主意吗?一个问题是,您假设一天有86400000毫秒。无需使用truncate方法,他只需将日历
实例上的毫秒归零,就可以设置集(Calendar.millissecond,0)
@DuncanJones,甚至更好!没有看到日历库的那个方面,谢谢@邓肯·琼斯:请加上这个作为回答,这样我就可以给你适当的信用。@ScottBiggs:很高兴知道。请不要忘记接受答案。优雅的解决方案!我应该更彻底地阅读文档(就像我们都有时间一样!)。仅供参考,麻烦的旧日期时间cla
public long getDays(long currentTime, long endDateTime) {
Calendar endDateCalendar;
Calendar currentDayCalendar;
//expiration day
endDateCalendar = Calendar.getInstance(TimeZone.getTimeZone("EST"));
endDateCalendar.setTimeInMillis(endDateTime);
endDateCalendar.set(Calendar.MILLISECOND, 0);
endDateCalendar.set(Calendar.MINUTE, 0);
endDateCalendar.set(Calendar.HOUR, 0);
//current day
currentDayCalendar = Calendar.getInstance(TimeZone.getTimeZone("EST"));
currentDayCalendar.setTimeInMillis(currentTime);
currentDayCalendar.set(Calendar.MILLISECOND, 0);
currentDayCalendar.set(Calendar.MINUTE, 0);
currentDayCalendar.set(Calendar.HOUR, 0);
long remainingDays = Math.round((float) (endDateCalendar.getTimeInMillis() - currentDayCalendar.getTimeInMillis()) / (24 * 60 * 60 * 1000));
return remainingDays;
}
long remainingDays = TimeUnit.MILLISECONDS.toDays(
Math.abs(expiryCalendar.getTimeInMillis() - currentDayCalendar.getTimeInMillis()));