Подтвердить что ты не робот

Разница по месяцам Java

У меня есть дата начала и окончания.

Мне нужно количество месяцев между этими двумя датами в Java.

Например

  • От даты: 2009-01-29
  • На сегодняшний день: 2009-02-02

У этого есть одна дата января и одна дата февраля.

Должен вернуться 2.

4b9b3361

Ответ 1

Как говорят остальные, если есть библиотека, которая даст вам временные разницы в месяцы, и вы можете ее использовать, тогда вы также можете.

В противном случае, если y1 и m1 - это год и месяц первой даты, а y2 и m2 - год и месяц второго, то значение, которое вы хотите:

(y2 - y1) * 12 + (m2 - m1) + 1;

Обратите внимание, что средний член (m2 - m1) может быть отрицательным, даже если вторая дата после первого, но это штраф.

Не имеет значения, взяты ли месяцы с января = 0 или январем = 1, и не имеет значения, являются ли годы AD, годами с 1900 года и т.д., если обе даты используют ту же основу. Так, например, не смешивайте даты AD и BC, так как не было года 0, и поэтому BC смещается на 1 от AD.

Вы получили бы y1 и т.д. либо с дат непосредственно, если они будут предоставлены вам в подходящей форме, либо с помощью Календаря.

Ответ 2

Помимо использования времени Joda, которое, кажется, является излюбленным предложением, я предлагаю следующий фрагмент:

public static final int getMonthsDifference(Date date1, Date date2) {
    int m1 = date1.getYear() * 12 + date1.getMonth();
    int m2 = date2.getYear() * 12 + date2.getMonth();
    return m2 - m1 + 1;
}

EDIT: Начиная с Java 8, существует более стандартный способ вычисления такой же разницы. Посмотрите мой альтернативный ответ с использованием JSR-310 api.

Ответ 3

Я настоятельно рекомендую для этого Joda-Timeначиная с Java 8, Java Time apis).

  1. Это делает такую работу очень простой (ознакомьтесь с периодами)
  2. Он не страдает от проблем с потоками, которые мешают текущим объектам даты/времени (особенно я думаю о форматерах)
  3. Это основа новых API даты/времени Java, которые будут поставляться с Java 7 (так что вы изучаете что-то, что станет стандартом)

Обратите внимание также на комментарии Ника Холта ниже. изменения летнего времени.

Ответ 4

Теперь, когда JSR-310 был включен в SDK Java 8 и выше, здесь более стандартный способ получить месячную разницу двух значения даты:

public static final long getMonthsDifference(Date date1, Date date2) {
    YearMonth m1 = YearMonth.from(date1.toInstant());
    YearMonth m2 = YearMonth.from(date2.toInstant());

    return m1.until(m2, ChronoUnit.MONTHS) + 1;
}

Это позволяет четко определить точность вычисления, и очень легко понять, в чем заключается цель расчета.

Ответ 5

Решение Java 8:

@Test
public void monthBetween() {

    LocalDate d1 = LocalDate.of(2013, Month.APRIL, 1);
    LocalDate d2 = LocalDate.of(2014, Month.APRIL, 1);

    long monthBetween = ChronoUnit.MONTHS.between(d1, d2);

    assertEquals(12, monthBetween);

}

Ответ 6

используя время joda, было бы так (я сравнивал, сколько месяцев между сегодняшним днем ​​и 20/dec/2012)

import org.joda.time.DateTime ;
import org.joda.time.Months;

DateTime x = new DateTime().withDate(2009,12,20); // doomsday lol

Months d = Months.monthsBetween( new DateTime(), x);
int monthsDiff = d.getMonths();

Результат: 41 месяц (с 6 июля 2009 года)

должно быть легко?:)

ps: вы также можете конвертировать свою дату с помощью SimpleDateFormat как:

Date x = new SimpleDateFormat("dd/mm/yyyy").parse("20/12/2009");
DateTime z = new DateTime(x);

Если вы не хотите использовать Joda (по какой бы то ни было причине), вы можете конвертировать свою дату в TimeStamp, а затем выполнять разницу в миллисекундах между датой, а затем рассчитывать до месяца. Но я все же предпочитаю использовать время Джоды для простоты:)

