Task Start and Finish Dates

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

Microsoft Office Project 2007 uses a complex scheduling engine to manage projects throughout the project lifecycle. The Project 2007 scheduling engine automatically calculates values for some fields, rather than allowing you to manually specify their values. Developers working with the Project Server Interface (PSI) can be confused by this behavior. This article clarifies some best practices for working with task start and finish dates in the Project 2007 scheduling engine. (This article is based on content contributed by Chris Boyd, Microsoft Corporation.).

The TASK_START_DATE and TASK_FINISH_DATE properties are calculated fields. The following code example attempts to read the ProjectDataSet object, find the task to update in the task table, and update the task start date field.

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

In Project 2007, attempting to execute this code throws the following run-time exception.

Column 'TASK_START_DATE' is read only.

As the exception states, the start date and finish date are read-only fields. The Project 2007 scheduling engine calculates the values for these fields automatically; you cannot set them by updating a project data set manually.

Many factors can influence the start and finish date of a task. The following sections describe some of these factors and provide examples of how to programmatically manipulate those values that the Project 2007 scheduling engine uses to calculate task start and finish dates.

  • Setting the Start and Finish Dates for a New Task

  • Working with Task Dependencies

  • Working with Task Constraints

  • Understanding Task Types, Effort-driven Scheduling, and Resource Assignments

  • Understanding Calendar Exceptions

  • Identifying Task Drivers

Setting the Start and Finish Dates for a New Task

When you first create a task, you can enter specific values for the task start date and finish date. However, Project 2007 might reschedule the task based on other information that is stored in the project.

The following code example creates a project with a task named Task One, sets the start date and finish date for Task One, and then publishes the project.

For critical information about running this code example, see Prerequisites for Reference Code Samples.

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Web.Services.Protocols;
using System.Threading;
using PSLibrary = Microsoft.Office.Project.Server.Library;

