For tasks without recourse the start and end dates are not calculated correctly

For tasks without recourse the start and end dates are not calculated correctly when using the Recalculate method.

Here is sample C # code (attached Project1.mpp):

	[TestMethod]
	public void Incorrect_Dates_After_Import()
	{
		using (var destinationStream = ProjetoPadrao.Carregar())
		{
			var destination = new Project(destinationStream);

			using (var originStream = File.Open(@"C:\Aspose - Bugs\Project1.mpp", FileMode.Open))
			{
				var origin = new Project(originStream);

				destination.CalculationMode = CalculationMode.None;

				ImportResources(origin, destination);
				ImportRootTask(origin, destination);
				ImportTasks(origin.RootTask.Children, destination);

				var destnationTasks = new List<Task>();
				GetAllTasks(destination.RootTask, destnationTasks);

				var links = origin.TaskLinks;

				foreach (var link in links)
				{
					var predTaskOrigin = link.PredTask;
					var succTaskOrigin = link.SuccTask;
				
					if (predTaskOrigin != null && succTaskOrigin != null && !succTaskOrigin.Children.Any())
					{
						var predTask = destnationTasks.SingleOrDefault(t => t.Get(Tsk.Id) == predTaskOrigin.Get(Tsk.Id));
						var succTask = destnationTasks.SingleOrDefault(t => t.Get(Tsk.Id) == succTaskOrigin.Get(Tsk.Id));
				
						var duration = destination.GetDuration(link.LinkLag, link.LagFormat);
				
						if (predTask != null && succTask != null)
						{
							var taskLink = destination.TaskLinks.Add(predTask, succTask, link.LinkType, destination.GetDuration(link.LinkLag / 10, TimeUnitType.Minute).Convert(link.LagFormat));
							taskLink.LagFormat = link.LagFormat;
						}
					}
				}

				var tasksBeforeRecalculate = destination.TaskLinks.Where(t => t.SuccTask.Get(Tsk.Start) <= t.SuccTask.Get(Tsk.Finish));
				Assert.IsTrue(tasksBeforeRecalculate.Count() == destination.TaskLinks.Count);
				destination.Recalculate();

				var tasksAfterRecalculate = destination.TaskLinks.Where(t => t.SuccTask.Get(Tsk.Start) <= t.SuccTask.Get(Tsk.Finish));
				Assert.IsTrue(tasksBeforeRecalculate.Count() == destination.TaskLinks.Count);
			}
		}
	}

	private static IEnumerable<Task> GetAllTasks(Task parentTask, List<Task> list)
	{
		foreach (var task in parentTask.Children)
		{
			list.Add(task);
			GetAllTasks(task, list);
		}
		return list;
	}
	
	private void ImportResources(Project origin, Project destination)
	{
		foreach (var resource in origin.Resources)
			destination.Resources.Add(resource.Get(Rsc.Name));
	}

	private void ImportTasks(IEnumerable<Task> tasks, Project destination)
	{
		foreach (var task in tasks)
		{
			var newTask = destination.RootTask.Children.Add(task.Get(Tsk.Name));
			destination.RootTask.Children.Add(CloneTask(task, newTask, destination));

			if (task.Children.Any())
				ImportChildrenOfATask(task.Children, newTask, destination);
		}
	}

	private void ImportChildrenOfATask(TaskCollection children, Task task, Project project)
	{
		foreach (var child in children)
		{
			Task newChild = task.Children.Add(child.Get(Tsk.Name));
			task.Children.Add(CloneTask(child, newChild, project));

			if (child.Children.Any())
				ImportChildrenOfATask(child.Children, newChild, project);
		}
	}

	private void ImportRootTask(Project origin, Project destination)
	{
		CloneTask(origin.RootTask, destination.RootTask, destination);
	}

	private Task CloneTask(Task origin, Task destination, Project project)
	{
		if (!origin.Children.Any())
		{
			foreach (var assignment in origin.Assignments)
			{
				var resource = assignment.Get(Asn.Resource);
				if (resource != null)
				{
					var resourceName = String.IsNullOrEmpty(resource.Get(Rsc.Name)) ? $"{Siteware.Resources.Resource.Recurso + " " + resource.Get(Rsc.Uid)}" : resource.Get(Rsc.Name);

					var res = project.Resources.SingleOrDefault(r => r.Get(Rsc.Id) == resource.Get(Rsc.Id));
					res.Set(Rsc.Name, resourceName);

					var newAssignment = project.ResourceAssignments.Add(destination, res, assignment.Get(Asn.Units));
					newAssignment.Set(Asn.Work, assignment.Get(Asn.Work));
				}
			}
			destination.Set(Tsk.Duration, origin.Get(Tsk.Duration));
			destination.Set(Tsk.DurationFormat, TimeUnitType.Day);

			SetWork(destination, destination.Get(Tsk.Work).ToDouble(), TimeUnitType.Hour);
		}

		destination.Set(Tsk.Start, origin.Get(Tsk.Start).Date);
		destination.Set(Tsk.Finish, origin.Get(Tsk.Finish).Date);

		destination.Set(Tsk.Id, origin.Get(Tsk.Id));
		destination.Set(Tsk.OutlineLevel, origin.Get(Tsk.OutlineLevel));

		destination.Set(Tsk.IsMilestone, origin.Get(Tsk.IsMilestone));
		SetWork(destination, destination.Get(Tsk.Work).ToDouble(), TimeUnitType.Hour);

		DateTime? constraintDate = origin.Get(Tsk.ConstraintDate).Date;

		var constraintType = origin.Get(Tsk.ConstraintType);
		constraintDate = ReturnConstraintDate(constraintType, origin.Get(Tsk.ConstraintDate).Date, project);

		destination.Set(Tsk.ConstraintType, constraintType);
		if (constraintDate.HasValue)
			destination.Set(Tsk.ConstraintDate, constraintDate.Value);

		return destination;
	}

	private DateTime? ReturnConstraintDate(ConstraintType constraintType, DateTime constraintDate, Project project)
	{
		if (constraintDate == DateTime.MinValue)
			return null;

		var calendar = project.Calendars.First();

		var startHour = TimeSpan.FromHours(calendar.GetWorkingTimes(DateTime.UtcNow).First().FromTime.Hour);
		var finishHour = TimeSpan.FromHours(calendar.GetWorkingTimes(DateTime.UtcNow).LastOrDefault().ToTime.Hour);

		switch (constraintType)
		{
			case ConstraintType.AsLateAsPossible: { constraintDate = constraintDate.Date + startHour; break; }

			case ConstraintType.AsSoonAsPossible: { constraintDate = constraintDate.Date + startHour; break; }

			case ConstraintType.FinishNoEarlierThan: { constraintDate = constraintDate.Date + finishHour; break; }

			case ConstraintType.FinishNoLaterThan: { constraintDate = constraintDate.Date + finishHour; break; }

			case ConstraintType.MustFinishOn: { constraintDate = constraintDate.Date + finishHour; break; }

			case ConstraintType.MustStartOn: { constraintDate = constraintDate.Date + startHour; break; }

			case ConstraintType.StartNoEarlierThan: { constraintDate = constraintDate.Date + startHour; break; }

			case ConstraintType.StartNoLaterThan: { constraintDate = constraintDate.Date + startHour; break; }
		}
		return constraintDate;
	}

	private Task SetWork(Task task, double value, TimeUnitType timeUnit)
	{
		var duration = task.ParentProject.GetDuration(value, timeUnit).Convert(TimeUnitType.Hour);
		task.Set(Tsk.Work, duration);

		return task;
	}

This Topic is created by kashif.iqbal using the Email to Eopic plugin.

Hi,

Reference Thread:

We have investigated the issue at our end and it seems to be due to an error in your code. When tasks are being copied the time part is trimmed which is incorrect. Please remove “.Date” in next expressions of CloneTask method to fix this. Thus,

destination.Set(Tsk.Start, origin.Get(Tsk.Start).Date);
destination.Set(Tsk.Finish, origin.Get(Tsk.Finish).Date);

should become:

destination.Set(Tsk.Start, origin.Get(Tsk.Start));
destination.Set(Tsk.Finish, origin.Get(Tsk.Finish));

Please try it at your end and let us know feedback.