Java Date month difference

Viewed 89981

I have start date and end date.

I need the number of months between this two dates in Java.

For example

  • From date: 2009-01-29
  • To date: 2009-02-02

It has one jan date and one Feb date.

It should return 2.

22 Answers

As the rest say, if there's a library that will give you time differences in months, and you can use it, then you might as well.

Otherwise, if y1 and m1 are the year and month of the first date, and y2 and m2 are the year and month of the second, then the value you want is:

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

Note that the middle term, (m2 - m1), might be negative even though the second date is after the first one, but that's fine.

It doesn't matter whether months are taken with January=0 or January=1, and it doesn't matter whether years are AD, years since 1900, or whatever, as long as both dates are using the same basis. So for example don't mix AD and BC dates, since there wasn't a year 0 and hence BC is offset by 1 from AD.

You'd get y1 etc. either from the dates directly if they're supplied to you in a suitable form, or using a Calendar.

Apart from using Joda time which seems to be the the favorite suggestion I'd offer the following snippet:

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: Since Java 8, there is a more standard way of calculating same difference. See my alternative answer using JSR-310 api instead.

I would strongly recommend Joda-Time (and as of Java 8, the Java Time apis) for this.

  1. It makes this sort of work very easy (check out Periods)
  2. It doesn't suffer from the threading issues plaguing the current date/time objects (I'm thinking of formatters, particularly)
  3. It's the basis of the new Java date/time APIs to come with Java 7 (so you're learning something that will become standard)

Note also Nick Holt's comments below re. daylight savings changes.

using joda time would be like this (i compared how many months between today and 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();

Result: 41 months (from july 6th 2009)

should be easy ? :)

ps: you can also convert your date using SimpleDateFormat like:

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

If you don't want to use Joda (for whatever reason), you can convert your date to TimeStamp and then do the differences of milli seconds between both date and then calculate back to months. But I still prefer to use Joda time for the simplicity :)

You can use a Calendar or Joda time library for this.

In Joda time you can use the Days.daysBetween() method. You can then calculate the months difference. You can also use DateTime.getMonthOfYear() and do a subtraction (for dates in the same year).

Joda Time is a pretty cool library for Java Date and Time and can help you achieve what you want using Periods.

It depends on your definition of a month, but this is what we use:

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;

I had to write this implementation, becoz I had custom defined periods, which i had to look for within two dates. Here you can define you custom period and put the logic, for calculation.

Here TimePeriod is a POJO which has start, end, period start, period 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;
}

}

it is not the best anwer but you can use unixtimestamp First you find the unixtime's of the dates then eject each other

Finally you should convert the unixtime(sum) to String

Here a complete implementation for monthDiff in java without iterations. It returns the number of full month between two dates. If you want to include the number of incomplete month in the result (as in the initial question), you have to zero out the day, hours, minutes, seconds and millisecondes of the two dates before calling the method, or you could change the method to not compare days, hours, minutes etc.

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's a full month yeah
                }
            }
        }
    }
    return monthDiff;
}

So many answers with long code when you can just do it with 1 line and some math:

LocalDate from = yourdate;
LocalDate to = yourotherdate;

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