namespace Microsoft.SDK.Project.Samples.TaskDates
{
    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            try
            {
                const string PROJECT_SERVER_URI = "http://ServerName/ProjectServerName/"; // Change to match your project server and directory.
                const string PROJECT_SERVICE_PATH = "_vti_bin/psi/project.asmx";
                const string QUEUESYSTEM_SERVICE_PATH = "_vti_bin/psi/queuesystem.asmx";

                Guid jobId;

                // Set up the Web service objects.
                ProjectWebSvc.Project projectSvc = new ProjectWebSvc.Project();

                ProjectWebSvc.ProjectDataSet projectDs = new ProjectWebSvc.ProjectDataSet();

                projectSvc.Url = PROJECT_SERVER_URI + PROJECT_SERVICE_PATH;
                projectSvc.Credentials = CredentialCache.DefaultCredentials;

                QueueSystemWebSvc.QueueSystem q = new QueueSystemWebSvc.QueueSystem();
                q.Url = PROJECT_SERVER_URI + QUEUESYSTEM_SERVICE_PATH;
                q.UseDefaultCredentials = true;

                // Create a sample project.
                Console.WriteLine("Creating project data");
                projectDs = new ProjectWebSvc.ProjectDataSet();

                // Create the project.
                ProjectWebSvc.ProjectDataSet.ProjectRow projectRow = projectDs.Project.NewProjectRow();
                projectRow.PROJ_UID = Guid.NewGuid();
                projectRow.PROJ_NAME = "Its a wonderful project at " + DateTime.Now.ToShortDateString().Replace("/", "") + " " + DateTime.Now.ToShortTimeString().Replace(":", "");
                projectRow.PROJ_INFO_START_DATE = new DateTime(2007, 05, 07);
                projectRow.PROJ_TYPE = (int)PSLibrary.Project.ProjectType.Project;
                projectDs.Project.AddProjectRow(projectRow);

                // Create Task One.
                ProjectWebSvc.ProjectDataSet.TaskRow taskOne = projectDs.Task.NewTaskRow();
                taskOne.PROJ_UID = projectRow.PROJ_UID;
                taskOne.TASK_UID = Guid.NewGuid();
                taskOne.TASK_DUR_FMT = (int)PSLibrary.Task.DurationFormat.Day; // Task Duration format must be specified
                taskOne.TASK_DUR = 4800; // 8 hours in Project duration time units (minute/10)
                taskOne.TASK_NAME = "Task One";
                taskOne.TASK_START_DATE = new DateTime(2007, 05, 10); // <---Set the start date for Task One.
                taskOne.TASK_FINISH_DATE = new DateTime(2007, 05, 10); // <---Set the finish date for Task One.
                projectDs.Task.AddTaskRow(taskOne);

                // Insert a Task Two code block here.

                // Save the project to the database.
                Console.WriteLine("Saving project data to the server");
                jobId = Guid.NewGuid();
                projectSvc.QueueCreateProject(jobId, projectDs, false);
                WaitForQueue(q, jobId);

                // Publish the project.
                jobId = Guid.NewGuid();
                projectSvc.QueuePublish(jobId, projectRow.PROJ_UID, false, String.Empty);
                WaitForQueue(q, jobId);

            }
            catch (SoapException ex)
            {
                PSLibrary.PSClientError error = new PSLibrary.PSClientError(ex);
                PSLibrary.PSErrorInfo[] errors = error.GetAllErrors();
                string errMess = "==============================\r\nError: \r\n";
                for (int i = 0; i < errors.Length; i++)
                {
                    errMess += "\n" + ex.Message.ToString() + "\r\n";
                    errMess += "".PadRight(30, '=') + "\r\nPSCLientError Output:\r\n \r\n";
                    errMess += errors[i].ErrId.ToString() + "\n";

                    for (int j = 0; j < errors[i].ErrorAttributes.Length; j++)
                    {
                        errMess += "\r\n\t" + errors[i].ErrorAttributeNames()[j] + ": " + errors[i].ErrorAttributes[j];
                    }
                    errMess += "\r\n".PadRight(30, '=');
                }
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine(errMess);
            }
            catch (WebException ex)
            {
                string errMess = ex.Message.ToString() +
                   "\n\nLog on, or check the Project Server Queuing Service";
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("Error: " + errMess);
            }
            catch (Exception ex)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("Error: " + ex.Message);
            }
            finally
            {
                Console.ResetColor();
                Console.WriteLine("\r\n\r\nPress any key...");
                Console.ReadKey();
            }
        }
        static private void WaitForQueue(QueueSystemWebSvc.QueueSystem q, Guid jobId)
        {
            QueueSystemWebSvc.JobState jobState;
            const int QUEUE_WAIT_TIME = 2; // two seconds
            bool jobDone = false;
            string xmlError = string.Empty;
            int wait = 0;

            //Wait for the project to move through the queue.
            // - Get the estimated wait time in seconds.
            wait = q.GetJobWaitTime(jobId);

            // - Wait for it.
            Thread.Sleep(wait * 1000);
            // - Wait until it is done.

            do
            {
                // - Get the job state.
                jobState = q.GetJobCompletionState(jobId, out xmlError);

                if (jobState == QueueSystemWebSvc.JobState.Success)
                {
                    jobDone = true;
                }
                else
                {
                    if (jobState == QueueSystemWebSvc.JobState.Unknown
                    || jobState == QueueSystemWebSvc.JobState.Failed
                    || jobState == QueueSystemWebSvc.JobState.FailedNotBlocking
                    || jobState == QueueSystemWebSvc.JobState.CorrelationBlocked
                    || jobState == QueueSystemWebSvc.JobState.Canceled)
                    {
                        // If the job failed, throw an error.
                        throw (new ApplicationException("Queue request failed \"" + jobState + "\" Job ID: " + jobId + ".\r\n" + xmlError));
                    }
                    else
                    {
                        Console.WriteLine("Job State: " + jobState + " Job ID: " + jobId);
                        Thread.Sleep(QUEUE_WAIT_TIME * 1000);
                    }
                }
            }
            while (!jobDone);
        }
    }
}

