pub struct ShiftCycleConfig {
pub cycle: Vec<ShiftType>,
pub cycle_length: u32,
pub reference_date: NaiveDate,
pub total_teams: u32,
}Expand description
Runtime shift cycle configuration.
The default 42-day, 6-team configuration is available via
default_config().
§Custom cycles
use shift_algorithm::{ShiftCycleConfig, ShiftType};
use chrono::NaiveDate;
let config = ShiftCycleConfig {
cycle: vec![ShiftType::Morning, ShiftType::Afternoon, ShiftType::Rest],
cycle_length: 3,
reference_date: NaiveDate::from_ymd_opt(2025, 12, 15).unwrap(),
total_teams: 1,
};Fields§
§cycle: Vec<ShiftType>The ordered list of shift types defining one full cycle.
Must have length == cycle_length.
cycle_length: u32Number of days in one full cycle (= cycle.len()).
reference_date: NaiveDateThe anchor reference date. Day 1 of the cycle falls on this date. Default: 2025-12-15.
total_teams: u32Total number of teams sharing this cycle.
Each team is offset by cycle_length / total_teams days.
Default: 6.
Implementations§
Source§impl ShiftCycleConfig
impl ShiftCycleConfig
Sourcepub fn new(
cycle: Vec<ShiftType>,
reference_date: NaiveDate,
total_teams: u32,
) -> Self
pub fn new( cycle: Vec<ShiftType>, reference_date: NaiveDate, total_teams: u32, ) -> Self
Create a new config, validating that cycle.len() == cycle_length.
§Panics
Panics if cycle.len() != cycle_length as usize.
Sourcepub fn successor_of(&self, team_id: u32) -> u32
pub fn successor_of(&self, team_id: u32) -> u32
The team that follows yours in the circular rotation order.
Convenience wrapper around successor_team_id using self.total_teams.
use shift_algorithm::cycle::default_config;
let config = default_config();
assert_eq!(config.successor_of(1), 2);
assert_eq!(config.successor_of(6), 1);Sourcepub fn predecessor_of(&self, team_id: u32) -> u32
pub fn predecessor_of(&self, team_id: u32) -> u32
The team that yours follows in the circular rotation order.
The predecessor is the team whose shift your team takes over.
Convenience wrapper around predecessor_team_id using self.total_teams.
use shift_algorithm::cycle::default_config;
let config = default_config();
assert_eq!(config.predecessor_of(1), 6); // Team 1 takes over from Team 6
assert_eq!(config.predecessor_of(2), 1); // Team 2 takes over from Team 1
assert_eq!(config.predecessor_of(6), 5);Sourcepub fn team_phase_offset(&self, team_id: u32) -> u32
pub fn team_phase_offset(&self, team_id: u32) -> u32
Team phase offset in days.
Formula: (team_id - 1) * (cycle_length / total_teams).
For a 42-day, 6-team cycle:
- Team 1 (一值): offset 0
- Team 2 (二值): offset 7
- Team 3 (三值): offset 14
- …
- Team 6 (六值): offset 35
use shift_algorithm::cycle::default_config;
let config = default_config();
assert_eq!(config.team_phase_offset(1), 0);
assert_eq!(config.team_phase_offset(2), 7);
assert_eq!(config.team_phase_offset(6), 35);Sourcepub fn shift_handover(
&self,
date: NaiveDate,
team_id: u32,
) -> Option<(u32, u32)>
pub fn shift_handover( &self, date: NaiveDate, team_id: u32, ) -> Option<(u32, u32)>
Find which team you take over from and which team takes over from you.
Shift handover happens within a single day between different shift types:
- 夜 → 早 → 中 → 夜 (cyclical)
- If you are on 休 or 学, there is no handover (you’re not working).
Returns (predecessor_team_id, successor_team_id) — the teams whose shifts
you take over from and who takes over from you, respectively.
use shift_algorithm::cycle::default_config;
use chrono::NaiveDate;
let config = default_config();
let date = NaiveDate::from_ymd_opt(2026, 6, 26).unwrap();
// If team 1 is working 早班 today, predecessor should be the team on 夜班,
// successor should be the team on 中班.
if let Some((pred, succ)) = config.shift_handover(date, 1) {
println!("Take over from team {}, hand over to team {}", pred, succ);
}Trait Implementations§
Source§impl Clone for ShiftCycleConfig
impl Clone for ShiftCycleConfig
Source§fn clone(&self) -> ShiftCycleConfig
fn clone(&self) -> ShiftCycleConfig
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more