The CPM Procedure

Example 4.10 Multiple Calendars

This example illustrates the use of multiple calendars within a project. Different scenarios are presented to show the use of different calendars and how project schedules are affected. Output 4.10.1 shows the data set WORKDATA, which defines several shift patterns. These shift patterns are appropriately associated with three different calendars in the data set CALEDATA, also shown in the same output. The three calendars are defined as follows:

  • The DEFAULT calendar has five eight-hour days (Monday through Friday) and holidays on Saturday and Sunday.

  • The calendar OVT_CAL specifies an overtime calendar that has 10-hour work days on Monday through Friday and a half day on Saturday and a holiday on Sunday.

  • The calendar PROD_CAL follows a more complicated work pattern: Sunday is a holiday; on Monday work is done from 8 a.m. through midnight with a two hour break from 6 p.m. to 8 p.m.; on Tuesday through Friday work is done round the clock with two 2-hour breaks from 6 a.m. to 8 a.m. and 6 p.m. to 8 p.m.; on Saturday the work shifts are from midnight to 6 a.m. and again from 8 a.m. to 6 p.m. In other words, work is done continuously from 8 a.m. on Monday morning to 6 p.m. on Saturday with two hour breaks every day at 6 a.m. and 6 p.m.

Output 4.10.1: Workday and Calendar Data Sets

Multiple Calendars
Workdays Data Set

Obs fullday halfday ovtday s1 s2 s3
1 8:00 8:00 8:00 . 8:00 .
2 16:00 12:00 18:00 6:00 18:00 6:00
3 . . . 8:00 20:00 8:00
4 . . . 18:00 . 18:00
5 . . . 20:00 . .
6 . . . . . .



Multiple Calendars
CALENDAR Data Set

Obs cal _sun_ _mon_ _tue_ _wed_ _thu_ _fri_ _sat_
1 DEFAULT holiday fullday fullday fullday fullday fullday holiday
2 OVT_CAL holiday ovtday ovtday ovtday ovtday ovtday halfday
3 PROD_CAL holiday s2 s1 s1 s1 s1 s3


The same set of holidays is used as in Example 4.9, except that in this case the holiday for New Year’s is defined by specifying both the start and finish time for the holiday instead of defaulting to a one-day long holiday. When multiple calendars are involved, it is often less confusing to define holidays by specifying both a start and a finish time for the holiday instead of the start time and duration. Output 4.10.2 displays the Holiday data set.

Output 4.10.2: Holiday Data Set

Multiple Calendars
Holidays Data Set

Obs holiday holifin holidur
1 24DEC03 26DEC03 4
2 01JAN04 01JAN04 .


The data set HOLIDAYS does not include any variable identifying the calendars with which to associate the holidays. By default, the procedure associates the two holiday periods with all the calendars.

An easy way to visualize all the breaks and holidays for each calendar is to use a Gantt chart, plotting a bar for each calendar from the start of the project to January 4, 2004, with all the holiday and work shift specifications. The following program produces Output 4.10.3. Holidays and breaks are marked with a solid fill pattern.

goptions hpos=160 vpos=25;
title h=2 'Multiple Calendars';
title2 h=1.4 'Breaks and Holidays for the Different Calendars';
proc gantt data=cals graphics
           calendar=calendar holidata=holidays
           workday=workdata;
   chart / interval=dtday mininterval=dthour skip=2
           holiday=(holiday) holifin=(holifin)
           markbreak daylength='08:00't calid=cal
           ref='1dec03:00:00'dt to '4jan04:08:00'dt by dtday
           nolegend nojobnum increment=16
           hpages=6;
   id cal;
   run;

Output 4.10.3: Gantt Chart Showing Breaks and Holidays for Multiple Calendars

Gantt Chart Showing Breaks and Holidays for Multiple Calendars
External File:images/cpm10o31_1.png
External File:images/cpm10o31_2.png
External File:images/cpm10o31_3.png
External File:images/cpm10o31_4.png
External File:images/cpm10o31_5.png


The Activity data set used in Example 4.9 is modified by adding a variable called cal, which sets the calendar to be 'PROD_CAL' for the activity 'Production', and 'OVT_CAL' for the activity 'Prototype', and the DEFAULT calendar for the other activities. Thus, in both the Activity data set and the Calendar data set, the calendar information is conveyed through a CALID variable, cal.