Ответ 7

Основываясь на приведенных выше ответах, я применил свой собственный, который я добавил к существующему классу DateUtils:

    public static Integer differenceInMonths(Date beginningDate, Date endingDate) {
        if (beginningDate == null || endingDate == null) {
            return 0;
        }
        Calendar cal1 = new GregorianCalendar();
        cal1.setTime(beginningDate);
        Calendar cal2 = new GregorianCalendar();
        cal2.setTime(endingDate);
        return differenceInMonths(cal1, cal2);
    }

    private static Integer differenceInMonths(Calendar beginningDate, Calendar endingDate) {
        if (beginningDate == null || endingDate == null) {
            return 0;
        }
        int m1 = beginningDate.get(Calendar.YEAR) * 12 + beginningDate.get(Calendar.MONTH);
        int m2 = endingDate.get(Calendar.YEAR) * 12 + endingDate.get(Calendar.MONTH);
        return m2 - m1;
    }

И ассоциативные модульные тесты:

    public void testDifferenceInMonths() throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
        assertEquals(12, DateUtils.differenceInMonths(sdf.parse("2014/03/22"), sdf.parse("2015/03/22")).intValue());

        assertEquals(11, DateUtils.differenceInMonths(sdf.parse("2014/01/01"), sdf.parse("2014/12/25")).intValue());

        assertEquals(88, DateUtils.differenceInMonths(sdf.parse("2014/03/22"), sdf.parse("2021/07/05")).intValue());

        assertEquals(6, DateUtils.differenceInMonths(sdf.parse("2014/01/22"), sdf.parse("2014/07/22")).intValue());
    }

Ответ 8

Joda Time - довольно классная библиотека для Java Date and Time и может помочь вам достичь того, что вы хотите использовать Period s.

Ответ 9

ТЛ; др

ChronoUnit.MONTHS.between( 
    YearMonth.from( LocalDate.of( 2009 , 1 , 29 ) ) , 
    YearMonth.from( LocalDate.of( 2009 , 2 , 2 ) )
)

Часовой пояс

Ответ Роланда Теппа близок, но игнорирует критическую проблему часового пояса. Для определения месяца и даты требуется часовой пояс, так как в любой данный момент дата меняется по всему земному шару в зависимости от зоны.

ZonedDateTime

Так что его пример преобразования объектов java.util.Date объекты java.time.Instant неявно использует UTC. Значения в любом из этих классов всегда в UTC по определению. Таким образом, вам нужно настроить эти объекты в желаемом/предполагаемом часовом поясе, чтобы иметь возможность извлечь значимую дату.

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdtStart = myJavaUtilDate1.toInstant().atZone( z );
ZonedDateTime zdtStop = myJavaUtilDate2.toInstant().atZone( z );

YearMonth

Поскольку вы хотите знать, сколько календарных месяцев было затронуто вашим диапазоном дат, а не количеством прошедших 30-дневных чанков, преобразуйте их в объекты YearMonth.

YearMonth start = YearMonth.from( zdtStart );
YearMonth stop = YearMonth.from( zdtStop );

ChronoUnit

ChronoUnit месяцы между ними, позвонив в перечисление ChronoUnit.

long monthsBetween = ChronoUnit.MONTHS.between( start , stop );

1

Полуоткрытый

Вы хотели получить результат 2, но мы получаем 1 здесь. Причина в том, что в работе с датой и временем лучшая практика - определять промежутки времени с помощью подхода Half-Open. В Half-Open начало включительно, а окончание - эксклюзивно. Я предлагаю вам придерживаться этого определения на протяжении всей работы с датой и временем, так как это в конечном счете имеет смысл, устраняет запутанные неоднозначности и облегчает умственный анализ вашей работы и делает ее менее подверженной ошибкам. Но если вы настаиваете на своем определении, просто добавьте 1 к результату, предполагая, что у вас есть положительные пронумерованные результаты (то есть ваши промежутки времени идут вперед во времени, а не назад).

LocalDate

Исходный Вопрос неясен, но может потребовать значения только для даты, а не значения даты и времени. Если это так, используйте класс LocalDate. Класс LocalDate представляет значение только для даты без времени суток и без часового пояса.

