How to calculate a date from a different date with a given number of business days
I need to calculate a date (year, month, day) that is (for example) 18 business days ago from a different date. That would be enough to rule out just the weekend.
Example: I have the date 2009-08-21 and the number of 18 business days as a parameter, and the correct answer should be 2009-07-27.
thanks for any help
I assume you are using datetime, but this should work (date is date, days is integer):
def goback(date, days):
delta = datetime.timedelta( days=days + 2*(days//5) )
if date.weekday() == 5:
delta += datetime.timedelta(days=1)
elif date.weekday() == 6:
delta += datetime.timedelta(days=2)
else:
leftover = date.weekday() - days % 5
if leftover < 0:
delta += datetime.timedelta(days=2)
return date - delta
Please note that the example in your description is not correct, I think. 18 business days to 21st - 28th.
source to share
I suggest taking a look at http://docs.python.org/library/calendar.html with it you can easily figure out what day of the week a certain date is and then you can calculate back - given the weekend
source to share
Here's one way to do it. Note (1) you are not saying what you expect if the start date is not a business day. (2) Your example is wrong.
C:\junk\so>type workdays.py
import datetime
def add_workdays(adate, nworkdays):
if nworkdays < 0:
incr = -1
nworkdays = - nworkdays
else:
incr = 1
delta_weeks, delta_days = divmod(nworkdays, 5)
one_day = datetime.timedelta(days=incr)
if delta_weeks:
wdate = adate + one_day * 7 * delta_weeks
else:
wdate = adate
while delta_days:
wdate += one_day
if wdate.weekday() < 5: # Mon-Fri
delta_days -= 1
return wdate
if __name__ == "__main__":
start = datetime.date(2009, 8, 21)
for i in range(10, -19, -1):
end = add_workdays(start, i)
print "%3d %s" % (i, end.strftime("%a %Y-%m-%d"))
C:\junk\so>\python26\python workdays.py
10 Fri 2009-09-04
9 Thu 2009-09-03
8 Wed 2009-09-02
7 Tue 2009-09-01
6 Mon 2009-08-31
5 Fri 2009-08-28
4 Thu 2009-08-27
3 Wed 2009-08-26
2 Tue 2009-08-25
1 Mon 2009-08-24
0 Fri 2009-08-21
-1 Thu 2009-08-20
-2 Wed 2009-08-19
-3 Tue 2009-08-18
-4 Mon 2009-08-17
-5 Fri 2009-08-14
-6 Thu 2009-08-13
-7 Wed 2009-08-12
-8 Tue 2009-08-11
-9 Mon 2009-08-10
-10 Fri 2009-08-07
-11 Thu 2009-08-06
-12 Wed 2009-08-05
-13 Tue 2009-08-04
-14 Mon 2009-08-03
-15 Fri 2009-07-31
-16 Thu 2009-07-30
-17 Wed 2009-07-29
-18 Tue 2009-07-28
C:\junk\so>
source to share
I recommend using scikits time series with "business" frequency. You can download this great python package here:
http://pytseries.sourceforge.net/
Then you can write something like
import datetime import scikits.timeseries as TS workDay1 = TS.Date(freq='B', datetime=datetime.datetime(2009,8,21)) workDay2 = workDay1 - 7 asDatetime = workDay2.datetime
source to share
If you need to count holidays as non-working days at some point, you will need to work out Easter / Good Friday, which is best left to the library call:
>>> from dateutil import easter
>>> easter.easter(2009)
datetime.date(2009, 4, 12)
Other major holidays are relatively simple: they either meet the same date every year, or fall on a consecutive day of the week every other month. You can check out period.py ( http://www.medsch.wisc.edu/~annis/creations/period.py.html ), which offers the is_holiday () method, although it does require customization.
The NYSE Stock Market Holidays provide a reasonable default vacation schedule for the United States.
My wife Anna has a recipe for this in the second edition. from the Python Cookbook - you can read it on the web with this google book url search , it starts with p. 122. Recipe 3.5 is weekdays versus weekends; the very next recipe, 3.6, adds attention to the holidays, but unfortunately it can only be partially read on the internet when searching for books on google (I've seen a lot of pirated copies of our book advertised as free downloads but don't have friendly URLs) ...
These recipes are especially close and dear to our hearts because they mostly relate to how we reconnected (on the Internet) through the years we lost each other. Anna was looking for help improving them as they needed their functionality in the workplace, I suggested ... 20 months later we were married; -).
source to share