1use std::fmt::{Debug, Display};
2
3use chrono::{Datelike, NaiveDate};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
7pub struct ArvelieDate {
8 pub start_year: i32,
10 pub year: i32,
12 pub sub_year: SubYear,
14}
15impl ArvelieDate {
16 pub fn day_of_year(&self) -> u16 {
18 match self.sub_year {
19 SubYear::LeapDay => 366,
20 SubYear::YearDay => 365,
21 SubYear::NormalSubYear(sub_year) => {
22 sub_year.day as u16 + sub_year.month as u16 * 14 + 1
23 }
24 }
25 }
26 pub fn gregorian_year(&self) -> i32 {
28 self.start_year + self.year
29 }
30}
31impl Display for ArvelieDate {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 write!(f, "{:0>2}", self.year)?;
34 write!(f, "{}", self.sub_year)
35 }
36}
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
40pub enum SubYear {
41 NormalSubYear(NormalSubYear),
43 YearDay,
45 LeapDay,
47}
48impl Default for SubYear {
49 fn default() -> Self {
50 SubYear::NormalSubYear(NormalSubYear::default())
51 }
52}
53impl Display for SubYear {
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 match self {
56 SubYear::NormalSubYear(normal_sub_year) => write!(f, "{normal_sub_year}"),
57 SubYear::YearDay => f.write_str("+00"),
58 SubYear::LeapDay => f.write_str("+01"),
59 }
60 }
61}
62
63#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
65pub struct NormalSubYear {
66 pub month: u8,
68 pub day: u8,
70}
71impl Display for NormalSubYear {
72 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73 let chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".chars().collect::<Vec<char>>();
74 let letter = chars.get(self.month as usize).unwrap();
75 write!(f, "{letter}{:0>2}", self.day)
76 }
77}
78
79pub struct NaiveDateAndStartYear {
81 pub date: NaiveDate,
83 pub start_year: i32,
85}
86
87impl From<NaiveDateAndStartYear> for ArvelieDate {
88 fn from(value: NaiveDateAndStartYear) -> Self {
89 let NaiveDateAndStartYear { date, start_year } = value;
90 let year = date.year() - start_year;
91 let day_of_year = date.ordinal0() as i32;
92 let sub_year = match day_of_year {
93 365 => SubYear::LeapDay,
94 364 => SubYear::YearDay,
95 _ => {
96 let month = day_of_year / 14;
97 let day = day_of_year - month * 14;
98 SubYear::NormalSubYear(NormalSubYear {
99 month: month as u8,
100 day: day as u8,
101 })
102 }
103 };
104
105 ArvelieDate {
106 start_year,
107 year,
108 sub_year,
109 }
110 }
111}
112
113impl From<ArvelieDate> for NaiveDate {
114 fn from(value: ArvelieDate) -> Self {
115 NaiveDate::from_yo_opt(value.gregorian_year(), value.day_of_year() as u32).unwrap()
116 }
117}