How to Add Number of Business Days to Given Date

How to add number of business days to given date

The key is to generate series of business days and number them with row_number():

create or replace function add_business_day(from_date date, num_days int)
returns date
as $fbd$
select d
from (
select d::date, row_number() over (order by d)
from generate_series(from_date+ 1, from_date+ num_days* 2+ 5, '1d') d
where
extract('dow' from d) not in (0, 6)
and d not in (select pyha from pyha)
) s
where row_number = num_days
$fbd$ language sql;

The test query's results seem correct:

select days, add_business_day('2018-12-08', days)
from generate_series(1, 20) days

days | add_business_day
------+------------------
1 | 2018-12-10
2 | 2018-12-11
3 | 2018-12-12
4 | 2018-12-13
5 | 2018-12-14
6 | 2018-12-17
7 | 2018-12-18
8 | 2018-12-19
9 | 2018-12-20
10 | 2018-12-21
11 | 2018-12-27
12 | 2018-12-28
13 | 2018-12-31
14 | 2019-01-02
15 | 2019-01-03
16 | 2019-01-04
17 | 2019-01-07
18 | 2019-01-08
19 | 2019-01-09
20 | 2019-01-10
(20 rows)

Alternatively, you can find the date in a loop:

create or replace function add_business_day_loop(from_date date, num_days int)
returns date
as $fbd$
begin
while num_days > 0 loop
from_date:= from_date+ 1;
while from_date in (select pyha from pyha) or extract('dow' from from_date) in (0, 6) loop
from_date:= from_date+ 1;
end loop;
num_days:= num_days- 1;
end loop;
return from_date;
end;
$fbd$ language plpgsql;

Add business days to date in SQL without loops

This answer has been significantly altered since it was accepted, since the original was wrong. I'm more confident in the new query though, and it doesn't depend on DATEFIRST


I think this should cover it:

declare @fromDate datetime
declare @daysToAdd int

select @fromDate = '20130123',@DaysToAdd = 4

declare @Saturday int
select @Saturday = DATEPART(weekday,'20130126')

;with Numbers as (
select 0 as n union all select 1 union all select 2 union all select 3 union all select 4
), Split as (
select @DaysToAdd%5 as PartialDays,@DaysToAdd/5 as WeeksToAdd
), WeekendCheck as (
select WeeksToAdd,PartialDays,MAX(CASE WHEN DATEPART(weekday,DATEADD(day,n.n,@fromDate))=@Saturday THEN 1 ELSE 0 END) as HitWeekend
from
Split t
left join
Numbers n
on
t.PartialDays >= n.n
group by WeeksToAdd,PartialDays
)
select DATEADD(day,WeeksToAdd*7+PartialDays+CASE WHEN HitWeekend=1 THEN 2 ELSE 0 END,@fromDate)
from WeekendCheck

We split the time to be added into a number of weeks and a number of days within a week. We then use a small numbers table to work out if adding those few days will result in us hitting a Saturday. If it does, then we need to add 2 more days onto the total.

Add Working Days to a Date Using JavaScript

It is possible to use Date's setDate function (in combination with getDate) to add days onto a date i.e. -

var myDate = new Date(); // Tue 22/11/2016
myDate.setDate(myDate.getDate() + 3); // Fri 25/11/2016

So once you've calculated the number of weekend days within the workdays period you can add that and the required number of workdays to the start date to get the final date.

This function should work though obviously this will not take account of national holidays -

function addWorkDays(startDate, days) {
if(isNaN(days)) {
console.log("Value provided for \"days\" was not a number");
return
}
if(!(startDate instanceof Date)) {
console.log("Value provided for \"startDate\" was not a Date object");
return
}
// Get the day of the week as a number (0 = Sunday, 1 = Monday, .... 6 = Saturday)
var dow = startDate.getDay();
var daysToAdd = parseInt(days);
// If the current day is Sunday add one day
if (dow == 0)
daysToAdd++;
// If the start date plus the additional days falls on or after the closest Saturday calculate weekends
if (dow + daysToAdd >= 6) {
//Subtract days in current working week from work days
var remainingWorkDays = daysToAdd - (5 - dow);
//Add current working week's weekend
daysToAdd += 2;
if (remainingWorkDays > 5) {
//Add two days for each working week by calculating how many weeks are included
daysToAdd += 2 * Math.floor(remainingWorkDays / 5);
//Exclude final weekend if remainingWorkDays resolves to an exact number of weeks
if (remainingWorkDays % 5 == 0)
daysToAdd -= 2;
}
}
startDate.setDate(startDate.getDate() + daysToAdd);
return startDate;
}

