Emil Kaminski
Emil Kaminski

Reputation: 1885

find days difference between 2 dates and how many days in each month

I could use some help with this method I'm trying to make. I have a Problem Object, which has a target date and i need to find out how many days this problem is late divided/split by months, compared to today's date.

Image this situation: Lets say that today's date is 05-02-2013.

ID  Target date
P1  02-02-2013
P2  27-01-2013
P3  26-01-2013
P4  05-12-2012

This means that each problem is this many days late in the following months:

    DEC JAN FEB
P1          3
P2      4   5
P3      5   5
P4  26  31  5

A problem can not be older than 12 months.

Now i need a method to sum these numbers storing the month name and a summed number of late days. If the target month and now month are the same, its an easy case, because i can just substract the days and store the month, but what to do when its not the case? I have the following code:

List<Problem> problems = problemQuery.getResultList(); //Problems list is already filtered and contain only late problems. 

Calendar now = Calendar.getInstance();
Calendar before = Calendar.getInstance();
Map<Integer, Integer> newMap = new TreeMap<Integer, Integer>(); //map that contains month number and daysLateCount

for (Problem p : problems) {
    before.setTime(p.getTarget_date());
    int nowMonth = now.get(Calendar.MONTH);
    int beforeMonth = before.get(Calendar.MONTH);
    if (beforeMonth == nowMonth) { //easy case when both dates have same month
        int result = now.get(Calendar.DAY_OF_MONTH) - before.get(Calendar.DAY_OF_MONTH);
        if (newMap.containsKey(nowMonth)) {
            int newLateDaysValue = newMap.get(nowMonth)+result; //get old result and add the new
            newMap.put(nowMonth, newLateDaysValue);
        }                   
        else {
            newMap.put(nowMonth, result);
        }
    }
    else {
                         //What to do here???
    }
}

Perhaps i could even skip the if-else clause and make an algorithm that could handle both cases? I don't know please help :)

Upvotes: 1

Views: 377

Answers (4)

VGR
VGR

Reputation: 44338

The year is needed, if only to know how many days are in February.

    for (Problem p : problems) {
        int nowYear = now.get(Calendar.YEAR);
        int nowMonth = now.get(Calendar.MONTH);
        int nowDay = now.get(Calendar.DAY_OF_MONTH);

        before.setTime(p.getTarget_date());
        int beforeYear = before.get(Calendar.YEAR);
        int beforeMonth = before.get(Calendar.MONTH);
        int beforeDay = before.get(Calendar.DAY_OF_MONTH);
        while (beforeYear < nowYear || beforeMonth < nowMonth) {
            int daysInMonth =
                before.getActualMaximum(Calendar.DAY_OF_MONTH);
            int result = daysInMonth - beforeDay;

            Integer oldLateDaysValue = newMap.get(beforeMonth);
            newMap.put(beforeMonth,
                oldLateDaysValue == null ?
                    result : (oldLateDaysValue + result));

            // For all subsequent months, calculate using entire month.
            beforeDay = 0;

            before.add(Calendar.MONTH, 1);
            beforeYear = before.get(Calendar.YEAR);
            beforeMonth = before.get(Calendar.MONTH);
        }

        int result = nowDay - beforeDay;

        Integer oldLateDaysValue = newMap.get(beforeMonth);
        newMap.put(beforeMonth,
            oldLateDaysValue == null ?
                result : (oldLateDaysValue + result));
    }

    System.out.println(newMap);
}

Upvotes: 1

Modus Tollens
Modus Tollens

Reputation: 5123

A solution using Joda-Time:

LocalDate today = new LocalDate(2013, 2, 5);
LocalDate targetDate = new LocalDate(2012, 12, 5); // example with target date P4

LocalDate begin = targetDate;
LocalDate end = begin.dayOfMonth().withMaximumValue();

while (end.isBefore(today)) {
    Days days = Days.daysBetween(begin, end);
    if (days.getDays() > 0) {
        System.out.println(end.monthOfYear().getAsText() + ": " + days.getDays());
    }

    begin = end;
    end = begin.plusDays(1).dayOfMonth().withMaximumValue();
}

end = today;
Days days = Days.daysBetween(begin, end);
if (days.getDays() > 0) {
    System.out.println(end.monthOfYear().getAsText() + ": " + days.getDays());
}

Prints the following result for e.g. target date P4:

December: 26
January: 31
February: 5

Upvotes: 1

Husman
Husman

Reputation: 6909

I think there is a relatively simple solution to this, the algorithm is as follows:

import java.util.Calendar;

public class test {

    public static void main(String[] args){

        Calendar today = Calendar.getInstance();
        Calendar problemDate = Calendar.getInstance();

        today.set(2013, 01, 05);
        problemDate.set(2012, 11, 05);
        System.out.println(today.getTime());
        System.out.println(problemDate.getTime());

        // This might need further validation to make sure today >= problemDate
        int diffYear = today.get(Calendar.YEAR) - problemDate.get(Calendar.YEAR);
        int differenceInMonths = diffYear * 12 + today.get(Calendar.MONTH) - problemDate.get(Calendar.MONTH);
        //int differenceInMonths = today.get(Calendar.MONTH) - problemDate.get(Calendar.MONTH);

        for(int i = 0; i <= differenceInMonths; i++) {
          int daysDifference;

          if (differenceInMonths == 0) {
             daysDifference = today.get(Calendar.DAY_OF_MONTH) - problemDate.get(Calendar.DAY_OF_MONTH);
          } else {
            if ( i == 0) { // first month
              daysDifference = problemDate.getActualMaximum(Calendar.DAY_OF_MONTH) - problemDate.get(Calendar.DAY_OF_MONTH);
            }
            else if( i == differenceInMonths ) { // last month
              daysDifference = today.get(Calendar.DAY_OF_MONTH);
            }
            else {
              Calendar cal= Calendar.getInstance();
              cal.set(Calendar.MONTH, problemDate.get(Calendar.MONTH) + i);
              daysDifference = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
            } 
                  }

          System.out.println(daysDifference);
        }
    }
}

Which outputs:

Tue Feb 05 14:35:43 GMT 2013
Wed Dec 05 14:35:43 GMT 2012
26
31
5

You should be able to wrap this up into your code, and in a loop fairly easily, and also remove the print statements to insert into whatever data structure you have.

Upvotes: 1

Petr
Petr

Reputation: 6269

The best way is to use Joda Time library: http://www.joda.org/joda-time/

Java Date/Time API is not very good and useful for such purposes.

Upvotes: 3

Related Questions