/* Compile with: gcc workdays.c -lm -o workdays */ /* Calculate nr of day since year 0 in new date-system (from 1615) */ long calc_daynr(int year,int month,int day) { long delsum; int temp; //DBUG_ENTER("calc_daynr"); if (year == 0 && month == 0 && day == 0) return (0); /* Skip errors */ delsum= (long) (365L * year+ 31*(month-1) +day); if (month <= 2) year--; else delsum-= (long) (month*4+23)/10; temp=(int) ((year/100+1)*3)/4; return (delsum+(int) year/4-temp); } /* calc_daynr */ /* Calc weekday from daynr */ /* Returns 0 for monday, 1 for tuesday .... */ int calc_weekday(long daynr,int sunday_first_day_of_week) { //DBUG_ENTER("calc_weekday"); return ((int) ((daynr + 5L + (sunday_first_day_of_week ? 1L : 0L)) % 7)); } /* Calc workdays like excel */ /* nr of weekends = nr of days / 7 nr of workdays = nr of days - nr of weekends The remainder of the division of nr of days / 7 could completely or partly comprise a weekend. Example: MTWTFSSMTWTFSSMTWTFSSMTWTFSSMTWTFSSMTWTFSSMTWTFSSMTWTFSSMTWTFSSMTWTFSS 0123456012345601234560123456012345601234560123456012345601234560123456 01234560123456012345 (2 weeks + 6 days) 01234560123456 (2 weeks = 14 days ) 012345 (the remainder of 6 days begins on the same day as the start date) The first line in the table below shows that for a remainder of 6 days, when the start date is a Monday there will be one extra weekendday. Nr of Extra Calculation remaining Startday weekend (Nr of remaining days - (5 - Startday)) days days 6 days day 0 1 6-(5-0) = 1 1 6 days day 1 2 6-(5-1) = 2 6 days day 2 2 6-(5-2) = 3 6 days day 3 2 6-(5-3) = 4 6 days day 4 2 6-(5-4) = 5 6 days day 5 2 6-(5-5) = 6 6 days day 6 1 6-(5-6) = 7 1 5 days day 0 0 5-(5-0) = 0 5 days day 1 1 5-(5-1) = 1 1 5 days day 2 2 5-(5-2) = 2 5 days day 3 2 5-(5-3) = 3 5 days day 4 2 5-(5-4) = 4 5 days day 5 2 5-(5-5) = 5 5 days day 6 1 5-(5-6) = 6 1 4 days day 0 0 4-(5-0) = -1 4 days day 1 0 4-(5-1) = 0 4 days day 2 1 4-(5-2) = 1 1 4 days day 3 2 4-(5-3) = 2 4 days day 4 2 4-(5-4) = 3 4 days day 5 2 4-(5-5) = 4 4 days day 6 1 4-(5-6) = 5 1 3 days day 0 0 3 days day 1 0 3 days day 2 0 3 days day 3 1 3 days day 4 2 3 days day 5 2 3 days day 6 1 2 days day 0 0 2 days day 1 0 2 days day 2 0 2 days day 3 0 2 days day 4 1 2 days day 5 2 2 days day 6 1 1 days day 0 0 1 days day 1 0 1 days day 2 0 1 days day 3 0 1 days day 4 0 1 days day 5 1 1 days day 6 1 If startday = 6 (Sunday) add 1 extra weekendday If (Nr of remaining days - (5 - day of week of start day)) < 1 => 0 weekenddays = 1 => 1 weekendday >1 => 2 weekenddays (a saturday and a sunday) */ int calc_workdays(int y1, int m1, int d1, int y2, int m2, int d2) { int days1 = calc_daynr(y1, m1, d1); int days2 = calc_daynr(y2, m2, d2); int nrofdays = days2 - days1; if (nrofdays==0) return 1; // e.g. monday - monday = 1 day int neg_nrofdays = (nrofdays < 0); int dayofweek = calc_weekday((neg_nrofdays ? days2 : days1), 0); //printf("day of week: %d\n", dayofweek); nrofdays = abs(nrofdays)+1; // e.g. diff mon-tue = 1, but takes 2 days int nrofweekends = floor(nrofdays / 7); int mod = nrofdays % 7; int add = 0; // Correction when the remainder (part of a week) // fully or partly comprises a weekend. if (mod) { if ((dayofweek)==6) add=1; else { add = mod - (5 - dayofweek); if (add<0) add = 0; if (add>1) add = 2; } } //printf("add: %d\n", add); //printf("nrofdays: %d\n", nrofdays); int workdays = nrofdays - ((nrofweekends*2) + add); return (neg_nrofdays ? -workdays : workdays); } int main (void) { // Print nr of workdays between May 1th, 2007 and Apr 16th, 2007 //printf("Nr of workdays: %d\n", calc_workdays(2007, 5, 1, 2007, 4, 16)); // Print nr of workdays between May 7th, 2007 and May 20th, 2007 printf("Nr of workdays: %d\n", calc_workdays(2007, 5, 7, 2007, 5, 20)); }