关于Java: Joda-Time时间中两个日期之间的天数

Number of days between two dates in Joda-Time

我如何找到两个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的答案是错误的,但只是偶尔。你想要:

1
Days.daysBetween(start.toLocalDate(), end.toLocalDate()).getDays()

事实证明,"午夜/一天的开始"有时意味着凌晨1点(日光节约在某些地方是这样发生的),而白天之间的时间处理得不好。

1
2
3
4
5
6
7
8
9
10
// 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

使用Days类和withTimeAtStartOfDay方法应该可以:

1
Days.daysBetween(start.withTimeAtStartOfDay() , end.withTimeAtStartOfDay() ).getDays()


您可以使用LocalDate

1
Days.daysBetween(new LocalDate(start), new LocalDate(end)).getDays()


DR

1
2
3
4
java.time.temporal.ChronoUnit.DAYS.between(
    earlier.truncatedTo( ChronoUnit.DAYS )  ,
    later.truncatedTo( ChronoUnit.DAYS )
)

…或…

1
2
3
4
java.time.temporal.ChronoUnit.HOURS.between(
    earlier.truncatedTo( ChronoUnit.HOURS )  ,
    later.truncatedTo( ChronoUnit.HOURS )
)

Java.时间

仅供参考,Joda Time项目现在处于维护模式,团队建议迁移到java.time类。

与joda时间DateTime相当的是ZonedDateTime

1
2
ZoneId z = ZoneId.of("Pacific/Auckland" ) ;
ZonedDateTime now = ZonedDateTime.now( z ) ;

显然,你想按日期数日,这意味着你想忽略一天中的时间。例如,从午夜前的一分钟开始到午夜后的一分钟结束应该会导致一天。对于这种行为,从您的ZonedDateTime中提取一个LocalDateLocalDate类表示没有时间和时区的仅日期值。

1
2
LocalDate localDateStart = zdtStart.toLocalDate() ;
LocalDate localDateStop = zdtStop.toLocalDate() ;

使用ChronoUnit枚举计算经过的天数或其他单位。

1
long days = ChronoUnit.DAYS.between( localDateStart , localDateStop ) ;

截断

至于你想问一个更一般的方法来做这个计数,如果你感兴趣的是小时的增量作为时钟的小时,而不是完整的小时作为60分钟的时间跨度,使用truncatedTo方法。

这是你在同一天14:45到15:12的例子。

1
2
3
4
5
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分钟后。

1
2
3
4
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.DateCalendarSimpleDateFormat

现在处于维护模式的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的一个试验场。您可以在这里找到一些有用的类,如IntervalYearWeekYearQuarter等等。

threeten额外项目使用额外的类扩展java.time。这个项目是将来可能添加到java.time的一个试验场。您可以在这里找到一些有用的类,如IntervalYearWeekYearQuarter等等。


接受的答案构建了两个LocalDate对象,如果您正在读取大量数据,这是非常昂贵的。我用这个:

1
2
3
4
  public static int getDaysBetween(DateTime earlier, DateTime later)
  {
    return (int) TimeUnit.MILLISECONDS.toDays(later.getMillis()- earlier.getMillis());
  }

通过调用getMillis()可以使用已经存在的变量。那么,MILLISECONDS.toDays()使用简单的算术计算,不创建任何对象。


java.time.Period

使用java.time.Period类计算天数。

由于Java 8计算的差异更直观,使用EDCOX1,0,EDCOX1,30表示两个日期。

1
2
3
4
5
6
    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);


1
2
3
4
5
DateTime  dt  = new DateTime(laterDate);        

DateTime newDate = dt.minus( new  DateTime ( previousDate ).getMillis());

System.out.println("No of days :" + newDate.getDayOfYear() - 1 );

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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;
}