Repository navigation
A minor release. A calendar's hours per day are the hours its shifts work when every working day of its week works the same number of hours and day_hr_cnt says otherwise. That is how P6 schedules, measured on Primavera P6 Professional 23.12.1's own F9.
Changed
-
Hours per day come from the shifts when
day_hr_cntdisagrees with all of them. P6 schedules a duration in hours against the calendar's shifts;day_hr_cnt("Hours per Day") only converts hours to days for display. Scheduled with F9 on 10-Oct-2026, a Monday-Saturday 07:00-17:00 calendar declaring 8 ran a 40 h activity over four days.get_calendar_mapdivided by 8 and gave five; it now giveshours_per_day10, andduration_hours_to_days('40', cal)gives 4.Each working day's hours are read from the DaysOfWeek block, in either P6 slot order, with a 00:00 finish read as the end of the day. A week whose working days work different hours keeps
day_hr_cnt, and so does a calendar with no hours to read. The rule is the onecpp-cpm-enginev2.9.54'sparseXERapplies.
Added
declared_hours_per_dayon such a calendar: the file'sday_hr_cnt, as it was.calendar_shift_hours(cal_map)lists those calendars.CalendarShiftHoursWarning, raised once per such calendar.
What can move
hours_per_day on a calendar of that shape, and every conversion that reads it: duration_hours_to_days, the float generate_summary reports, and anything a caller computes from the map. Nothing moves on any other calendar.
Why a minor release. Before 1.0 this project moves the minor number for a release that changes results a caller already reads.
Testing
tests/test_calendar_shift_hours_2026_10_10.py has 7 synthetic tests. The three that pin the change fail on v0.2.1, and two more fail there because the function they call is new. pytest tests/ is 116 tests across 12 files: 115 pass and the engine-parity test skips, and all 116 pass with cpp-cpm-engine v2.9.54's python_reference on sys.path.
See CHANGELOG.md.