LocalDate start = LocalDate.of( 2009 , 1 , 29 ) ; 
LocalDate stop = LocalDate.of( 2009 , 2 , 2 ) ;

long monthsBetween = ChronoUnit.MONTHS.between( start ,  stop );

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?

  • Java SE 8, Java SE 9, Java SE 10 и более поздние версии
    • Встроенный.
    • Часть стандартного Java API со встроенной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и Java SE 7
    • Большая часть функциональности java.time перенесена на Java 6 и 7 в ThreeTen-Backport.
  • Android
    • Более поздние версии Android связывают реализации классов java.time.
    • Для более ранних версий Android (<26) проект ThreeTenABP адаптирует ThreeTen-Backport (упомянуто выше). Смотрите Как использовать ThreeTenABP….

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

Ответ 10

Это зависит от вашего определения месяца, но это то, что мы используем:

int iMonths = 0;

Calendar cal1 = GregorianCalendar.getInstance();
cal1.setTime(date1);

Calendar cal2 = GregorianCalendar.getInstance();
cal2.setTime(date2);

while (cal1.after(cal2)){
    cal2.add(Calendar.MONTH, 1);
    iMonths++;
}

if (cal2.get(Calendar.DAY_OF_MONTH) > cal1.get(Calendar.DAY_OF_MONTH)){
            iMonths--;
        }


return iMonths;

Ответ 11

Для этого вы можете использовать календарь или Joda time.

Во время Йоды вы можете использовать метод Days.daysBetween(). Затем вы можете рассчитать разницу в месяцах. Вы также можете использовать DateTime.getMonthOfYear() и делать вычитание (для дат в том же году).

Ответ 12

Мне пришлось написать эту реализацию, потому что у меня были определенные определенные периоды, которые я должен был искать в течение двух дат. Здесь вы можете определить свой пользовательский период и поместить логику для расчета.

Здесь TimePeriod - это POJO, у которого есть начало, конец, начало периода, период End

public class Monthly extends Period {

public int getPeriodCount(String startDate, String endDate, int scalar) {
    int cnt = getPeriods(startDate, endDate, scalar).size();        
    return cnt;
}

public List getPeriods(String startDate, String endDate, int scalar) {

    ArrayList list = new ArrayList();

    Calendar startCal = CalendarUtil.getCalendar(startDate);
    Calendar endCal =  CalendarUtil.getCalendar(endDate);

    while (startCal.compareTo(endCal) <= 0) {
        TimePeriod period = new TimePeriod();
        period.setStartDate(startCal.getTime());
        period.setPeriodStartDate(getPeriodStartDate((Calendar) startCal.clone()).getTime());
        Calendar periodEndCal = getPeriodEndDate((Calendar) startCal.clone(), scalar);
        period.setEndDate(endCal.before(periodEndCal) ? endCal.getTime()    : periodEndCal.getTime());
        period.setPeriodEndDate(periodEndCal.getTime());

        periodEndCal.add(Calendar.DATE, 1);
        startCal = periodEndCal;
        list.add(period);
    }

    return list;
}


private Calendar getPeriodStartDate(Calendar cal) {     
    cal.set(Calendar.DATE, cal.getActualMinimum(Calendar.DATE));        
    return cal;
}

private Calendar getPeriodEndDate(Calendar cal, int scalar) {

    while (scalar-- > 0) {
        cal.set(Calendar.DATE, cal.getActualMaximum(Calendar.DATE));
        if (scalar > 0)
            cal.add(Calendar.DATE, 1);          
    }

    return cal;
}

}

Ответ 13

это не лучший anwer, но вы можете использовать unixtimestamp Сначала вы найдете unixtime дат затем выталкивать друг друга

Наконец, вы должны преобразовать unixtime (sum) в String

Ответ 14

Что, поскольку классы Java Дата и Календарь используют индексы месяца из 0-11

January = 0
December = 1

Рекомендуется использовать Joda Time!

Ответ 15

Вот решение с использованием объекта java.util.Calendar:

