Skip to content

shifts

shifts ¤

Shift assignment and production-day helpers.

Production shifts are grouped by (date, shift). A shift that crosses midnight -- e.g. a night shift 22:00 -> 06:00 -- breaks the naive timestamp.date() grouping: a reading at 23:00 and a reading at 03:00 the next morning belong to the same physical shift, but they carry two different calendar dates. Worse, within a single calendar date the night-shift group then spans 00:00-06:00 and 22:00-23:59 with an 16-hour hole, so a last - first over that group sweeps in the whole day's production.

The fix is a production day: the post-midnight portion of an overnight shift is attributed to the shift's start date, so each (date, shift) group is one contiguous interval. :func:production_dates computes it; it is opt-in at the call sites so day-only schedules are unaffected.

assign_shift ¤

assign_shift(
    timestamp: Timestamp | datetime | Series,
    shift_definitions: dict[str, tuple[str, str]],
) -> str | pd.Series

Return the shift a timestamp falls in, or "unknown".

An overnight shift (start time >= end time, e.g. 22:00 -> 06:00) matches timestamps at or after its start or before its end. Shifts are tried in the order of shift_definitions; the first match wins.

Pass a datetime Series to label every row at once (vectorized). The local wall-clock time is used for tz-aware data, and a missing timestamp (NaT) is labeled "unknown".

Parameters:

Name Type Description Default
timestamp Timestamp | datetime | Series

A single timestamp, or a datetime Series.

required
shift_definitions dict[str, tuple[str, str]]

Mapping of shift name to (start, end) strings.

required

Returns:

Type Description
str | Series

The shift name, or a Series of shift names aligned to timestamp.

production_dates ¤

production_dates(
    timestamps: Series,
    shifts: Series,
    shift_definitions: dict[str, tuple[str, str]],
) -> pd.Series

Production date for each timestamp given its assigned shift.

For a reading in the post-midnight portion of an overnight shift (its time is before the shift's end), the production date is the previous calendar day -- the shift's start date. All other readings keep their calendar date.

Parameters:

Name Type Description Default
timestamps Series

Datetime Series.

required
shifts Series

Shift name per timestamp (from :func:assign_shift), aligned to timestamps.

required
shift_definitions dict[str, tuple[str, str]]

Mapping of shift name to (start, end) strings.

required

Returns:

Type Description
Series

A Series of :class:datetime.date, aligned to timestamps.