Task Start and Finish Dates

When working with the task start and finish dates via the Project PSI, you might find some strange behaviors. It is not that it is strange, it is that these two fields are used by the scheduling engine to calculate your project's schedule. Hopefully this post will give you some insight to how to work with these two fields and why they may not be set to values that you expect.  

When you first create a task, you can set the start date and finish date for the task. The below sample code shows you how to create a new task and how to set these fields:

dsP = new WSProject.ProjectDataSet();

WSProject.ProjectDataSet.TaskRow taskRow = dsP.Task.NewTaskRow();
// Set the requied fields
taskRow.PROJ_UID = projGuid;
taskRow.TASK_UID = taskGuid;
taskRow.TASK_NAME = "Example Task 3"

// Set the start and finish dates
taskRow.TASK_START_DATE = new DateTime(2007, 01, 20);
taskRow.TASK_FINISH_DATE = new DateTime(2007, 01, 20);

taskRow.AddPosition = (int)PSLibrary.Task.AddPositionType.Last;

dsP.Task.AddTaskRow(taskRow);

projWS.QueueAddToProject(jobGuid, sessGuid, dsP, false);

The above sample code sets the start and finish date for the task to be January 20th, 2007. When I publish the project and view it in Project Center Drill Down, this is what I get:

You might notice that the start date and finish date are not set to January 20th, but instead January 17th. This is because the start date of the project is set to January 17th. When the scheduling engine works out the schedule, it looks at the task I just created and determines that it has no constrains, thus it can be started right when the project begins. Thus the scheduling engine changes the start and finish date to January 17th.

Now, lets create another task that is dependent on the one we just created. This time, we will make it's start and finish date January 31st, 2007:

// Create a second task

dsP = new WSProject.ProjectDataSet();
taskRow = dsP.Task.NewTaskRow();

Guid task2Guid = Guid.NewGuid();
jobGuid = Guid.NewGuid();

// Set the requied fields
taskRow.PROJ_UID = projGuid;
taskRow.TASK_UID = task2Guid;
taskRow.TASK_NAME = "Example Task 4"

// Set the start and finish dates
taskRow.TASK_START_DATE = new DateTime(2007, 01, 31);
taskRow.TASK_FINISH_DATE = new DateTime(2007, 01, 31);

taskRow.AddPosition = (int)PSLibrary.Task.AddPositionType.Last;

dsP.Task.AddTaskRow(taskRow);

// Here we make it dependent on the task we created before

WSProject.ProjectDataSet.DependencyRow dependRow = dsP.Dependency.NewDependencyRow();

dependRow.PROJ_UID = projGuid;
dependRow.LINK_PRED_UID = taskGuid;
dependRow.LINK_SUCC_UID = task2Guid;
dependRow.LINK_UID = Guid.NewGuid();

dsP.Dependency.AddDependencyRow(dependRow);

projWS.QueueAddToProject(jobGuid, sessGuid, dsP, false);

PublishProject(projGuid);

Again you will notices that the schedule engine has moved the task forward to January 18th:

This is because the dependency we added to the new task on the one we had previously created.

Lets say that you have a task that you need to schedule, but you know it cannot start before a certain date, due to some external factors from your project. In this case, you do not want the scheduling engine to move your task forward beyond that date. In this case, we need to set the TASK_CONSTRAINT_DATE and TASK_CONSTRAINT_TYPE fields. The below sample shows how to do this:

// Create a task with a constraint
dsP = new WSProject.ProjectDataSet();

WSProject.ProjectDataSet.TaskRow taskRow = dsP.Task.NewTaskRow();
// Set the requied fields
taskRow.PROJ_UID = projGuid;
taskRow.TASK_UID = taskGuid;
taskRow.TASK_NAME = "Example Task"

// Set the start and finish dates
taskRow.TASK_START_DATE = new DateTime(2007, 01, 22);
taskRow.TASK_FINISH_DATE = new DateTime(2007, 01, 22);

taskRow.TASK_CONSTRAINT_DATE = new DateTime(2007, 01, 22);
taskRow.TASK_CONSTRAINT_TYPE = (short)Library.Task.ConstraintType.StartNoEarlierThan;
taskRow.AddPosition = (int)PSLibrary.Task.AddPositionType.Last;

dsP.Task.AddTaskRow(taskRow);

projWS.QueueAddToProject(jobGuid, sessGuid, dsP, false);

PublishProject(projGuid);

Here is what we get:

So finally we are able to create a task and have it start on a particular date, but there is a catch. You can only put one type of constraint on your task. Here are a list of constraint types that you can use:

 

Constraint Type Description
AsLateAsPossible Schedules the task as late as it can without delaying subsequent tasks. Use no constraint date.
AsSoonAsPossible Schedules the task to start as early as it can. Use no constraint date.
FinishNoEarlierThan Schedules the task to finish on or after the constraint date.
FinishNoLaterThan Schedules the task to finish on or before the constraint date.
MustFinishOn Schedules the task to finish on the constraint date. Once selected the task will not be moveable on the timescale.
MustStartOn Schedules the task to start on the constraint date. Once selected the task will not be movable on the timescale.
StartNoEarlierThan Schedules the task to start on or after the constraint date.
StartNoLaterThan Schedules the task to start on or before the constraint date.

 

Hopefully you have a somewhat of an idea about creating a task and how the start and finish date is affected by the scheduling engine. Now, lets take a look at updating a task's start and finish date. If you need to update a tasks start or finish date, you will quickly learn that you cannot simply read the project data set, find the task you want to update in the task table and update the start and finish date fields like this:

dsP.Tables[dsP.Task.TableName].Rows[1][dsP.Task.TASK_START_DATEColumn] = new DateTime(2007, 12, 03);

You will quickly run into the following runtime exception:

Column 'TASK_START_DATE' is read only.

As the exception states, this is because the start date and finish date are read only fields. These fields are read only because they are calculated fields and cannot be set when updating a project data set. 

So how can you get around this? Again, you can place constraints on the dates like we did when creating tasks. The scheduling engine will honor the constraint when calculating the schedule, but remember, there are other factors that affect the calculation. Such as the number of resource assigned to the tasks and the amount of work required to complete the task. So if you constrain your start date, it will affect your finish date. This is why you can only place one constraint on a task. The below example shows how you can update a task that must start on January 15th, 2007:

dsP = projWS.ReadProject(projGuid, ProjOutlookConnector.WSProject.DataStoreEnum.WorkingStore);

dsP.Tables[dsP.Task.TableName].Rows[1][dsP.Task.TASK_CONSTRAINT_TYPEColumn] = (short)Library.Task.ConstraintType.MustStartOn;
dsP.Tables[dsP.Task.TableName].Rows[1][dsP.Task.TASK_CONSTRAINT_DATEColumn] = new DateTime(2007, 01, 15);

projWS.QueueUpdateProject(Guid.NewGuid(), sessGuid, dsP, false);

PublishProject(projGuid);

Here is what you will see in PWA after publishing the project:

We have primarily focused on the factors that affect the start date. Just like the start date, the finish date is affected by many factors that the scheduling engine takes under consideration. For example, the finish date is affected by number of resources assigned to the task, calendar exceptions, such as weekends, specific exceptions in individual resource calendars, and the amount of work assigned required to complete the task.

These are only some basic examples. Project's schedule engine is very complex and there are a number of factors that affect the start and finish date of a task. Hopefully I have given you some insight why your start and finish dates change.

Chris Boyd

Technorati Profile