16

How can I add business days to the current date in Java?

public Calendar addBusinessDate(Calendar cal, int days) {
//
// code goes over here
//
}

Note:

It should consider weekends too.

OscarRyz
  • 196,001
  • 113
  • 385
  • 569
Anand
  • 1,137
  • 3
  • 9
  • 12
  • How are you defining holidays? And what have you tried so far? – ChssPly76 Oct 07 '09 at 23:51
  • 2
    **MISTER** Minion, thankyouverymuch – OMG Ponies Oct 07 '09 at 23:57
  • Oh Yeah.. I have to consider public holiday like Christmas, Thanks giving day, labour day too. – Anand Oct 08 '09 at 00:22
  • @akf - leave my tag alone, will you please? OP has not exactly been forthcoming with any details regarding the implementation, so this very much looks like work order. I'll be the first to remove the tag and up-vote the question as soon as I see some effort put into it. – ChssPly76 Oct 08 '09 at 02:37
  • ChssPly76, I certainly agree that this is not the most attractive post due to the covertly selfish posture of the OP. However, I don't think that new tags are the way to convey this. – akf Oct 08 '09 at 02:44
  • IMO, this is just a variant of the tag mentioned here: http://meta.stackexchange.com/questions/10078/whats-the-difference-between-an-obvious-homework-question-and-one-tagged-plzsend/10086#10086 – akf Oct 08 '09 at 02:53
  • FYI, the terribly troublesome old date-time classes such as [`java.util.Date`](https://docs.oracle.com/javase/10/docs/api/java/util/Date.html), [`java.util.Calendar`](https://docs.oracle.com/javase/10/docs/api/java/util/Calendar.html), and `java.text.SimpleDateFormat` are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [*java.time*](https://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes built into Java 8 and later. See [*Tutorial* by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Sep 14 '18 at 21:45

14 Answers14

31

You may want to consider using ObjectLab Kit to do the heavy lifting for you.

Assuming the requirement is simply to return the next business day when the computed date falls on a non-business day:

package bizdays.example;

import java.time.LocalDate;
import java.util.HashSet;
import net.objectlab.kit.datecalc.common.DateCalculator;
import net.objectlab.kit.datecalc.common.DefaultHolidayCalendar;
import net.objectlab.kit.datecalc.common.HolidayHandlerType;
import net.objectlab.kit.datecalc.jdk8.LocalDateKitCalculatorsFactory;
import static org.junit.Assert.assertThat;
import org.junit.Before;
import org.junit.Test;
import static org.hamcrest.Matchers.equalTo;

public class BizDayTest {
    private DateCalculator<LocalDate> dateCalculator;
    private final LocalDate startDate = LocalDate.of(2009, 12, 23);

    @Before
    public void setUp() {
        HashSet<LocalDate> holidays = new HashSet<LocalDate>();
        holidays.add(LocalDate.of(2009, 12, 25));  // Friday

        DefaultHolidayCalendar<LocalDate> holidayCalendar =
            new DefaultHolidayCalendar<LocalDate>(holidays);

        LocalDateKitCalculatorsFactory.getDefaultInstance()
                .registerHolidays("example", holidayCalendar);
        dateCalculator = LocalDateKitCalculatorsFactory.getDefaultInstance()
                .getDateCalculator("example", HolidayHandlerType.FORWARD);
        dateCalculator.setStartDate(startDate);
    }

    @Test
    public void should_not_change_calendar_start_date_even_after_moving() {
        assertThat(
            dateCalculator.moveByBusinessDays(6).getStartDate(),
            equalTo(startDate));
    }

    @Test
    public void moveByBusinessDays_will_return_24_dec_2009_as_next_business_day() {
        assertThat(
            dateCalculator.moveByBusinessDays(1).getCurrentBusinessDate(),
            equalTo(LocalDate.of(2009, 12, 24)));
    }

    @Test
    public void moveByBusinessDays_will_return_28_dec_2009_as_two_business_days_later() {
        assertThat(
            dateCalculator.moveByBusinessDays(2).getCurrentBusinessDate(),
            equalTo(LocalDate.of(2009, 12, 28)));

    }

    @Test
    public void moveByDays_will_also_return_28_dec_2009_as_two_business_days_later() {
        assertThat(
            dateCalculator.moveByDays(2).getCurrentBusinessDate(),
            equalTo(LocalDate.of(2009, 12, 28)));
    }

    @Test
    public void moveByBusinessDays_will_exclude_25_26_and_27_dec_when_computing_business_days() {
        assertThat(
            dateCalculator.moveByBusinessDays(5).getCurrentBusinessDate(),
            equalTo(LocalDate.of(2009, 12, 31)));
    }


    @Test
    public void moveByDays_will_include_25_26_and_27_dec_when_computing_business_days() {
        assertThat(
            dateCalculator.moveByDays(5).getCurrentBusinessDate(),
            equalTo(LocalDate.of(2009, 12, 28)));
    }
}

The library defaults the working week to be from Monday to Friday, but you can change the defaults by supplying a custom WorkingWeek to DateCalculator's setWorkingWeek().

As shown in the last two examples, moveByDays() includes the weekends when moving the days, whereas moveByBusinessDays() excludes weekends.

The library also allows you to use java.util.Calendar or Joda Time's LocalDate. The examples use JDK8's java.time.LocalDate because it is the preferred way since JDK8.

Edit: Updated examples to use java.time.LocalDate

shaolang
  • 995
  • 11
  • 25
6

Use:

public Calendar addBusinessDate(Calendar cal, int numBusinessDays) {
  int numNonBusinessDays = 0;

  for(int i = 0; i < numBusinessDays; i++) {
    cal.add(Calendar.DATE, 1);

    /*
       It's a Canadian/American custom to get the Monday (sometimes Friday) off
       when a holiday falls on a weekend.
    */
    for(int j = 0; j < holidays; j++) { //holidays is list of dates
      if(cal.getTime() == (Date)holidays.get(j)) {
        numNonBusinessDays++;
      }
    }

    if(cal.get(Calendar.DAY_OF_WEEK) == 1 ||
       cal.get(Calendar.DAY_OF_WEEK) == 7) {
      numNonBusinessDays++;
    }
  }

  if(numNonBusinessDays > 0) {
    cal.add(Calendar.DATE, numNonBusinessDays);
  }

  return cal;
}

You'd have to populate a list of dates in order to handle holidays. There's common ones like New Years, but Thanksgiving is different between Canada & the US for instance. Also mind that holidays can fall on a weekend, so the weekend becomes a 3 day weekend.

Reference:

PS: There isn't really a need to return the Calendar instance if you are updating the value as in the example. But it is valid if you want to create a separate Calendar instance, use:

public Calendar addBusinessDate(Calendar cal, int numBusinessDays) {
  Calendar cal2 = Calendar.getInstance();
  cal2.setTime(cal.getTime());

  int numNonBusinessDays = 0;

  for(int i = 0; i < numBusinessDays; i++) {
    cal2.add(Calendar.DATE, 1);

    /*
       It's a Canadian/American custom to get the Monday (sometimes Friday) off
       when a holiday falls on a weekend.
    */
    for(int j = 0; j < holidays; j++) { //holidays is list of dates
      if(cal2.getTime() == (Date)holidays.get(j)) {
        numNonBusinessDays++;
      }
    }

    if(cal2.get(Calendar.DAY_OF_WEEK) == 1 ||
       cal2.get(Calendar.DAY_OF_WEEK) == 7) {
      numNonBusinessDays++;
    }
  }

  if(numNonBusinessDays > 0) {
    cal2.add(Calendar.DATE, numNonBusinessDays);
  }

  return cal2;
}
OMG Ponies
  • 325,700
  • 82
  • 523
  • 502
  • So January 1st, 2009 is a business day because it happens to fall on Thursday? – ChssPly76 Oct 07 '09 at 23:59
  • You'd think so, but no :-) Checking date equality via '==' is not going to work. – ChssPly76 Oct 08 '09 at 02:07
  • I don't think that's what you meant to do because current version won't compile (assignment to function result _and_ within if condition). My point was that you can't check date equality by reference. Incidentally, for what you're trying to do `equals()` is not going to work either due to time portion. I'm upvoting you for the effort put in :-) and I suggest you let the OP figure out the rest of this. – ChssPly76 Oct 08 '09 at 02:34
  • @OMG Ponies: why add numNonBusinessDays but use a loop to add 1 for each numBusinessDays? – Otis Dec 23 '09 at 19:06
  • also if an holiday falls on weekday 1 or 7 (better use constants: `Calendar.SATERDAY`, ...), we get 2 days added... – user85421 Dec 29 '09 at 15:19
  • @Carlos: Because when a holiday falls on a weekend, it's a Canadian/American custom to get the Monday (sometimes Friday) off. – OMG Ponies Dec 29 '09 at 17:07
  • @Otis: Because you have to loop through the list of holiday dates to compare to the current date value in order to determine if it is a holiday. At least, I think that is what your question is about - I'm unsure. – OMG Ponies Dec 29 '09 at 17:14
  • that's a nice *rule*... we don't have that in Brazil or Germany :-/ but, anyway, found a problem: `cal2.get(Calendar.DAY_OF_WEEK) = 1` won't work, should be `==` – user85421 Dec 30 '09 at 18:10
  • 1
    @Carlos: It's already been mentioned that holidays are regional; holiday handling understandably would be too. I never said the example covered all conventions but I look forward to see yours that does. I have to wonder how the accepted answer, encapsulating the logic, handles such regional differences... – OMG Ponies Dec 30 '09 at 18:24
  • @OMG Ponies: just wanted to help (and understand), sorry if you got that wrong... – user85421 Dec 31 '09 at 16:36
  • does the solution correctly handles non business days? I would expect a Wednesday adds 3 business days would return me a Monday. Seems this answer returns a Sunday. A while loop to skip all non buz days probably easier to understand and simpler to implement. Something like ``` for (int i = 0; i < numDays; i++) { day.add(Calendar.DATE, 1); while (day.get(Calendar.DAY_OF_WEEK) == 1 || day.get(Calendar.DAY_OF_WEEK) == 7) { day.add(Calendar.DATE, 1); } } ``` – Yuming Cao Dec 07 '16 at 22:54