//And use it like so (months are zero based)
var today = new Date(2016, 10, 22);
today = addWorkDays(today, 5); // Tue Nov 29 2016 00:00:00 GMT+0000 (GMT Standard Time)

It could also be added to the Date prototype -

Date.prototype.addWorkDays = function (days) {
if(isNaN(days)) {
console.log("Value provided for \"days\" was not a number");
return
}

// Get the day of the week as a number (0 = Sunday, 1 = Monday, .... 6 = Saturday)
var dow = this.getDay();
var daysToAdd = parseInt(days);
// If the current day is Sunday add one day
if (dow == 0) {
daysToAdd++;
}
// If the start date plus the additional days falls on or after the closest Saturday calculate weekends
if (dow + daysToAdd >= 6) {
//Subtract days in current working week from work days
var remainingWorkDays = daysToAdd - (5 - dow);
//Add current working week's weekend
daysToAdd += 2;
if (remainingWorkDays > 5) {
//Add two days for each working week by calculating how many weeks are included
daysToAdd += 2 * Math.floor(remainingWorkDays / 5);
//Exclude final weekend if the remainingWorkDays resolves to an exact number of weeks
if (remainingWorkDays % 5 == 0)
daysToAdd -= 2;
}
}
this.setDate(this.getDate() + daysToAdd);
};

//And use it like so (months are zero based)
var today = new Date(2016, 10, 22)
today.addWorkDays(5); // Tue Nov 29 2016 00:00:00 GMT+0000 (GMT Standard Time)

Python - Add OR Subtract N *Business* Days from Date Input

Seems like a small tweak to your routine would do the trick:

from datetime import datetime, timedelta

def bizday_calc_func(self, start_date, num_days):
my_start_date = start_date
my_num_days = abs(num_days)
inc = 1 if num_days > 0 else -1
while my_num_days > 0:
my_start_date += timedelta(days=inc)
weekday = my_start_date.weekday()
if weekday >= 5:
continue
my_num_days -= 1
return my_start_date

disclaimer: untested.

Add two business days to a date array excluding holiday dates

You could do something as simple as use a while loop.

$date = '2017-07-25';
$reserved = ['2017-07-27', '2017-07-28'];
$days = 2;

while ($days > 0) {
$date = date('Y-m-d', strtotime($date . ' +1 weekday'));
if (! in_array($date, $reserved)) $days--;
}

var_dump($date);

Add n business days to a given date ignoring holidays and weekends in python

Skipping weekends would be pretty easy doing something like this:

import datetime
def date_by_adding_business_days(from_date, add_days):
business_days_to_add = add_days
current_date = from_date
while business_days_to_add > 0:
current_date += datetime.timedelta(days=1)
weekday = current_date.weekday()
if weekday >= 5: # sunday = 6
continue
business_days_to_add -= 1
return current_date

#demo:
print '10 business days from today:'
print date_by_adding_business_days(datetime.date.today(), 10)

The problem with holidays is that they vary a lot by country or even by region, religion, etc. You would need a list/set of holidays for your use case and then skip them in a similar way. A starting point may be the calendar feed that Apple publishes for iCal (in the ics format), the one for the US would be http://files.apple.com/calendars/US32Holidays.ics

You could use the icalendar module to parse this.

How to add business days to date in python?

This works well enough. Not the quickest or cleanest solution, but easy to understand, and doesn't use any external libraries:

#date_calculator.py
import datetime as dt

def add_working_days(start_date, added_days):
# data from https://www.redcort.com/us-federal-bank-holidays/
federal_holidays = [dt.date(2018, 1, 1), dt.date(2018, 1, 15),
dt.date(2018, 2, 19), dt.date(2018, 5, 28), dt.date(2018, 7, 4),
dt.date(2018, 9, 3), dt.date(2018, 10, 8), dt.date(2018, 11, 12),
dt.date(2018, 11, 22), dt.date(2018, 12, 25)]

days_elapsed = 0
while days_elapsed < added_days:
test_date = start_date+dt.timedelta(days=1)
start_date = test_date
if test_date.weekday()>4 or test_date in federal_holidays:
# if a weekend or federal holiday, skip
continue
else:
# if a workday, count as a day
days_elapsed += 1

return start_date

print(add_working_days(dt.date(2018, 1, 11), 10))
#> 2018-01-26
print(add_working_days(dt.date(2018, 1, 11), 115))
#> 2018-06-26

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

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



Related Topics



Leave a reply



Submit