PROC CPM is first invoked without reference to the CALID variable. Thus, the procedure recognizes only the first observation in the Calendar data set (a warning is printed to the log to this effect), and only the default calendar is used for all activities in the project. The daylength parameter is interpreted as the length of a standard work day; all the durations are assumed to be in units of this standard work day. Output 4.10.4 displays the schedule obtained. The project is scheduled to finish on March 12, 2004, at 12 noon.


data widgcal;
   set widget9;
   if task = 'Production' then       cal = 'PROD_CAL';
   else if task = 'Prototype' then   cal = 'OVT_CAL';
   else                              cal = 'DEFAULT';
   run;

proc cpm date='01dec03'd data=widgcal out=scheddef
         holidata=holidays daylength='08:00't
         workday=workdata
         calendar=calendar;
   holiday holiday / holifin = holifin;
   activity task;
   duration days;
   successor succ1 succ2 succ3;
   run;

title2 'Project Schedule: Default calendar';
proc print heading=h;
   var task days e_start e_finish l_start l_finish
       t_float f_float;
   run;

Output 4.10.4: Schedule Using Default Calendar

Multiple Calendars
Project Schedule: Default calendar

Obs task days E_START E_FINISH L_START L_FINISH T_FLOAT F_FLOAT
1 Approve Plan 5.5 01DEC03:08:00:00 08DEC03:11:59:59 01DEC03:08:00:00 08DEC03:11:59:59 0.0 0.0
2 Drawings 10.0 08DEC03:12:00:00 22DEC03:11:59:59 08DEC03:12:00:00 22DEC03:11:59:59 0.0 0.0
3 Study Market 5.0 08DEC03:12:00:00 15DEC03:11:59:59 23JAN04:12:00:00 30JAN04:11:59:59 30.0 0.0
4 Write Specs 4.5 08DEC03:12:00:00 12DEC03:15:59:59 16DEC03:08:00:00 22DEC03:11:59:59 5.5 5.5
5 Prototype 15.0 22DEC03:12:00:00 16JAN04:11:59:59 22DEC03:12:00:00 16JAN04:11:59:59 0.0 0.0
6 Mkt. Strat. 10.0 15DEC03:12:00:00 02JAN04:11:59:59 30JAN04:12:00:00 13FEB04:11:59:59 30.0 30.0
7 Materials 10.0 16JAN04:12:00:00 30JAN04:11:59:59 16JAN04:12:00:00 30JAN04:11:59:59 0.0 0.0
8 Facility 10.0 16JAN04:12:00:00 30JAN04:11:59:59 16JAN04:12:00:00 30JAN04:11:59:59 0.0 0.0
9 Init. Prod. 10.0 30JAN04:12:00:00 13FEB04:11:59:59 30JAN04:12:00:00 13FEB04:11:59:59 0.0 0.0
10 Evaluate 10.0 13FEB04:12:00:00 27FEB04:11:59:59 20FEB04:12:00:00 05MAR04:11:59:59 5.0 5.0
11 Test Market 15.0 13FEB04:12:00:00 05MAR04:11:59:59 13FEB04:12:00:00 05MAR04:11:59:59 0.0 0.0
12 Changes 5.0 05MAR04:12:00:00 12MAR04:11:59:59 05MAR04:12:00:00 12MAR04:11:59:59 0.0 0.0
13 Production 0.0 12MAR04:12:00:00 12MAR04:12:00:00 12MAR04:12:00:00 12MAR04:12:00:00 0.0 0.0
14 Marketing 0.0 13FEB04:12:00:00 13FEB04:12:00:00 12MAR04:12:00:00 12MAR04:12:00:00 20.0 20.0


Next PROC CPM is invoked with the CALID statement identifying the variable CAL in the Activity and Calendar data sets. Recall that the two activities, 'Production' and 'Prototype', do not follow the default calendar. The schedule displayed in Output 4.10.5 shows that, due to longer working hours for these two activities in the project, the scheduled finish date is now March 8, at 10:00 a.m.


proc cpm date='01dec03'd data=widgcal out=schedmc
         holidata=holidays daylength='08:00't
         workday=workdata
         calendar=calendar;
   holiday holiday / holifin = holifin;
   activity task;
   duration days;
   successor succ1 succ2 succ3;
   calid cal;
   run;
title2 'Project Schedule: Three Calendars';
proc print;
   var task days cal e_: l_: t_float f_float;
   run;

Output 4.10.5: Schedule Using Three Calendars

Multiple Calendars
Project Schedule: Three Calendars