6

Here is the modified version to find date calculation.

public  Calendar algorithm2(int businessDays){
    Calendar cal2 = Calendar.getInstance();
    Calendar cal = Calendar.getInstance(); 
    int totalDays= businessDays/5*7;
    int remainder = businessDays % 5;
    cal2.add(cal2.DATE, totalDays); 

    switch(cal.get(Calendar.DAY_OF_WEEK)){
        case 1:
                break;
        case 2: 
                break;
        case 3: 
                if(remainder >3)
                cal2.add(cal2.DATE,2);
                break;
        case 4: 
                if(remainder >2)
                cal2.add(cal2.DATE,2);
                break;
        case 5: 
                if(remainder >1)
                cal2.add(cal2.DATE,2);
                break;
        case 6: 
                if(remainder >1)
                cal2.add(cal2.DATE,2);
                break;
        case 7: 
                if(remainder >1)
                cal2.add(cal2.DATE,1);
                break;
    }

    cal2.add(cal2.DATE, remainder); 
    return cal2;

}
Anand
  • 1,137
  • 3
  • 9
  • 12
5

//supports negative numbers too.

private Calendar addBusinessDay(final Calendar cal, final Integer numBusinessDays)
{
    if (cal == null || numBusinessDays == null || numBusinessDays.intValue() == 0)
    {
        return cal;
    }
    final int numDays = Math.abs(numBusinessDays.intValue());
    final int dateAddition = numBusinessDays.intValue() < 0 ? -1 : 1;//if numBusinessDays is negative
    int businessDayCount = 0;
    while (businessDayCount < numDays)
    {
        cal.add(Calendar.DATE, dateAddition);

        //check weekend
        if (cal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY)
        {
            continue;//adds another day
        }

        //check holiday
        if (isHoliday(cal))//implement isHoliday yourself
        {
            continue;//adds another day
        }

        businessDayCount++;
    }
    return cal;
}
user2961462
  • 51
  • 1
  • 1
