2

I want to get the number of working days in a specific month

in my case the weekend days are FRIDAY and SATURDAY

I use this code :

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

public class TestWeekDay {

    /**
     * @param args
     * @throws ParseException 
     */
    public static void main(String[] args) throws ParseException {

        // TODO Auto-generated method stub


        SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
        String dateInString = "01-07-2016";
        Date startDate = sdf.parse(dateInString);
        String dateInString2 = "31-07-2016";
        Date endDate = sdf.parse(dateInString2);
        calculateDuration(startDate,endDate);

    }



    public static int calculateDuration(Date startDate, Date endDate)
    {
      Calendar startCal = Calendar.getInstance();
      startCal.setTime(startDate);

      Calendar endCal = Calendar.getInstance();
      endCal.setTime(endDate);

      int workDays = 0;

      if (startCal.getTimeInMillis() > endCal.getTimeInMillis())
      {
        startCal.setTime(endDate);
        endCal.setTime(startDate);
      }

      do
      {
        startCal.add(Calendar.DAY_OF_MONTH, 1);
        if (startCal.get(Calendar.DAY_OF_WEEK) != Calendar.FRIDAY && startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY)
        {
          workDays++;
        }
      }
      while (startCal.getTimeInMillis() <= endCal.getTimeInMillis());

      return workDays;
    }

}

when I test for example for July month I have 22 and the correct response should be 21

franco
  • 1,829
  • 6
  • 42
  • 75
  • Please see [What is a debugger and how can it help me diagnose problems?](http://stackoverflow.com/q/25385173/5221149) – Andreas Jul 18 '16 at 06:44
  • 1
    Do you have a particular reason for using `Date` and `Calendar`, rather than the java 8 time API? – Andy Turner Jul 18 '16 at 06:47

5 Answers5

3

If you add the following line after the if statement, you will see your problem.

System.out.printf("%s  %d%n", new SimpleDateFormat("yyyy-MM-dd EEE").format(startCal.getTime()), workDays);

BTW: This is called debugging.

Output

2016-07-02 Sat  0
2016-07-03 Sun  1
2016-07-04 Mon  2
2016-07-05 Tue  3
2016-07-06 Wed  4
2016-07-07 Thu  5
2016-07-08 Fri  5
2016-07-09 Sat  5
2016-07-10 Sun  6
2016-07-11 Mon  7
2016-07-12 Tue  8
2016-07-13 Wed  9
2016-07-14 Thu  10
2016-07-15 Fri  10
2016-07-16 Sat  10
2016-07-17 Sun  11
2016-07-18 Mon  12
2016-07-19 Tue  13
2016-07-20 Wed  14
2016-07-21 Thu  15
2016-07-22 Fri  15
2016-07-23 Sat  15
2016-07-24 Sun  16
2016-07-25 Mon  17
2016-07-26 Tue  18
2016-07-27 Wed  19
2016-07-28 Thu  20
2016-07-29 Fri  20
2016-07-30 Sat  20
2016-07-31 Sun  21
2016-08-01 Mon  22
22

As you can see, you have two problems:

  • The first day of the month (2016-07-01) is not checked
  • The first day of next month (2016-08-01) is checked

I'll leave it to you to figure out a solution. Good luck.

Andreas
  • 154,647
  • 11
  • 152
  • 247
1

I think your problem may be caused by a boundary condition which is resulting in one extra day being added to each month before the evaluation. Try doing the day of week check first before you increment the actual day.

while (startCal.getTimeInMillis() <= endCal.getTimeInMillis()) {
    if (startCal.get(Calendar.DAY_OF_WEEK) != Calendar.FRIDAY &&
        startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY) {

        workDays++;
    }

    startCal.add(Calendar.DAY_OF_MONTH, 1);
}
Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
  • Your code fixes the problem, but your description is misleading, at least the way I read it. It is not changing from `do {} while()` to `while() {}` that fixes the problem, it is moving the `add()` call to the end of the loop that does it. Said another way, it it not the *loop check* that must be before the *increment*, it is the *day-of-week check* that must be before the increment. – Andreas Jul 18 '16 at 06:56
  • @Andreas Yes, I realized this before your comment, and I will update now. Thanks as always for your vigilence. – Tim Biegeleisen Jul 18 '16 at 06:56
1
Calendar cal = Calendar.getInstance();
/* set the 1st date of ongoing month */
cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), 1, 0, 0, 1);
Calendar cal1 = Calendar.getInstance();
/* set the last date of ongoing month */
cal1.set(cal1.get(Calendar.YEAR), cal1.get(Calendar.MONTH), cal1.getMaximum(Calendar.DAY_OF_MONTH), 23, 59, 59);
int workingDays = 0;
/* run the while loop until the months are same */
while (cal.get(Calendar.MONTH) != cal1.get(Calendar.MONTH)) {
      if (cal.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY
           && cal.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY) {
                System.out.println("Check >> "+ cal.getTime());
                workingDays++;
      }
      cal.add(Calendar.DAY_OF_MONTH, 1);
}
System.out.println(workingDays);
0

Use this piece of code, just run loop until the condition startCal after endCal return false.

while(!startCal.after(endCal)) {
      if (startCal.get(Calendar.DAY_OF_WEEK) != Calendar.FRIDAY && startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY) {
        workDays++;
      }
      startCal.add(Calendar.DATE, 1);
  }
Arjit
  • 3,290
  • 1
  • 17
  • 18
-1

Replace the <= in your while condition to < as shown below -

while (startCal.getTimeInMillis() < endCal.getTimeInMillis());

This is creating problem because for the last day of the month, your condition (initially with the <=) returns true, because finally after incrementing the startCal by 1 day it becomes equal to endCal at a point. Because of becoming equal, your following line gets executed in the do

startCal.add(Calendar.DAY_OF_MONTH, 1);

and thus the next date is 1st of April which is is Monday. And thus this gets added to the list of working days too.

NOTE - Please follow @Andreas comment to debug your code. With a little debugging you could have found the issue easily. And again debugging the code is very essential for developers. You can't just ignore it!

As rightly pointed by @Andreas, the 1st day of the month won't be checked too. In order to check the 1st day, you need to compare the 1st day first and then increment the day by 1. The below is the code -

 do
   {
      if (startCal.get(Calendar.DAY_OF_WEEK) != Calendar.FRIDAY &&   startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY)
      {
          workDays++;
      }
      startCal.add(Calendar.DAY_OF_MONTH, 1); //Moved this line to last of do block
   }
   while (startCal.getTimeInMillis() < endCal.getTimeInMillis());
Manish
  • 710
  • 3
  • 12
  • 25