Obs task days cal E_START E_FINISH L_START L_FINISH T_FLOAT F_FLOAT
1 Approve Plan 5.5 DEFAULT 01DEC03:08:00:00 08DEC03:11:59:59 01DEC03:08:00:00 08DEC03:11:59:59 0.00 0.00
2 Drawings 10.0 DEFAULT 08DEC03:12:00:00 22DEC03:11:59:59 08DEC03:12:00:00 22DEC03:11:59:59 0.00 0.00
3 Study Market 5.0 DEFAULT 08DEC03:12:00:00 15DEC03:11:59:59 19JAN04:10:00:00 26JAN04:09:59:59 25.75 0.00
4 Write Specs 4.5 DEFAULT 08DEC03:12:00:00 12DEC03:15:59:59 16DEC03:08:00:00 22DEC03:11:59:59 5.50 5.50
5 Prototype 15.0 OVT_CAL 22DEC03:12:00:00 12JAN04:09:59:59 22DEC03:12:00:00 12JAN04:09:59:59 0.00 0.00
6 Mkt. Strat. 10.0 DEFAULT 15DEC03:12:00:00 02JAN04:11:59:59 26JAN04:10:00:00 09FEB04:09:59:59 25.75 25.75
7 Materials 10.0 DEFAULT 12JAN04:10:00:00 26JAN04:09:59:59 12JAN04:10:00:00 26JAN04:09:59:59 0.00 0.00
8 Facility 10.0 DEFAULT 12JAN04:10:00:00 26JAN04:09:59:59 12JAN04:10:00:00 26JAN04:09:59:59 0.00 0.00
9 Init. Prod. 10.0 DEFAULT 26JAN04:10:00:00 09FEB04:09:59:59 26JAN04:10:00:00 09FEB04:09:59:59 0.00 0.00
10 Evaluate 10.0 DEFAULT 09FEB04:10:00:00 23FEB04:09:59:59 16FEB04:10:00:00 01MAR04:09:59:59 5.00 5.00
11 Test Market 15.0 DEFAULT 09FEB04:10:00:00 01MAR04:09:59:59 09FEB04:10:00:00 01MAR04:09:59:59 0.00 0.00
12 Changes 5.0 DEFAULT 01MAR04:10:00:00 08MAR04:09:59:59 01MAR04:10:00:00 08MAR04:09:59:59 0.00 0.00
13 Production 0.0 PROD_CAL 08MAR04:10:00:00 08MAR04:10:00:00 08MAR04:10:00:00 08MAR04:10:00:00 0.00 0.00
14 Marketing 0.0 DEFAULT 09FEB04:10:00:00 09FEB04:10:00:00 08MAR04:10:00:00 08MAR04:10:00:00 20.00 20.00


Now suppose that the engineer in charge of writing specifications requests a seven-day vacation from December 8, 2003. How is the project completion time going to be affected? A new calendar, Eng_cal, is defined that has the same work pattern as the default calendar, but it also contains an extra vacation period. Output 4.10.6 displays the data sets HOLIDATA and CALEDATA, which contain information about the new calendar. The fourth observation in the data set CALEDATA has missing values for the variables _sun_, …, _sat_, indicating that the calendar, Eng_cal, follows the same work pattern as the default calendar.

Output 4.10.6: HOLIDATA and CALEDATA Data Sets

Multiple Calendars
Holidays Data Set

Obs holiday holifin holidur cal
1 08DEC03 . 7 Eng_cal
2 24DEC03 26DEC03 .  
3 01JAN04 01JAN04 .  



Multiple Calendars
Calendar Data Set

Obs cal _sun_ _mon_ _tue_ _wed_ _thu_ _fri_ _sat_
1 DEFAULT holiday fullday fullday fullday fullday fullday holiday
2 OVT_CAL holiday ovtday ovtday ovtday ovtday ovtday halfday
3 PROD_CAL holiday s2 s1 s1 s1 s1 s3
4 Eng_cal              


Once again, in the following code, PROC GANTT is used to compare the new calendar with the default calendar, as shown in Output 4.10.7. Note that the breaks and holidays are marked with a solid fill pattern.

/* Create a data set to illustrate holidays with PROC GANTT */
data cals2;
   e_start='1dec03:00:00'dt;
   e_finish='18dec03:00:00'dt;
   label cal ='Schedule Breaks / Holidays';
   format e_start e_finish datetime16.;
   length cal $8.;
   cal='DEFAULT' ; output;
   cal='Eng_cal' ; output;
   run;

