1#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
8pub struct AmigaDate {
9 pub days: i32,
11 pub mins: i32,
13 pub ticks: i32,
15}
16
17impl AmigaDate {
18 #[inline]
20 pub const fn new(days: i32, mins: i32, ticks: i32) -> Self {
21 Self { days, mins, ticks }
22 }
23
24 #[inline]
26 pub fn to_date_time(self) -> DateTime {
27 let (year, month, day) = days_to_date(self.days);
28 let hour = (self.mins / 60) as u8;
29 let minute = (self.mins % 60) as u8;
30 let second = (self.ticks / 50) as u8;
31
32 DateTime {
33 year,
34 month,
35 day,
36 hour,
37 minute,
38 second,
39 }
40 }
41}
42
43#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
45pub struct DateTime {
46 pub year: u16,
48 pub month: u8,
50 pub day: u8,
52 pub hour: u8,
54 pub minute: u8,
56 pub second: u8,
58}
59
60fn days_to_date(mut days: i32) -> (u16, u8, u8) {
62 const DAYS_IN_MONTH: [i32; 12] = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
63
64 let mut year = 1978u16;
65
66 loop {
68 let days_in_year = if is_leap_year(year) { 366 } else { 365 };
69 if days < days_in_year {
70 break;
71 }
72 days -= days_in_year;
73 year += 1;
74 }
75
76 let mut month = 1u8;
78 let leap = is_leap_year(year);
79 for (i, &days_in_month) in DAYS_IN_MONTH.iter().enumerate() {
80 let dim = if i == 1 && leap { 29 } else { days_in_month };
81 if days < dim {
82 break;
83 }
84 days -= dim;
85 month += 1;
86 }
87
88 (year, month, (days + 1) as u8)
89}
90
91#[inline]
93const fn is_leap_year(year: u16) -> bool {
94 if year.is_multiple_of(100) {
95 year.is_multiple_of(400)
96 } else {
97 year.is_multiple_of(4)
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104
105 #[test]
106 fn test_epoch() {
107 let date = AmigaDate::new(0, 0, 0);
108 let dt = date.to_date_time();
109 assert_eq!(dt.year, 1978);
110 assert_eq!(dt.month, 1);
111 assert_eq!(dt.day, 1);
112 assert_eq!(dt.hour, 0);
113 assert_eq!(dt.minute, 0);
114 assert_eq!(dt.second, 0);
115 }
116
117 #[test]
118 fn test_known_date() {
119 let date = AmigaDate::new(6988, 0, 0);
121 let dt = date.to_date_time();
122 assert_eq!(dt.year, 1997);
123 assert_eq!(dt.month, 2);
124 assert_eq!(dt.day, 18);
125 }
126
127 #[test]
128 fn test_time() {
129 let date = AmigaDate::new(0, 754, 150); let dt = date.to_date_time();
131 assert_eq!(dt.hour, 12);
132 assert_eq!(dt.minute, 34);
133 assert_eq!(dt.second, 3);
134 }
135
136 #[test]
137 fn test_leap_year() {
138 assert!(is_leap_year(2000));
139 assert!(!is_leap_year(1900));
140 assert!(is_leap_year(1984));
141 assert!(!is_leap_year(1983));
142 }
143}