The preceding example code sets the start and finish date for Task One to May 10, 2007. However, if you view the project in the Project Web Access Project Center Task Drill Down view (Figure 1), you see that the scheduling engine has adjusted the task start and finish dates.

Figure 1. Task One: Scheduling in Project Web Access

Task One: Scheduling in Project Web Access

Notice that the start date and finish date for Task One are set to May 7 instead of May 10. This is because the start date of the project is May 7. When the scheduling engine works out the schedule, it looks at Task One and determines that nothing prevents the task from starting as soon as the project begins. The scheduling engine changes the task start date to May 7, and the task finish date is adjusted accordingly, based on the task duration.

Working with Task Dependencies

A task dependency is a relationship between two tasks that is based on the start or finish date of the tasks. The two tasks that are linked by a dependency are referred to as the predecessor task and the successor task.

You can set four types of dependencies by using the LINK_TYPE property (see Table 1).

Table 1. Task dependency types to set by using the LINK_TYPE property

Dependency Type

Description

FinishFinish

The successor task cannot finish until the predecessor task finishes.

FinishStart

The successor task cannot start until the predecessor task finishes. This is the default value.

StartFinish

The successor task cannot finish until the predecessor task starts.

StartStart

The successor task cannot start until the predecessor task starts.

Add the following code to the Setting the Start and Finish Dates for a New Task at the embedded comment "Insert a Task Two code block here" and run the code to create a project with two tasks. The second task, named Task Two - Dependency, has a dependency of type FinishStart on Task One. The start and finish dates for Task Two - Dependency are set to May 15, 2007.

//Create Task Two - Dependency
ProjectWebSvc.ProjectDataSet.TaskRow taskTwo = projectDs.Task.NewTaskRow();
taskTwo.PROJ_UID = projectRow.PROJ_UID;
taskTwo.TASK_UID = Guid.NewGuid();
taskTwo.TASK_DUR_FMT = (int)PSLibrary.Task.DurationFormat.Day;  // Task Duration format must be specified
taskTwo.TASK_DUR = 4800;// 8 hours in Project duration time units (minute/10)
taskTwo.TASK_NAME = "Task Two - Dependency";
taskTwo.TASK_START_DATE = new DateTime(2007, 05, 15); // <---Set the start date for Task Two.
taskTwo.TASK_FINISH_DATE = new DateTime(2007, 05, 15); // <---Set the finish date for Task Two.
projectDs.Task.AddTaskRow(taskTwo);

// Add the dependency to the task we created before. 
ProjectWebSvc.ProjectDataSet.DependencyRow dependRow = projectDs.Dependency.NewDependencyRow();
dependRow.PROJ_UID = projectRow.PROJ_UID;
dependRow.LINK_PRED_UID = taskOne.TASK_UID;
dependRow.LINK_SUCC_UID = taskTwo.TASK_UID;
dependRow.LINK_UID = Guid.NewGuid();
projectDs.Dependency.AddDependencyRow(dependRow);

If you view the project in the Project Web Access Project Center Task Drill Down view (Figure 2), you see that the scheduling engine has adjusted the task start and finish dates for Task Two - Dependency.

Figure 2. Task Two - Dependency: Scheduling in Project Web Access

Task Two: Dependency Scheduling

Again, the schedule engine moves the task start date of Task One to May 7, 2007. The task start date of Task Two - Dependency is adjusted to May 8, 2007. The scheduling engine determines that Task Two - Dependency can start as soon as Task One is finished, and adjusts the task start and finish dates accordingly.

Adding a Lag or Lead Time to a Task Dependency

You can manipulate task scheduling by adding a lag time or lead time to a dependency. You can set a lag time or lead time by using the LINK_LAG property. A positive value sets a lag time, moving the start date of the successor task out by the indicated interval. A negative value sets a lead time, moving the start date of the successor task in by the indicated interval.

