use time::Date;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize)]
pub enum NetzzugangRegime {
Nzv,
EnwgFestlegung,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize)]
pub enum EntgeltRegime {
Verordnung,
AgNeS,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize)]
pub struct RegulatoryRegime {
netzzugang: NetzzugangRegime,
entgelt: EntgeltRegime,
tarifjahr: i32,
}
const NZV_LETZTER_TAG: Date = time::macros::date!(2025 - 12 - 31);
const VERORDNUNG_LETZTER_TAG: Date = time::macros::date!(2028 - 12 - 31);
impl RegulatoryRegime {
#[must_use]
pub fn for_period(period_from: Date, period_to: Date) -> Self {
let _ = period_from;
Self {
netzzugang: if period_to <= NZV_LETZTER_TAG {
NetzzugangRegime::Nzv
} else {
NetzzugangRegime::EnwgFestlegung
},
entgelt: if period_to <= VERORDNUNG_LETZTER_TAG {
EntgeltRegime::Verordnung
} else {
EntgeltRegime::AgNeS
},
tarifjahr: period_from.year(),
}
}
#[must_use]
pub const fn new(netzzugang: NetzzugangRegime, entgelt: EntgeltRegime, tarifjahr: i32) -> Self {
Self {
netzzugang,
entgelt,
tarifjahr,
}
}
#[must_use]
pub const fn netzzugang(&self) -> NetzzugangRegime {
self.netzzugang
}
#[must_use]
pub const fn entgelt(&self) -> EntgeltRegime {
self.entgelt
}
#[must_use]
pub const fn tarifjahr(&self) -> i32 {
self.tarifjahr
}
#[must_use]
pub fn straddles_turnover(period_from: Date, period_to: Date) -> bool {
let start = Self::for_period(period_from, period_from);
let end = Self::for_period(period_to, period_to);
start.netzzugang != end.netzzugang || start.entgelt != end.entgelt
}
}
#[cfg(test)]
mod tests {
use super::*;
use time::macros::date;
#[test]
fn the_nzv_regime_ends_with_2025() {
let last = RegulatoryRegime::for_period(date!(2025 - 12 - 01), date!(2025 - 12 - 31));
assert_eq!(last.netzzugang(), NetzzugangRegime::Nzv);
let first_after =
RegulatoryRegime::for_period(date!(2026 - 01 - 01), date!(2026 - 01 - 31));
assert_eq!(first_after.netzzugang(), NetzzugangRegime::EnwgFestlegung);
}
#[test]
fn the_verordnung_regime_ends_with_2028() {
let last = RegulatoryRegime::for_period(date!(2028 - 12 - 01), date!(2028 - 12 - 31));
assert_eq!(last.entgelt(), EntgeltRegime::Verordnung);
let first_after =
RegulatoryRegime::for_period(date!(2029 - 01 - 01), date!(2029 - 01 - 31));
assert_eq!(first_after.entgelt(), EntgeltRegime::AgNeS);
}
#[test]
fn a_period_is_governed_by_the_rules_at_its_end() {
let straddling = RegulatoryRegime::for_period(date!(2025 - 12 - 15), date!(2026 - 01 - 15));
assert_eq!(straddling.netzzugang(), NetzzugangRegime::EnwgFestlegung);
}
#[test]
fn a_straddling_period_is_detected() {
assert!(RegulatoryRegime::straddles_turnover(
date!(2025 - 12 - 15),
date!(2026 - 01 - 15)
));
assert!(RegulatoryRegime::straddles_turnover(
date!(2028 - 12 - 15),
date!(2029 - 01 - 15)
));
assert!(!RegulatoryRegime::straddles_turnover(
date!(2026 - 01 - 01),
date!(2026 - 12 - 31)
));
}
#[test]
fn an_explicit_regime_overrides_the_calendar() {
let historical =
RegulatoryRegime::new(NetzzugangRegime::Nzv, EntgeltRegime::Verordnung, 2024);
assert_eq!(historical.netzzugang(), NetzzugangRegime::Nzv);
assert_eq!(historical.tarifjahr(), 2024);
}
#[test]
fn the_tarifjahr_follows_the_period_start() {
let r = RegulatoryRegime::for_period(date!(2026 - 03 - 01), date!(2026 - 03 - 31));
assert_eq!(r.tarifjahr(), 2026);
}
}