3
public static Date addBusinessDays(Date date, int days) {

    DateTime result = new DateTime(date);
    result = isWeekEnd(result)
        ? getPreviousBusinessDate(result)
        : result;

    for (int i = 0; i < days; i++) {
        if (isWeekEnd(result)) {
            i--;
        }
        result = result.plusDays(1);
    }
    return result.toDate();
}

private static boolean isWeekEnd(DateTime dateTime) {
    int dayOfWeek = dateTime.getDayOfWeek();
    return dayOfWeek == DateTimeConstants.SATURDAY || dayOfWeek == DateTimeConstants.SUNDAY;
}

private static DateTime getPreviousBusinessDate(DateTime result) {
    while (isWeekEnd(result)) {
        result = result.minusDays(1);
    }

    return result;
}
jetuns
  • 31
  • 1
  • Using Joda-Time? This Answer needs some explanation. – Basil Bourque Sep 14 '18 at 21:46
  • FYI, the [*Joda-Time*](http://www.joda.org/joda-time/) project is now in [maintenance mode](https://en.wikipedia.org/wiki/Maintenance_mode), with the team advising migration to the [*java.time*](http://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes. See [Tutorial by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Sep 14 '18 at 21:47
2

Will this work? Of course, this is not handling holidays.

public static Date addBusinessDays(Date baseDate, int numberOfDays){

    if(baseDate == null){
        baseDate = new Date();
    }

    Calendar baseDateCal = Calendar.getInstance();
    baseDateCal.setTime(baseDate);

    for(int i = 0; i < numberOfDays; i++){

        baseDateCal.add(Calendar.DATE,1);
        if(baseDateCal.get(Calendar.DAY_OF_WEEK)
                         == Calendar.SATURDAY){
           baseDateCal.add(Calendar.DATE,2);
        }
    }
    return baseDateCal.getTime();
}
rudolf
  • 21
  • 1
2

tl;dr

Going forward.

myLocalDate.with( 
    org.threeten.extra.Temporals.nextWorkingDay() 
)

Going backward.

myLocalDate.with( 
    org.threeten.extra.Temporals.previousWorkingDay() 
)

Using java.time

The Question and other Answers use the troublesome old date-time classes, now legacy, supplanted by the java.time classes.

Also, see my Answer to a similar Question.

TemporalAdjuster

In java.time, the TemporalAdjuster interface provides for classes to manipulate date-time values. Using immutable objects, a new instance is created with values based on the original.

nextWorkingDay

The ThreeTen-Extra project extend java.time with additional functionality. That includes a nextWorkingDay adjuster that skips over Saturday and Sunday days. So we can loop, incrementing a date one day at a time, and skip over any weekend days.

The LocalDate class represents a date-only value without time-of-day and without time zone.

LocalDate start = LocalDate.now( ZoneId.of( "America/Montreal" ) ) ;
int businessDaysToAdd = 13 ;
// … ensure that: ( businessDaysToAdd >= 0 )

int daysLeft = businessDaysToAdd ;
LocalDate localDate = start ;
while ( daysLeft > 0 ) {
    localDate = localDate.with( Temporals.nextWorkingDay() );
    daysLeft = ( daysLeft - 1 ) ;  // Decrement as we go.
}
return localDate ;

Holidays

Holidays are an entirely different matter. Obviously there is no simple solution. You must either supply a list of your honored holidays, or obtain a list with which you agree.

Once you have such a list, I suggest writing your own implementation of TemporalAdjuster similar to nextWorkingDay.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Community
  • 1
  • 1
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
1

This algorithm calculates the next business date for a given date (business days are from monday to friday in my country), you can adapt it to iterate the number of days you need to add.

public Calendar nextBusinessDate(Calendar cal) {

    List<Calendar> holidays = ********
    // Here get list of holidays from DB or some other service...

    GregorianCalendar calCp = new GregorianCalendar();
    calCp.setTime(cal.getTime());
    calCp.add(Calendar.DAY_OF_MONTH, 1);

    boolean isSaturday = (calCp.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY);
    boolean isSunday = (calCp.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY);
    boolean isHoliday = holidays.contains(calCp);

    while (isSaturday || isSunday || isHoliday) {
      if (isSaturday) {
          calCp.add(Calendar.DAY_OF_MONTH, +2); // is saturday, make it monday
        } else {
        if (isSunday) {
            calCp.add(Calendar.DAY_OF_MONTH, +1); // is sunday, make it monday
        } else {
            if (isHoliday) {
                 calCp.add(Calendar.DAY_OF_MONTH, +1); // is holiday, make it next day
               }
            }
        }
      calCp = new GregorianCalendar();
      calCp.setTime(cal.getTime());
      isSaturday = (calCp.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY);
      isSunday = (calCp.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY);
    isHoliday = holidays.contains(calCp);
    } // end while

    return calCp;
}
JuanZe
  • 8,007
  • 44
  • 58
  • I think that `holidays.contains()` will not work. The `Calendar.equals()` (also) use milliseconds to compare the dates. – user85421 Dec 29 '09 at 15:31
1

O(1) version that works and supports different weekend patterns and negative days:

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class DateUtil {

//Weekend patterns
public static  final int WEEKEND_SAT_SUN = 0;
public static  final int WEEKEND_FRI_SAT = 1;
public static  final int WEEKEND_THU_FRI = 2;
public static  final int WEEKEND_FRI_SUN = 3;
public static  final int WEEKEND_FRI = 4;
public static  final int WEEKEND_SAT = 5;
public static  final int WEEKEND_SUN = 6;


//Weekend pattern by country 
//@see https://en.wikipedia.org/wiki/Workweek_and_weekend
public static Map<String,Integer> weekendPatternByCountry = new HashMap<>();
static {
    weekendPatternByCountry.put("CO",WEEKEND_SUN);     //Colombia
    weekendPatternByCountry.put("GQ",WEEKEND_SUN);     //Equatorial Guinea
    weekendPatternByCountry.put("IN",WEEKEND_SUN);     //India
    weekendPatternByCountry.put("MX",WEEKEND_SUN);     //Mexico
    weekendPatternByCountry.put("KP",WEEKEND_SUN);     //North Korea
    weekendPatternByCountry.put("UG",WEEKEND_SUN);     //Uganda
    weekendPatternByCountry.put("BN",WEEKEND_FRI_SUN); //Brunei Darussalam
    weekendPatternByCountry.put("DJ",WEEKEND_FRI);     //Djibouti
    weekendPatternByCountry.put("IR",WEEKEND_FRI);     //Iran
    weekendPatternByCountry.put("AF",WEEKEND_THU_FRI); //Afghanistan
    weekendPatternByCountry.put("NP",WEEKEND_SAT);     //Nepal
    weekendPatternByCountry.put("DZ",WEEKEND_FRI_SAT); //Algeria
    weekendPatternByCountry.put("BH",WEEKEND_FRI_SAT); //Bahrain
    weekendPatternByCountry.put("BD",WEEKEND_FRI_SAT); //Bangladesh
    weekendPatternByCountry.put("EG",WEEKEND_FRI_SAT); //Egypt
    weekendPatternByCountry.put("IQ",WEEKEND_FRI_SAT); //Iraq
    weekendPatternByCountry.put("IL",WEEKEND_FRI_SAT); //Israel
    weekendPatternByCountry.put("JO",WEEKEND_FRI_SAT); //Jordan
    weekendPatternByCountry.put("KW",WEEKEND_FRI_SAT); //Kuwait
    weekendPatternByCountry.put("LY",WEEKEND_FRI_SAT); //Libya
    weekendPatternByCountry.put("MV",WEEKEND_FRI_SAT); //Maldives
    weekendPatternByCountry.put("MR",WEEKEND_FRI_SAT); //Mauritania
    weekendPatternByCountry.put("MY",WEEKEND_FRI_SAT); //Malaysia
    weekendPatternByCountry.put("OM",WEEKEND_FRI_SAT); //Oman
    weekendPatternByCountry.put("PS",WEEKEND_FRI_SAT); //Palestine
    weekendPatternByCountry.put("QA",WEEKEND_FRI_SAT); //Qatar
    weekendPatternByCountry.put("SA",WEEKEND_FRI_SAT); //Saudi Arabia
    weekendPatternByCountry.put("SD",WEEKEND_FRI_SAT); //Sudan
    weekendPatternByCountry.put("SY",WEEKEND_FRI_SAT); //Syria
    weekendPatternByCountry.put("AE",WEEKEND_FRI_SAT); //United Arab Emirates
    weekendPatternByCountry.put("YE",WEEKEND_FRI_SAT); //Yemen
}

//Adjustment vectors - precomputed adjustment
static int[][][] adjVector = new int[][][]{
    {//WEEKEND_SAT_SUN
        //Positive number of days
        {1,0,-1,-2,-3,1,1},
        {0,0},
        {0,0,0,0,0,2,1},
        //Negative number of days
        {-1,3,2,1,0,-1,-1},
        {0,0},
        {-1,1,1,1,1,1,0}
    },
    {//WEEKEND_FRI_SAT
        //Positive number of days
        {0,-1,-2,-3,1,1,1},
        {0,0},
        {0,0,0,0,2,1,0},
        //Negative number of days
        {3,2,1,0,-1,-1,-1},
        {0,0},
        {1,1,1,1,1,0,-1}
    },
    {//WEEKEND_THU_FRI
        //Positive number of days
        {-1,-2,-3,1,1,1,0},
        {0,0},
        {0,0,0,2,1,0,0},
        //Negative number of days
        {2,1,0,-1,-1,-1,3},
        {0,0},
        {1,1,1,1,0,-1,1}
    },
    {//WEEKEND_FRI_SUN
        //Positive number of days
        {0,-1,-2,-3,-4,-4,0},
        {1,0},
        {0,0,0,0,0,-1,1},
        //Negative number of days
        {4,3,2,1,0,0,4},
        {0,-1},
        {1,1,1,1,1,0,2}
    },
    {//WEEKEND_FRI
        //Positive number of days
        {-1,-2,-3,-4,1,1,0},
        {0},
        {0,0,0,0,1,0,0},
        //Negative number of days
        {3,2,1,0,-1,-1,4},
        {0},
        {1,1,1,1,1,0,1}
    },
    {//WEEKEND_SAT
        //Positive number of days
        {0,-1,-2,-3,-4,1,1},
        {0},
        {0,0,0,0,0,1,0},
        //Negative number of days
        {4,3,2,1,0,-1,-1},
        {0},
        {1,1,1,1,1,1,0}
    },
    {//WEEKEND_SUN
        //Positive number of days
        {1,0,-1,-2,-3,-4,1},
        {0},
        {0,0,0,0,0,0,1},
        //Negative number of days
        {-1,4,3,2,1,0,-1},
        {0},
        {0,1,1,1,1,1,1}
    }
};

//O(1) algorithm to add business days.
public static Date addBusinessDays(Date day, int days,int weekendPattern){
    Calendar ret = Calendar.getInstance();
    if(day != null) {
        ret.setTime(day);
    }
    if(days != 0) {
        int startDayofWeek  = ret.get(Calendar.DAY_OF_WEEK)-1; //Zero based to use the vectors bellow.
        int idx = days > 0 ? 0 : 3;
        int howManyWeekendDays = 0;
        int[][] adjV = adjVector[weekendPattern];
        int numWeekendDaysInOneWeek = adjV[idx+1].length;

        for(int i  = 0; i < numWeekendDaysInOneWeek;i++){
            int adjustmentA = adjV[idx][startDayofWeek];  //pattern shift
            int adjustmentB = adjV[idx+1][i];             //day shift

            howManyWeekendDays += (days-adjustmentA-adjustmentB)/(7-numWeekendDaysInOneWeek); 
        }

        int adjustmentC = adjV[idx+2][startDayofWeek]; //f(0) adjustment
        howManyWeekendDays += adjustmentC;

        ret.add(Calendar.DATE,days + howManyWeekendDays);

        //TODO: Extend to support holidays using recursion
        // int numHolidays = getNumHolidaysInInterval(day,ret.getTime());
        // if(numHolidays > 0) return addBusinessDays(ret.getTime,numHolidays);
    }
    return ret.getTime();
}

public static Date addBusinessDays(Date day, int days,String country){
    Integer weekpat = weekendPatternByCountry.get(country);     
    return weekpat != null ? addBusinessDays(day,days,weekpat) : addBusinessDays(day,days,WEEKEND_SAT_SUN);
}
}
  • @Anand algorithm2 is wrong when: date is Saturday or Sunday and days 5,10,15,.. , or when date is Friday and days 1, 6, 11, 16. – Ezio Anselmo Mazarim Fernandes Oct 01 '15 at 05:40
  • I'd like your solution but you should check current day is not a holiday \n here \n // if(numHolidays > 0) return addBusinessDays(ret.getTime,numHolidays); \n because you will count same holidays twice – Shakirov Ramil Mar 01 '21 at 13:40
  • minus operation will return wrong. For example (16.02.2021, -1) => 16.02.2021 instead of 15.02.2021. At least SAT_SUN_HOLIDAYS. In case of minus day, I just add extra -1 before calling – Shakirov Ramil Mar 01 '21 at 15:57
1

This is the method I came up with:

    private Date addLaborDays(Integer days, Date date){
        Collection<Date> holidaysList = getHolidays();

        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DATE, 1);
        Date dateTemp = cal.getTime();

        if(days == 1) return dateTemp; 
        if(holidaysList.contains(dateTemp) || DateUtil.isWeekend(dateTemp)){
            return addLaborDays(days, dateTemp);
        } else {
            return addLaborDays(days-1, dateTemp);
        }
    }

