我如何找到两个joda time DateTime实例之间的天数差异?如果开始时间是星期一,结束时间是星期二,那么不管开始和结束日期的小时/分钟/秒是多少,返回值都应该是1。
如果从晚上开始到早上结束,Days.daysBetween(start, end).getDays()给我0。
我对其他日期字段也有同样的问题,所以我希望有一种通用的方法来"忽略"那些意义较小的字段。
换句话说,2月和3月4日之间的月份也是1,14:45到15:12之间的时间也是1。但是14:01和14:55之间的小时差为0。
令人恼火的是,withTimeatStartofDay的答案是错误的,但只是偶尔。你想要:
Days.daysBetween(start.toLocalDate(), end.toLocalDate()).getDays()
事实证明,"午夜/一天的开始"有时意味着凌晨1点(日光节约在某些地方是这样发生的),而白天之间的时间处理得不好。
// 5am on the 20th to 1pm on the 21st, October 2013, Brazil
DateTimeZone BRAZIL = DateTimeZone.forID("America/Sao_Paulo");
DateTime start = new DateTime(2013, 10, 20, 5, 0, 0, BRAZIL);
DateTime end = new DateTime(2013, 10, 21, 13, 0, 0, BRAZIL);
System.out.println(daysBetween(start.withTimeAtStartOfDay(),
end.withTimeAtStartOfDay()).getDays());
// prints 0
System.out.println(daysBetween(start.toLocalDate(),
end.toLocalDate()).getDays());
// prints 1
通过LocalDate避开了整个问题。
您能否提供一个示例案例,其中包含您认为Days.daysBetween不正确的特定数据?
@巴兹堡-我的答案中已经有了这个例子。
当你说要使用Instant时,你不仅仅是在谈论start.toInstant(),是吗?
@帕特里克是的,我是。经过深思熟虑,我们还不清楚这到底是要施加什么约束,所以我将删除最后一句话。谢谢!
@Chrispy Daysbetween医生说它返回整天的数据。在我的情况下,2天1小时应该可以让我返回3天。在您的示例中,它返回2天。有没有办法做到这一点?
@苏吉乔希,恐怕我不明白你的问题。我建议发布一个完整的堆栈溢出问题并为我粘贴一个链接:)
注意日期与新年重叠!2016年12月31日至2017年1月5日之间的天数为-361天。
@西尔夫,不,不,我刚检查过。我怀疑你2017年打字错误。
Days类
使用Days类和withTimeAtStartOfDay方法应该可以:
Days.daysBetween(start.withTimeAtStartOfDay() , end.withTimeAtStartOfDay() ).getDays()
谢谢!我试图用joda实现android.text.format.dateutils.getrelativeTimespanstring()的行为,这非常有用。
先生,关于本文,不推荐使用来自日期时间类型的方法toDateMidnight()。
现在应该使用.withTimeAtStartOfDay()而不是.todateMidnight()。
如果end在start之前,它是否返回负天数?
@阿凯亚:你为什么不试试呢?
您可以使用LocalDate:
Days.daysBetween(new LocalDate(start), new LocalDate(end)).getDays()
先生,关于本文,不推荐使用来自日期时间类型的方法toDateMidnight()。
更新…
为什么用new LocalDate(date)代替date.toLocalDate()?
DR
java.time.temporal.ChronoUnit.DAYS.between(
earlier.truncatedTo( ChronoUnit.DAYS ) ,
later.truncatedTo( ChronoUnit.DAYS )
)
…或…
java.time.temporal.ChronoUnit.HOURS.between(
earlier.truncatedTo( ChronoUnit.HOURS ) ,
later.truncatedTo( ChronoUnit.HOURS )
)
Java.时间
仅供参考,Joda Time项目现在处于维护模式,团队建议迁移到java.time类。
与joda时间DateTime相当的是ZonedDateTime。
ZoneId z = ZoneId.of("Pacific/Auckland" ) ;
ZonedDateTime now = ZonedDateTime.now( z ) ;
显然,你想按日期数日,这意味着你想忽略一天中的时间。例如,从午夜前的一分钟开始到午夜后的一分钟结束应该会导致一天。对于这种行为,从您的ZonedDateTime中提取一个LocalDate。LocalDate类表示没有时间和时区的仅日期值。
LocalDate localDateStart = zdtStart.toLocalDate() ;
LocalDate localDateStop = zdtStop.toLocalDate() ;
使用ChronoUnit枚举计算经过的天数或其他单位。
long days = ChronoUnit.DAYS.between( localDateStart , localDateStop ) ;
截断
至于你想问一个更一般的方法来做这个计数,如果你感兴趣的是小时的增量作为时钟的小时,而不是完整的小时作为60分钟的时间跨度,使用truncatedTo方法。
这是你在同一天14:45到15:12的例子。
ZoneId z = ZoneId.of("America/Montreal" );
ZonedDateTime start = ZonedDateTime.of( 2017 , 1 , 17 , 14 , 45 , 0 , 0 , z );
ZonedDateTime stop = ZonedDateTime.of( 2017 , 1 , 17 , 15 , 12 , 0 , 0 , z );
long hours = ChronoUnit.HOURS.between( start.truncatedTo( ChronoUnit.HOURS ) , stop.truncatedTo( ChronoUnit.HOURS ) );
1
按日期计算的天数,截断为ChronoUnit.DAYS。这里有一个例子,在1过去的几天里,午夜从5分钟前滚动到5分钟后。
ZoneId z = ZoneId.of("America/Montreal" );
ZonedDateTime start = ZonedDateTime.of( 2017 , 1 , 17 , 23 , 55 , 0 , 0 , z );
ZonedDateTime stop = ZonedDateTime.of( 2017 , 1 , 18 , 00 , 05 , 0 , 0 , z );
long days = ChronoUnit.DAYS.between( start.truncatedTo( ChronoUnit.DAYS ) , stop.truncatedTo( ChronoUnit.DAYS ) );
1
关于JavaTimes
JavaTimeFr框架是在Java 8和之后构建的。这些类取代了麻烦的旧遗留日期时间类,如java.util.Date、Calendar和SimpleDateFormat。
现在处于维护模式的joda time项目建议迁移到java.time类。
要了解更多信息,请参阅Oracle教程。以及搜索堆栈溢出以获得许多示例和解释。规格为JSR 310。
您可以直接与数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC驱动程序。不需要字符串,不需要java.sql.*类。
在哪里获取java.time类?
Java SE 8、Java SE 9、Java SE 10以及以后
内置的。
标准JAVA API的一部分与捆绑实现。
Java 9添加了一些小的特性和修复。
Java SE 6和Java SE 7
大部分JavaTimeActudio都被移植到TealEnter后端的Java 6和7中。
安卓
java.time类的Android包实现的更高版本。
对于早期的Android(<26),threetenabp项目适应threeten backport(如上所述)。看看如何使用三连珠……
threeten额外项目使用额外的类扩展java.time。这个项目是将来可能添加到java.time的一个试验场。您可以在这里找到一些有用的类,如Interval、YearWeek、YearQuarter等等。
threeten额外项目使用额外的类扩展java.time。这个项目是将来可能添加到java.time的一个试验场。您可以在这里找到一些有用的类,如Interval、YearWeek、YearQuarter等等。
接受的答案构建了两个LocalDate对象,如果您正在读取大量数据,这是非常昂贵的。我用这个:
public static int getDaysBetween(DateTime earlier, DateTime later)
{
return (int) TimeUnit.MILLISECONDS.toDays(later.getMillis()- earlier.getMillis());
}
通过调用getMillis()可以使用已经存在的变量。那么,MILLISECONDS.toDays()使用简单的算术计算,不创建任何对象。
只有当您对"天"的定义正好是24小时,而不考虑时区和日期时,此答案才有效。如果是这样,使用这种方法。如果没有,请查看其他解决时区问题的答案。
@巴兹尔布尔克,你说得对,不过,我还是想找一个基于算术计算的解决方案,而不是为每个方法调用构建昂贵的对象,这样的计算有很多味道,如果你正在从网页中读取输入,可能没问题,但是如果你正在处理一个有数十万行的日志文件只是让它很慢
如果循环是热的,Java将优化对象分配。见docs.oracle.com/javase/7/docs/technotes/guides/vm/&hellip;
java.time.Period
使用java.time.Period类计算天数。
由于Java 8计算的差异更直观,使用EDCOX1,0,EDCOX1,30表示两个日期。
LocalDate now = LocalDate.now();
LocalDate inputDate = LocalDate.of(2018, 11, 28);
Period period = Period.between( inputDate, now);
int diff = period.getDays();
System.out.println("diff =" + diff);
DateTime dt = new DateTime(laterDate);
DateTime newDate = dt.minus( new DateTime ( previousDate ).getMillis());
System.out.println("No of days :" + newDate.getDayOfYear() - 1 );
public static int getDifferenceIndays(long timestamp1, long timestamp2) {
final int SECONDS = 60;
final int MINUTES = 60;
final int HOURS = 24;
final int MILLIES = 1000;
long temp;
if (timestamp1 < timestamp2) {
temp = timestamp1;
timestamp1 = timestamp2;
timestamp2 = temp;
}
Calendar startDate = Calendar.getInstance(TimeZone.getDefault());
Calendar endDate = Calendar.getInstance(TimeZone.getDefault());
endDate.setTimeInMillis(timestamp1);
startDate.setTimeInMillis(timestamp2);
if ((timestamp1 - timestamp2) < 1 * HOURS * MINUTES * SECONDS * MILLIES) {
int day1 = endDate.get(Calendar.DAY_OF_MONTH);
int day2 = startDate.get(Calendar.DAY_OF_MONTH);
if (day1 == day2) {
return 0;
} else {
return 1;
}
}
int diffDays = 0;
startDate.add(Calendar.DAY_OF_MONTH, diffDays);
while (startDate.before(endDate)) {
startDate.add(Calendar.DAY_OF_MONTH, 1);
diffDays++;
}
return diffDays;
}
这个问题是专门寻找乔达的时间。