Add the following code to the Setting the Start and Finish Dates for a New Task at the embedded comment "Insert a Task Two code block here" and run the code to create a project with two tasks. The second task, named Task Two - Dependency with Lag, has a dependency of type FinishStart on Task One with a lag time of five working days.

// Create Task Two - Dependency with Lag.
ProjectWebSvc.ProjectDataSet.TaskRow taskTwo = projectDs.Task.NewTaskRow();
taskTwo.PROJ_UID = projectRow.PROJ_UID;
taskTwo.TASK_UID = Guid.NewGuid();
taskTwo.TASK_DUR_FMT = (int)PSLibrary.Task.DurationFormat.Day; // Task Duration format must be specified
taskTwo.TASK_DUR = 4800;// 8 hours in duration units (minute/10)
taskTwo.TASK_NAME = "Task Two - Dependency with Lag";
projectDs.Task.AddTaskRow(taskTwo);

// Add the dependency to Task One.
ProjectWebSvc.ProjectDataSet.DependencyRow dependRow = projectDs.Dependency.NewDependencyRow();
dependRow.PROJ_UID = projectRow.PROJ_UID;
dependRow.LINK_PRED_UID = taskOne.TASK_UID;
dependRow.LINK_SUCC_UID = taskTwo.TASK_UID;

//Set the lag time for the dependency.
dependRow.LINK_LAG = 24000; // <---Set a lag time of 5 working days in Project duration time units (minute/10).
dependRow.LINK_UID = Guid.NewGuid();
projectDs.Dependency.AddDependencyRow(dependRow);

If you view the project in the Project Web Access Project Center Task Drill Down view (Figure 3), you see that the scheduling engine has now scheduled Task Two - Dependency with Lag to begin on May 15, 2007.

Figure 3. Task Two - Dependency with Lag: Scheduling in Project Web Access

Task Two: Dependency with Lag Scheduling

By adding the lag time to the dependency, we force the scheduling engine to start Task Two - Dependency with Lag on May 15, 2007 as we intended. However, if the scheduling of Task One changes, Task Two - Dependency with Lag is rescheduled to maintain the five-day lag time.

Working with Task Constraints

Factors external to the data tracked in Project 2007 can require a particular task start or finish date. In such a case, you might want the task start or finish date to remain unchanged by the Project 2007 scheduling engine. You can use task constraints to impose a restriction on the task start date or the task finish date. Each task can have only a single constraint imposed on it. If you constrain the task start date, the task finish date is calculated by the scheduling engine based on that constraint and other information about the task stored in the project. Similarly, if you constrain the task finish date, the task start date is calculated by the scheduling engine.

You can set eight types of constraints by using the TASK_CONSTRAINT_TYPE property (see Table 2).

Table 2. Task constraint types to set by using the TASK_CONSTRAINT_TYPE property

Constraint Type

Description

AsLateAsPossible

Schedules the task as late as possible without delaying subsequent tasks. Use no constraint date.

AsSoonAsPossible

Schedules the task to start as early as possible. 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. After the constraint is applied, the task cannot be moved on the timescale.

MustStartOn

Schedules the task to start on the constraint date. After the constraint is applied, the task cannot be moved 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.

Add the following code to the Setting the Start and Finish Dates for a New Task at the embedded comment "Insert a Task Two code block here" and run the code to create a project with two tasks. The second task, named Task Two - Constraint, sets the TASK_CONSTRAINT_TYPE property to the value StartNoEarlierThan, and the TASK_CONSTRAINT_DATE property to May 15, 2007.

// Create Task Two - Constraint.
ProjectWebSvc.ProjectDataSet.TaskRow taskTwo = projectDs.Task.NewTaskRow();
taskTwo.PROJ_UID = projectRow.PROJ_UID;
taskTwo.TASK_UID = Guid.NewGuid();
taskTwo.TASK_DUR_FMT = (int)PSLibrary.Task.DurationFormat.Day; // Task Duration format must be specified
taskTwo.TASK_DUR = 4800;// 8 hours in Project duration time units (minute/10)
taskTwo.TASK_NAME = "Task Two - Constraint";

