Количество дней между двумя датами в Joda-Time - PullRequest
315 голосов
/ 27 сентября 2010

Как найти разницу в днях между двумя Joda-Time DateTime экземплярами? Под «разницей в днях» я подразумеваю, если начало - в понедельник, а конец - во вторник, я ожидаю возвращаемое значение 1 независимо от часа / минуты / секунд дат начала и окончания.

Days.daysBetween(start, end).getDays() дает мне 0, если начало вечером и конец утром.

У меня тоже такая же проблема с другими полями даты, поэтому я надеялся, что найдется общий способ «игнорировать» поля меньшей значимости.

Другими словами, месяцы с февраля по 4 марта также будут равны 1, как и часы с 14:45 до 15:12. Однако разница часов между 14:01 и 14:55 будет равна 0.

Ответы [ 8 ]

375 голосов
/ 31 июля 2013

К сожалению, ответ withTimeAtStartOfDay неверен, но только изредка. Вы хотите:

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

Оказывается, что "полночь / начало дня" иногда означает 1 час ночи (в некоторых местах происходит летнее время), который Days.daysBetween не обрабатывает должным образом.

// 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 обходит весь вопрос.

183 голосов
/ 27 сентября 2010

Days Класс

Использование класса Days с методом withTimeAtStartOfDay должно работать:

Days.daysBetween(start.withTimeAtStartOfDay() , end.withTimeAtStartOfDay() ).getDays() 
83 голосов
/ 27 сентября 2010

вы можете использовать LocalDate:

Days.daysBetween(new LocalDate(start), new LocalDate(end)).getDays() 
6 голосов
/ 22 августа 2017

ТЛ; др

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.time

К вашему сведению, проект Joda-Time теперь находится в режиме обслуживания , и команда рекомендует перейти на классы java.time .

Эквивалент Joda-Time DateTime равен ZonedDateTime.

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

Очевидно, вы хотите посчитать дни по датам, то есть вы хотите игнорировать время суток. Например, начиная с минуты до полуночи и заканчивая минутой после полуночи, вы получите один день. Для этого поведения извлеките LocalDate из вашего ZonedDateTime. Класс LocalDate представляет значение только для даты без времени суток и без часового пояса.

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

Используйте перечисление ChronoUnit для расчета прошедших дней или других единиц.

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

Округление

Что касается вопроса о более общем способе подсчета, когда вас интересует разница часов в часах, а не полных часов в промежутке в шестьдесят минут, используйте 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.

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


О java.time

Фреймворк java.time встроен в Java 8 и более поздние версии. Эти классы вытесняют проблемные старые устаревшие классы даты и времени, такие как java.util.Date, Calendar, & SimpleDateFormat.

Проект Joda-Time , теперь в режиме обслуживания , рекомендует выполнить переход на классы java.time .

Чтобы узнать больше, см. Oracle Tutorial . И поиск переполнения стека для многих примеров и объяснений. Спецификация JSR 310 .

Вы можете обмениваться java.time объектами напрямую с вашей базой данных. Используйте драйвер JDBC , совместимый с JDBC 4.2 или более поздней версии. Нет необходимости в строках, нет необходимости в java.sql.* классах.

Где получить классы java.time?

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Здесь вы можете найти некоторые полезные классы, такие как Interval, YearWeek, YearQuarter и more .

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Здесь вы можете найти несколько полезных классов, таких как Interval, YearWeek, YearQuarter и еще .

2 голосов
/ 21 июня 2016

Принятый ответ создает два LocalDate объекта, которые довольно дороги, если вы читаете много данных.Я использую это:

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

Вызывая getMillis(), вы используете уже существующие переменные.
MILLISECONDS.toDays() затем, используя простой арифметический расчет, не создает никакого объекта.

1 голос
/ 28 ноября 2018

java.time.Period

Используйте класс java.time.Period для подсчета дней .

Поскольку в Java 8 вычисление разницы более интуитивно понятно с использованием LocalDate, LocalDateTime для представления двух дат

    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);
0 голосов
/ 09 ноября 2018
DateTime  dt  = new DateTime(laterDate);        

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

System.out.println("No of days : " + newDate.getDayOfYear() - 1 );    
0 голосов
/ 24 декабря 2014
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;
}
...