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 fieldstaskRow.PROJ_UID = projGuid;taskRow.TASK_UID = taskGuid;taskRow.TASK_NAME = "Example Task 3"
// Set the start and finish datestaskRow.TASK_START_DATE = new DateTime(2007, 01, 20);taskRow.TASK_FINISH_DATE = new DateTime(2007, 01, 20);taskRow.AddPosition = (int)PSLibrary.Task.AddPositionType.Last;
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 fieldstaskRow.PROJ_UID = projGuid;taskRow.TASK_UID = task2Guid;taskRow.TASK_NAME = "Example Task 4"
// Set the start and finish datestaskRow.TASK_START_DATE = new DateTime(2007, 01, 31);taskRow.TASK_FINISH_DATE = new DateTime(2007, 01, 31);
taskRow.AddPosition = (int)PSLibrary.Task.AddPositionType.Last;
// 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();
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 constraintdsP = new WSProject.ProjectDataSet();
WSProject.ProjectDataSet.TaskRow taskRow = dsP.Task.NewTaskRow();// Set the requied fieldstaskRow.PROJ_UID = projGuid;taskRow.TASK_UID = taskGuid;taskRow.TASK_NAME = "Example Task"
// Set the start and finish datestaskRow.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;
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:
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[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[dsP.Task.TASK_CONSTRAINT_TYPEColumn] = (short)Library.Task.ConstraintType.MustStartOn; dsP.Tables[dsP.Task.TableName].Rows[dsP.Task.TASK_CONSTRAINT_DATEColumn] = new DateTime(2007, 01, 15);
projWS.QueueUpdateProject(Guid.NewGuid(), sessGuid, dsP, false);
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.
Love the blog.
I am putting together a reblog using Wordpress to
aggregate Project and Project Server themed blogs, to get the latest
news and to provide a searchable resource for tips, etc. Added to this
will be newsgroup postings from Microsoft.public.projectserver also, and
perhaps some kb articles to provide what I hope will be a very useful
resource for Project Server professionals. (Also hopes it sends more
traffic your way) If you think this is something your users will like, a
post in your news, or a link, would be most welcome.
Chris and all,
Is there a location where I can download the source code?
I am new to PSI and complete code will be very helpful. For example
projWS.QueueAddToProject(jobGuid, sessGuid, dsP, false);
in the above line, I anm not sure whant sessGuid is, if I have the entire code sample.
I have a question which might be a bit out of context of this blog. I have a task which is assigned to 2 resources (say both are working for 8 hrs each on a 16hrs task). Now I want to increase the total work of one of the two resources from 8 hrs to 16 hrs programatically and keep the other resource's work to be still at 8 hrs only. How can I do that using PSI. Can you please help me out here or point me to some forum where I can post this problem.