Method getHolidays() queries a custom holidays database table, and method DateUtil.isWeekend(dateTemp) returns true if dateTemp is Saturday or Sunday.

Wendy
  • 21
  • 3
0
/* To Calculate 10 business days ahead of today's date
*/
public class DueDate {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        DueDate d = new DueDate();
        String dueDate = d.getDueDate(10);
        System.out.println("due Date " + dueDate);
    }
    public String getDueDate(int bday){
        Calendar cal = new GregorianCalendar();
        SimpleDateFormat fdate = new SimpleDateFormat("MM/dd/yyyy");
        while(bday > 0){
            cal.add(Calendar.DAY_OF_MONTH, 1);
            if(noWeekendsorHolidays(cal)){
                bday--;
            }
        }
        return fdate.format(cal.getTime());
    }

    public boolean noWeekendsorHolidays(Calendar cal){
        int day = cal.get(Calendar.DAY_OF_WEEK);
        if(day == 1 || day == 7){
            return false;
        }
        return true;
    }

}
0

This one works for me, short and simple:

public static Date getBusinessDay(final Date date, final int businessDaysFromDate) {

final int max = 60;
if (date == null) {
  return getBusinessDay(new Date(), businessDaysFromDate);
} else if (date != null && (businessDaysFromDate < 0 || businessDaysFromDate > max)) {
  return getBusinessDay(date, 0);
} else {
  final Calendar baseDateCal = Calendar.getInstance();
  baseDateCal.setTime(date);
  for (int i = 1; i <= businessDaysFromDate; i++) {
    baseDateCal.add(Calendar.DATE, 1);
    while (baseDateCal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || baseDateCal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
      baseDateCal.add(Calendar.DATE, 1);
    }
  }
  return baseDateCal.getTime();
}

}