//Add the constraint.
taskTwo.TASK_CONSTRAINT_TYPE = (short)Microsoft.Office.Project.Server.Library.Task.ConstraintType.StartNoEarlierThan; // Set the constraint.
taskTwo.TASK_CONSTRAINT_DATE = new DateTime(2007, 05, 15); // Set the constraint date to May 15, 2007
projectDs.Task.AddTaskRow(taskTwo);

If you view the project in the Project Web Access Project Center Task Drill Down view (Figure 4), you see that the scheduling engine has scheduled Task Two - Constraint to begin on May 15, 2007.

Figure 4. Task Two - Constraint: Scheduling in Project Web Access

Task Two: Constraint Scheduling

Because we constrained the start date for Task Two - Constraint, Project 2007 is unable to shift the task start date. Changes to Task One scheduling do not affect the start date of Task Two - Constraint.

Understanding Task Types, Effort-driven Scheduling, and Resource Assignments

Task scheduling is also affected by the task type, whether the task is effort-driven, and the number and availability of assigned resources.

Three task types are available in Project 2007. The task type affects how the Project 2007 scheduling engine calculates task duration, work, and assignment units based on the following formula:

Duration = Work / Assignment Units

The task type determines which part of the formula is fixed, and which parts are calculated by the scheduling engine. You can set the task type by using the TASK_TYPE property.

Table 3. Task types to set by using the TASK_ TYPE property

Task Type

Description

Fixed duration

The duration of the task remains constant, regardless of the number of resources (Assignment Units) assigned or the amount of work.

Fixed units

The number of Assignment Units remains constant, regardless of the amount of work or duration on the task. This is the default task type.

Fixed work

The amount of work remains constant, regardless of any change in duration or the number of resources (Assignment Units) assigned to the task.

For a task type of fixed units or fixed work, the scheduling engine might recalculate the task duration if one of the other elements of the formula changes. This can result in changes to the task finish date.

By default, tasks in Project 2007 are of type fixed units and use effort-driven scheduling. Effort-driven scheduling means that when you assign resources to a task, or remove resources from a task, the Project 2007 scheduling engine lengthens or shortens the duration of the task based on the number of resources that are assigned to it without changing the total work for the task. For example, an 8-hour task with one assigned resource becomes a 4-hour task when a second resource is assigned.

You can control effort-driven scheduling for a specific task by using the TASK_IS_EFFORT_DRIVEN property. You can use the PROJ_OPT_NEW_TASKS_ARE_EFFORT_DRIVEN property to control whether the effort-driven setting is the default for all new tasks.

NoteNote

If you add or remove a resource assignment for an effort-driven task, Project Professional 2007 automatically recalculates the task duration for you. However, if you use the PSI to add or remove resource assignments for an effort-driven task, the task duration is not recalculated automatically. You must open the project in Project Professional 2007 and manually reallocate the work across the assigned resources. After the work is allocated among the assigned resources, the adjusted work information rolls up to the task level and the task duration is recalculated.

In addition to the number of assigned resources, the scheduling of effort-driven tasks is affected by the percentage of a resource's time that is allocated to that task. For example, an 8-hour task with one assigned resource becomes a 16-hour task when that resource work capacity (assignment units) for the task is set to 50% instead of 100%. You can control the percentage of a resource's time that is allocated to a particular task by using the ASSN_UNITS property.

Understanding Calendar Exceptions

Calendar exceptions can also influence task scheduling. The project calendar, task calendar, and resource calendars for assigned resources can all impact the task start and finish dates. The following sections briefly describe each of these calendars.

For more information about working with calendars and calendar exceptions programmatically, see Calendar Exceptions and Effective Work Weeks and the WebSvcCalendar and WebSvcResource namespaces.

