bo4e_core/com/
date_range.rs1use chrono::NaiveDate;
4use serde::{Deserialize, Serialize};
5
6use crate::traits::{Bo4eMeta, Bo4eObject};
7
8#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
25#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
26#[cfg_attr(feature = "json-schema", schemars(rename = "Datumsbereich"))]
27#[serde(rename_all = "camelCase")]
28pub struct DateRange {
29 #[serde(flatten)]
31 pub meta: Bo4eMeta,
32
33 #[serde(skip_serializing_if = "Option::is_none")]
35 #[cfg_attr(feature = "json-schema", schemars(rename = "startdatum"))]
36 pub start_date: Option<NaiveDate>,
37
38 #[serde(skip_serializing_if = "Option::is_none")]
40 #[cfg_attr(feature = "json-schema", schemars(rename = "enddatum"))]
41 pub end_date: Option<NaiveDate>,
42}
43
44impl Bo4eObject for DateRange {
45 fn type_name_german() -> &'static str {
46 "Datumsbereich"
47 }
48
49 fn type_name_english() -> &'static str {
50 "DateRange"
51 }
52
53 fn meta(&self) -> &Bo4eMeta {
54 &self.meta
55 }
56
57 fn meta_mut(&mut self) -> &mut Bo4eMeta {
58 &mut self.meta
59 }
60}
61
62impl DateRange {
63 pub fn new(start: NaiveDate, end: NaiveDate) -> Self {
65 Self {
66 start_date: Some(start),
67 end_date: Some(end),
68 ..Default::default()
69 }
70 }
71
72 pub fn year(year: i32) -> Self {
74 Self {
75 start_date: NaiveDate::from_ymd_opt(year, 1, 1),
76 end_date: NaiveDate::from_ymd_opt(year, 12, 31),
77 ..Default::default()
78 }
79 }
80
81 pub fn contains(&self, date: NaiveDate) -> bool {
83 let after_start = self.start_date.map_or(true, |s| date >= s);
84 let before_end = self.end_date.map_or(true, |e| date <= e);
85 after_start && before_end
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92
93 #[test]
94 fn test_date_range_creation() {
95 let start = NaiveDate::from_ymd_opt(2024, 1, 1).unwrap();
96 let end = NaiveDate::from_ymd_opt(2024, 12, 31).unwrap();
97
98 let range = DateRange::new(start, end);
99 assert_eq!(range.start_date, Some(start));
100 assert_eq!(range.end_date, Some(end));
101 }
102
103 #[test]
104 fn test_year_range() {
105 let range = DateRange::year(2024);
106 assert_eq!(range.start_date, NaiveDate::from_ymd_opt(2024, 1, 1));
107 assert_eq!(range.end_date, NaiveDate::from_ymd_opt(2024, 12, 31));
108 }
109
110 #[test]
111 fn test_contains() {
112 let range = DateRange::year(2024);
113 let mid = NaiveDate::from_ymd_opt(2024, 6, 15).unwrap();
114 assert!(range.contains(mid));
115
116 let before = NaiveDate::from_ymd_opt(2023, 12, 31).unwrap();
117 assert!(!range.contains(before));
118 }
119
120 #[test]
121 fn test_roundtrip() {
122 let range = DateRange::year(2024);
123 let json = serde_json::to_string(&range).unwrap();
124 let parsed: DateRange = serde_json::from_str(&json).unwrap();
125 assert_eq!(range, parsed);
126 }
127
128 #[test]
129 fn test_bo4e_object_impl() {
130 assert_eq!(DateRange::type_name_german(), "Datumsbereich");
131 assert_eq!(DateRange::type_name_english(), "DateRange");
132 }
133}