Here is a scheme I tried when first trying to use Boost date-time that would
approximate the initial request. It is hardly elegant code but it worked for
me at the time. I haven't needed it in quite awhile.
typedef vector<date> Holidays;
typedef vector<int> WeekendDays;
//-------------------------------------------------------------------------------------
// Calculate number of business days between two dates
//
// Input dates are yyyymmdd strings - sd1 <= sd2
// Holidays is a vector of dates for "holidays"
// WeekenDays is a vector of days of the week considered "weekend" days
//
// Holidays are excluded only if not on a "weekend" day
//-------------------------------------------------------------------------------------
long BusinessDays(const string &sd1,const string &sd2,Holidays
&holidays,WeekendDays c)
{
long f, adj, days, startday;
date d1(from_undelimited_string(sd1));
date d2(from_undelimited_string(sd2));
date_duration dd = d2 - d1;
days = dd.days();
// Adjust for "weekends" as needed
f = (long)c.size();
adj = 0;
if (f) {
// Compute adjustment for initial week
date td = d1;
date te = d1 + date_duration(7);
if (te > d2) te = d2;
date_duration one_day(1);
for (;td < te;td += one_day) {
startday = td.day_of_week();
if (find(c.begin(),c.end(),startday) != c.end()) {
adj++;
}
}
}
days -= ((days / 7) * f + adj);
// Adjust for "other" days like holidays from "calendar"
date_period dp(d1,d2);
Holidays::iterator hli;
for (hli = holidays.begin();hli != holidays.end();hli++) {
if (dp.contains(*hli)) {
startday = (*hli).day_of_week();
if (find(c.begin(),c.end(),startday) == c.end()) {
days--;
}
}
}
return days;
}
Larry
----- Original Message -----
From: "Jeff Garland"
kingos@optusnet.com.au wrote:
Hi,
I am hoping to use boost::date_time to do some date calculations. What I want to do is basically work out the number of days to a given date with various exclusions applied.
eg.
How many working days are there to christmas?
using namespace boost::gregorian;
int CalculateDaysToChristmas() { date_period someHoliday(date(2006, Dec, 01), date_duration(1));
date today(2006, Sep, 1);
date christmas(2006, Dec, 25);
int days = 0; for (day_iterator i = today; i != christmas; ++i) { if (is_weekday(*i) && !someHoliday.contains(*i)) ++days; }
return days; }
However, I can't find a simply way to work out is_weekday ...
Here's something I have laying around that does this:
using namespace boost::gregorian; inline bool is_weekday(date d) { greg_weekday dow = d.day_of_week(); if (dow == Saturday || dow == Sunday) { return false; } return true; }
inline int weekdays_in_period(const date_period& dp) { day_iterator i(dp.begin()); int count = 0; while ( i <= dp.end()) { if (is_weekday(*i)) { count++; } ++i; } return count; }
When I'm writing this sort of code I also like to hide the details of getting the date period. Something like this:
class holiday_period : public date_period { public: holiday_period(const date& holiday_date) : date_period(day_clock::local_day(), holiday_date) {}; private: };
Now you can write:
date christmas(2006, Dec, 25); hoiday_period hp(christmas); days days_until = weekdays_in_period(hp);
Secondly, is there some way to put every sunday in as a date_period?
Not sure what you have in mind here?
Thirdly, this doesn't seem very optimal ... is there a better way of doing this?
No doubt, this is suboptimal. A better way to do this is to figure out is to take advantage of the fact that a week is exactly 7 days and each week contains 5 non-weekend days (note that the weekend days aren't Sat/Sun in all parts of the world). The tricky part is that you have to account for the boundary conditions of landing on a weekend, or starting on a weekend, less than one week, etc. My guess is it would take an hour or two to really write it up and test all the cases. Anyway, I've not had a real reason to ever write this one up. Contributions always welcome ;-)
Jeff _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users