title2 'Breaks and Holidays for Eng_cal and the DEFAULT Calendar';
proc gantt data=cals2 graphics
           calendar=caledata holidata=holidata
           workday=workdata;
   chart / interval=dtday mininterval=dthour skip=2
           holiday=(holiday) holifin=(holifin) holidur=(holidur)
           markbreak daylength='08:00't calid=cal
           ref='1dec03:00:00'dt to '18dec03:00:00'dt by dtday
           nojobnum nolegend increment=16 hpages=3;
   id cal;
   run;

Output 4.10.7: Difference between Eng_cal and DEFAULT Calendar

Difference between Engcal and DEFAULT Calendar
External File:images/cpm10o71_1.png
External File:images/cpm10o71_2.png


The Activity data set is modified to redefine the calendar for the task 'Write Specs'. PROC CPM is invoked, and Output 4.10.8 shows the new schedule obtained. Note the effect of the Engineer’s vacation on the project completion time. The project is now scheduled to finish at 10 a.m. on March 9, 2004; in effect, the delay is only one day, even though the planned vacation period is seven days. This is due to the fact that the activity 'Write Specs', which follows the new calendar, had some slack time present in its original schedule; however, this activity has now become critical.

data widgvac;
   set widgcal;
   if task = 'Write Specs' then cal = 'Eng_cal';
   run;

proc cpm date='01dec03'd data=widgvac out=schedvac
         holidata=holidata daylength='08:00't
         workday=workdata
         calendar=caledata;
   holiday holiday / holifin = holifin holidur=holidur;
   activity task;
   duration days;
   successor succ1 succ2 succ3;
   calid cal;
   run;

title2 'Project Schedule: Four Calendars';
proc print;
   var task days cal e_: l_: t_float f_float;
   run;

Output 4.10.8: Schedule Using Four Calendars

Multiple Calendars
Project Schedule: Four Calendars

Obs task days cal E_START E_FINISH L_START L_FINISH T_FLOAT F_FLOAT
1 Approve Plan 5.5 DEFAULT 01DEC03:08:00:00 08DEC03:11:59:59 02DEC03:08:00:00 09DEC03:11:59:59 1.00 0.00
2 Drawings 10.0 DEFAULT 08DEC03:12:00:00 22DEC03:11:59:59 09DEC03:12:00:00 23DEC03:11:59:59 1.00 1.00
3 Study Market 5.0 DEFAULT 08DEC03:12:00:00 15DEC03:11:59:59 20JAN04:10:00:00 27JAN04:09:59:59 26.75 0.00
4 Write Specs 4.5 Eng_cal 17DEC03:08:00:00 23DEC03:11:59:59 17DEC03:08:00:00 23DEC03:11:59:59 0.00 0.00
5 Prototype 15.0 OVT_CAL 23DEC03:12:00:00 13JAN04:09:59:59 23DEC03:12:00:00 13JAN04:09:59:59 0.00 0.00
6 Mkt. Strat. 10.0 DEFAULT 15DEC03:12:00:00 02JAN04:11:59:59 27JAN04:10:00:00 10FEB04:09:59:59 26.75 26.75
7 Materials 10.0 DEFAULT 13JAN04:10:00:00 27JAN04:09:59:59 13JAN04:10:00:00 27JAN04:09:59:59 0.00 0.00
8 Facility 10.0 DEFAULT 13JAN04:10:00:00 27JAN04:09:59:59 13JAN04:10:00:00 27JAN04:09:59:59 0.00 0.00
9 Init. Prod. 10.0 DEFAULT 27JAN04:10:00:00 10FEB04:09:59:59 27JAN04:10:00:00 10FEB04:09:59:59 0.00 0.00
10 Evaluate 10.0 DEFAULT 10FEB04:10:00:00 24FEB04:09:59:59 17FEB04:10:00:00 02MAR04:09:59:59 5.00 5.00
11 Test Market 15.0 DEFAULT 10FEB04:10:00:00 02MAR04:09:59:59 10FEB04:10:00:00 02MAR04:09:59:59 0.00 0.00
12 Changes 5.0 DEFAULT 02MAR04:10:00:00 09MAR04:09:59:59 02MAR04:10:00:00 09MAR04:09:59:59 0.00 0.00
13 Production 0.0 PROD_CAL 09MAR04:10:00:00 09MAR04:10:00:00 09MAR04:10:00:00 09MAR04:10:00:00 0.00 0.00
14 Marketing 0.0 DEFAULT 10FEB04:10:00:00 10FEB04:10:00:00 09MAR04:10:00:00 09MAR04:10:00:00 20.00 20.00