private static Integer getMonthsBetweenDates(Date d1, Date d2) {
    Calendar todayDate = getCalendar(d1);
    Calendar pastDate = getCalendar(d2);

    int yearDiff = todayDate.get(Calendar.YEAR) - pastDate.get(Calendar.YEAR);
    if (pastDate.get(Calendar.MONTH) < 11 && pastDate.get(Calendar.DAY_OF_MONTH) < 31){ //if pastDate is smaller than 31/12
        yearDiff++;
    }

    int monthCount = 0;
    for (int year = 0 ; year < yearDiff ; year++){
        if (year == 0) {
            monthCount += 12 - pastDate.get(Calendar.MONTH);
        } else if (year == yearDiff - 1){ //last year
            if (todayDate.get(Calendar.MONTH) < pastDate.get(Calendar.MONTH)){
                monthCount += todayDate.get(Calendar.MONTH) + 1;
            } else if (todayDate.get(Calendar.MONTH) >= pastDate.get(Calendar.MONTH) && todayDate.get(Calendar.DAY_OF_MONTH) < pastDate.get(Calendar.DAY_OF_MONTH)){
                monthCount += todayDate.get(Calendar.MONTH);
            } else if (todayDate.get(Calendar.MONTH) >= pastDate.get(Calendar.MONTH) && todayDate.get(Calendar.DAY_OF_MONTH) >= pastDate.get(Calendar.DAY_OF_MONTH)){
                monthCount += todayDate.get(Calendar.MONTH) + 1;
            }
        }
        for (int months = 0 ; months < 12 ; months++){
            if (year > 0 && year < yearDiff -1){
                monthCount++;
            }
        }
    }
    return monthCount;
}

Ответ 16

Почему бы не рассчитать с полным временем

 public static Integer calculateMonthDiff(Date begining, Date end) throws Exception {

        if (begining.compareTo(end) > 0) {
            throw new Exception("Beginning date is greater than the ending date");
        }

        if (begining.compareTo(end) == 0) {
            return 0;
        }

        Calendar cEndCheckDate = Calendar.getInstance();
        cEndCheckDate.setTime(begining);
        int add = 0;
        while (true) {
            cEndCheckDate.add(Calendar.MONTH, 1);
            add++;
            if (cEndCheckDate.getTime().compareTo(end) > 0) {
                return add - 1;
            }
        }
    }

Ответ 17

Полный фрагмент кода для определения разницы между месяцами между двумя датами выглядит следующим образом:

public String getContractMonth(String contractStart, String contractEnd) {
    SimpleDateFormat dfDate = new SimpleDateFormat("yyyy-MM-dd");
    String months = "0";
    try {
        Date startDate = dfDate.parse(contractStart);
        Date endDate = dfDate.parse(contractEnd);

        Calendar startCalendar = Calendar.getInstance();
        startCalendar.setTime(startDate);
        Calendar endCalendar = Calendar.getInstance();
        endCalendar.setTime(endDate);

        int diffYear = endCalendar.get(Calendar.YEAR) - startCalendar.get(Calendar.YEAR);
        int diffMonth = diffYear * 12 + endCalendar.get(Calendar.MONTH) - startCalendar.get(Calendar.MONTH);
        months = diffMonth + "";
    } catch (ParseException e) {
        e.printStackTrace();
    } catch (java.text.ParseException e) {
        e.printStackTrace();
    }
    return months;
}

Ответ 18

ниже логика выберет вам разницу в месяцах

(endCal.get(Calendar.YEAR)*12+endCal.get(Calendar.MONTH))-(startCal.get(Calendar.YEAR)*12+startCal.get(Calendar.MONTH))

Ответ 19

Вы можете за 30 дней или по месяцам:

public static void main(String[] args) throws IOException {

        int n = getNumbertOfMonth(LocalDate.parse("2016-08-31"),LocalDate.parse("2016-11-30"));
        System.out.println("number of month = "+n);

         n = getNumbertOfDays(LocalDate.parse("2016-08-31"),LocalDate.parse("2016-11-30"));
        System.out.println("number of days = "+n);
        System.out.println("number of 30 days = "+n/30);
    }
        static int getNumbertOfMonth(LocalDate dateDebut, LocalDate dateFin) {

        LocalDate start = dateDebut;
        LocalDate end = dateFin;
        int count = 0 ;
        List<String> lTotalDates = new ArrayList<>();
        while (!start.isAfter(end)) {
            count++;
            start =  start.plusMonths(1);
        }
        return count;
    }

    static int getNumbertOfDays(LocalDate dateDebut, LocalDate dateFin) {

        LocalDate start = dateDebut;
        LocalDate end = dateFin;
        int count = 0 ;
        List<String> lTotalDates = new ArrayList<>();
        while (!start.isAfter(end)) {
            count++;
            start =  start.plusDays(1);
        }
        return count;
    }