jp093121
  • 1,752
  • 19
  • 13
0

Adding two business days to current date:

    Date today = new Date();
    Calendar cal1 = Calendar.getInstance();
    cal1.setTime(today);

    switch(cal1.get(Calendar.DAY_OF_WEEK)){

        case 1:
                cal1.add(Calendar.DATE, 2);
                break;
        case 2: 
                cal1.add(Calendar.DATE, 2);
                break;
        case 3: 
                cal1.add(Calendar.DATE, 2);
                break;
        case 4: 
                cal1.add(Calendar.DATE, 2);
                break;
        case 5: 
                cal1.add(Calendar.DATE, 4);
                break;
        case 6: 
                cal1.add(Calendar.DATE, 4);
                break;
        case 7: 
                cal1.add(Calendar.DATE, 3);
                break;

    }

    // You may also set the time to meet your purpose: 
    cal1.set(Calendar.HOUR_OF_DAY, 23);
    cal1.set(Calendar.MINUTE, 59);
    cal1.set(Calendar.SECOND, 59);
    cal1.set(Calendar.MILLISECOND, 00);

    Date twoWeekdaysAhead = cal1.getTime();
0

Most of the answer I've found online didn't work as expected, so I tweaked an example on this thread, How to get current date and add five working days in Java. The code below appears to work better.

public static Date addWorkingDays(Date date, int days) {
    if (days > 0) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);

        int daysAdded = 0;
        do {
            cal.add(Calendar.DATE, 1);
            if (isWorkingDay(cal)) {
                daysAdded++;
            }
        } while (daysAdded < days);

        return cal.getTime();;
    } else {
        return date;
    }
}


 private static boolean isWorkingDay(Calendar cal) {
    int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
    if (dayOfWeek == Calendar.SUNDAY || dayOfWeek == Calendar.SATURDAY)
        return false;
    // tests for other holidays here        
    return true;
 }
duvo
  • 1,634
  • 2
  • 18
  • 30
  • 1
    FYI… The terrible `Calendar` class was supplanted years ago by the *java.time* class with the adoption of JSR 310. Not a good suggestion in 2019. – Basil Bourque Jan 11 '19 at 03:44