Base Calendars

Base calendars are templates that project calendars, task calendars, and resource calendars are derived from. They define the standard working and nonworking times for the enterprise. For example the Standard base calendar, which is provided as one of the default calendars in Project 2007, reflects a traditional work schedule of Monday through Friday, 8:00 A.M. to 5:00 P.M. with an hour-long lunch break.

Project 2007 has three base calendars available by default. However, the base calendars you can access can be restricted by your enterprise configuration. Additional base calendars that meet the specific needs of your project or task can be configured from the Enterprise Calendars link on the Project Web Access Server Settings page, but you must have the ManageEnterpriseCalendars global permission to do so.

The Project Calendar

The project calendar defines the working and nonworking days and times for a specific project, and is used by default for the tasks in that project. Project 2007 uses this calendar to schedule tasks that do not have resources assigned, or for tasks that have a task type of fixed duration. You can use a project calendar to schedule nonworking times that reflect periods when the entire team will be working on nonproject activities, such as company meetings or annual reviews.

For example, if your entire organization will be in a company meeting on a Thursday you can create a new base calendar that has that particular Thursday as a nonworking day. When you select the new base calendar as the project calendar, you can prevent any tasks in that project from being scheduled on that Thursday.

You specify a base calendar as the project calendar by using the CAL_UID property.

The Task Calendar

Tasks use the specified project calendar by default; however, you can associate a different base calendar with each task as necessary. You can use a task calendar to schedule a task during nonworking times such as over nights and weekends, or to prevent particular tasks from being scheduled during normal working times.

For example, if a task requires time on a piece of machinery that runs only after hours and on weekends, you can create a base calendar with only nights and weekends as the working times. When you select that base calendar as the task calendar, that particular task will be scheduled during those working times without affecting the scheduling of other tasks in the project.

A base calendar is associated with a task by using the TASK_CAL_UID property; however, the TASK_CAL_UID property is read-only and cannot be updated programmatically. You can change the assigned task calendar by selecting an available enterprise calendar on the Advanced tab of the Task Information window in Project Professional.

The Resource Calendar

A resource calendar defines working and nonworking days and times for a specific resource or group of resources. You can use resource calendars to manage individual schedule information such as vacations and training schedules.

Resource calendar exceptions are represented by using the WebSvcResource namespace, not the WebSvcCalendar namespace. Resource calendars are stored in ResourceDataSet.CalendarExceptionsDataTable objects.

You can configure a task to ignore resource calendar exceptions by using the TASK_IGNORES_RES_CAL property. If a task is configured to ignore resource calendars, the scheduling engine schedules the task as if all assigned resources are available during normal working times according to the task calendar.

Identifying Task Drivers

Many factors can influence task start and finish dates. While we have provided some basic examples and background information on some of the most common factors, the Project 2007 schedule engine is very complex, and addressing all of the possible scenarios is beyond the scope of this article.

If your task is being scheduled in a way that you don't understand, you can gain additional insight by using the Task Drivers feature in Project Professional 2007. The Task Drivers feature displays the factors that the scheduling engine is considering when it calculates the start date of a specific task.

To use the task drivers feature, click the Task Drivers button on the toolbar in Project Professional 2007, or select Task Drivers on the Project menu (Figure 5).

Figure 5. Opening the Task Drivers pane in Project Professional

Opening the Task Drivers pane

The Task Drivers pane opens on the left and displays the factors that affect the start date of the currently highlighted task (Figure 6). You can click different tasks without closing the Task Drivers pane.

Figure 6. Task Drivers Pane in Project Professional

Task Drivers pane

The Task Drivers pane in Figure 6 displays the two factors that are influencing the task start date for Task Two in this simple project:

  • A dependency of type Finish to Start on Task One

  • The resource calendar for the assigned resource

See Also

Concepts

Calendar Exceptions and Effective Work Weeks

Project Server Programmability

Using Project Server DataSet Objects

Using the ProjTool Test Application