Ответ 20

long monthsBetween = ChronoUnit.MONTHS.between(LocalDate.parse("2016-01-29").minusMonths(1),
            LocalDate.parse("2016-02-02").plusMonths(1));
  1. 2016-01-29 до 2016-01-02 = месяцы 1
  2. 2016-02-29 до 2016-02-02 = месяцы 1
  3. 2016-03-29 до 2016-05-02 = 5 месяцев

Ответ 21

Здесь полная реализация monthDiff в Java без итераций. Возвращает номер полного месяца между двумя датами. Если вы хотите включить в результат число неполных месяцев (как в первоначальном вопросе), вам нужно обнулить день, часы, минуты, секунды и миллисекунды двух дат перед вызовом метода, или вы можете изменить способ не сравнивать дни, часы, минуты и т.д.

import java.util.Date;
import java.util.Calendar;
...
public static int monthDiff(Date d1, Date d2) {
    int monthDiff;

    Calendar c1, c2;
    int M1, M2, y1, y2, t1, t2, h1, h2, m1, m2, s1, s2, ms1, ms2;

    c1 = Calendar.getInstance();
    c1.setTime(d1);

    c2 = Calendar.getInstance();
    c2.setTime(d2);

    M1 = c1.get(Calendar.MONTH);
    M2 = c2.get(Calendar.MONTH);
    y1 = c1.get(Calendar.YEAR);
    y2 = c2.get(Calendar.YEAR);
    t1 = c1.get(Calendar.DAY_OF_MONTH);
    t2 = c2.get(Calendar.DAY_OF_MONTH);

    if(M2 < M1) { 
        M2 += 12;
        y2--;
    }

    monthDiff = 12*(y2 - y1) + M2 - M1;

    if(t2 < t1)
        monthDiff --; // not a full month
    else if(t2 == t1) { // perhaps a full month, we have to look into the details
        h1 = c1.get(Calendar.HOUR_OF_DAY);
        h2 = c2.get(Calendar.HOUR_OF_DAY);
        if(h2 < h1)
            monthDiff--; // not a full month
        else if(h2 == h1) { // go deeper
            m1 = c1.get(Calendar.MINUTE);
            m2 = c2.get(Calendar.MINUTE);
            if(m2 < m1) // not a full month
                monthDiff--;
            else if(m2 == m1) { // look deeper
                s1 = c1.get(Calendar.SECOND);
                s2 = c2.get(Calendar.SECOND);
                if(s2 < s1)
                    monthDiff--; // on enleve l'age de mon hamster
                else if(s2 == s1) { 
                    ms1 = c1.get(Calendar.MILLISECOND);
                    ms2 = c2.get(Calendar.MILLISECOND);
                    if(ms2 < ms1)
                        monthDiff--;
                    // else // it a full month yeah
                }
            }
        }
    }
    return monthDiff;
}

Ответ 22

Вы можете попробовать this-

Date startDate = // Set start date
Date endDate   = // Set end date

long duration  = endDate.getTime() - startDate.getTime();

long diffInSeconds = TimeUnit.MILLISECONDS.toSeconds(duration);
long diffInMinutes = TimeUnit.MILLISECONDS.toMinutes(duration);
long diffInHours = TimeUnit.MILLISECONDS.toHours(duration);
long diffInDays = TimeUnit.MILLISECONDS.toDays(duration);

Ответ 23

Так много ответов с длинным кодом, когда вы можете просто сделать это с 1 строкой и немного математики:

LocalDate from = yourdate;
LocalDate to = yourotherdate;

int difference = to.getMonthValue() - from.getMonthValue()) + ((to.getYear() - from.getYear()) * 12) + 1;