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
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
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 |