为资源日历添加非工作日例外导致完成百分比计算异常
问题分析与解决方案
问题概述
编写宏读取工时表数据并更新项目TimeScaleData,为周末加班的资源添加资源日历工作日例外后,使用Application.UpdateProject更新完成百分比时出现异常:状态日期为17号,但任务完成条显示到了状态日期后约1.5个工作日的位置。若将例外添加到基础日历则正常,但会导致所有资源周末都变成工作日。
核心原因
Application.UpdateProject默认基于项目基础日历计算进度,不会自动识别单个资源日历的工作日例外。当资源在周末(基础日历非工作日)加班时,这些额外工时会被算成超出状态日期的"超前"进度,导致完成条显示异常。
解决方案
方案1:将任务日历关联到资源日历
确保任务使用资源的日历来计算进度:
- 手动操作:打开任务信息窗口 → 切换到「高级」选项卡 → 「日历」选择「资源日历」
- 宏批量设置代码:
Dim t As Task For Each t In ActiveSelection.Tasks t.Calendar = t.Assignments(1).Resource.Calendar ' 假设任务仅分配单个资源 Next t
设置后,UpdateProject会基于资源日历的工作日计算进度,周末加班的工时会被纳入状态日期内的完成量。
方案2:手动计算完成百分比
替代UpdateProject的自动更新逻辑,根据实际完成的工时手动计算:
Dim t As Task Dim actualWork As Double Dim totalWork As Double Dim statusDt As Date statusDt = proj.StatusDate For Each t In ActiveSelection.Tasks totalWork = t.Work If totalWork > 0 Then ' 计算到状态日期的实际工时 actualWork = t.TimeScaleData(StartDate:=t.Start, EndDate:=statusDt, Type:=pjResourceTimescaleWork, TimeScaleUnit:=pjDay).Total ' 设置完成百分比 t.PercentComplete = (actualWork / totalWork) * 100 End If Next t
这种方式直接基于实际完成的工时计算,完全匹配资源的实际工作时间,不受日历设置的影响。
方案3:临时修改项目日历(谨慎使用)
如果必须使用UpdateProject,可临时为项目日历添加对应周末的例外,更新后再移除:
Dim projCal As Calendar Dim tempException As Exception Dim timesheetDate As Date timesheetDate = ' 替换为实际加班日期 Set projCal = ActiveProject.Calendar ' 添加临时例外 Set tempException = projCal.Exceptions.Add(Type:=pjDaily, Start:=timesheetDate, Finish:=timesheetDate, Occurrences:=1) tempException.Shift1.Start = proj.DefaultStartTime tempException.Shift1.Finish = #1:00:00 PM# tempException.Shift2.Start = #1:24:00 PM# tempException.Shift2.Finish = proj.DefaultFinishTime ' 更新完成百分比 Application.UpdateProject All:=False, UpdateDate:=proj.StatusDate, Action:=pj0to100Percent ' 移除临时例外 projCal.Exceptions.Delete tempException.Index
注意:此方法会临时影响所有使用项目日历的任务,仅适合单独处理特定任务时使用。
内容的提问来源于stack exchange,提问作者RadTunesly
相关产品推荐
相关产品推荐

