1use crate::error::UnknownEraError;
6use crate::preferences::CalendarAlgorithm;
7use crate::{
8 cal::abstract_gregorian::{impl_with_abstract_gregorian, GregorianYears},
9 calendar_arithmetic::ArithmeticDate,
10 types, Date, DateError, RangeError,
11};
12use tinystr::tinystr;
13
14#[derive(Copy, Clone, Debug, Default)]
15#[allow(clippy::exhaustive_structs)] pub struct Buddhist;
31
32impl_with_abstract_gregorian!(
33 crate::cal::Buddhist,
34 BuddhistDateInner,
35 BuddhistEra,
36 _x,
37 BuddhistEra
38);
39
40#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
41pub(crate) struct BuddhistEra;
42
43impl GregorianYears for BuddhistEra {
44 const EXTENDED_YEAR_OFFSET: i32 = -543;
45
46 fn extended_from_era_year(
47 &self,
48 era: Option<&[u8]>,
49 year: i32,
50 ) -> Result<i32, UnknownEraError> {
51 match era {
52 Some(b"be") | None => Ok(year),
53 _ => Err(UnknownEraError),
54 }
55 }
56
57 fn era_year_from_extended(&self, extended_year: i32, _month: u8, _day: u8) -> types::EraYear {
58 types::EraYear {
59 era: tinystr!(16, "be"),
60 era_index: Some(0),
61 year: extended_year,
62 extended_year,
63 ambiguity: types::YearAmbiguity::CenturyRequired,
64 }
65 }
66
67 fn debug_name(&self) -> &'static str {
68 "Buddhist"
69 }
70
71 fn calendar_algorithm(&self) -> Option<CalendarAlgorithm> {
72 Some(CalendarAlgorithm::Buddhist)
73 }
74}
75
76impl Date<Buddhist> {
77 pub fn try_new_buddhist(year: i32, month: u8, day: u8) -> Result<Date<Buddhist>, RangeError> {
92 ArithmeticDate::new_gregorian::<BuddhistEra>(year, month, day)
93 .map(BuddhistDateInner)
94 .map(|i| Date::from_raw(i, Buddhist))
95 }
96}
97
98#[cfg(test)]
99mod test {
100 use crate::cal::Iso;
101 use calendrical_calculations::rata_die::RataDie;
102
103 use super::*;
104
105 #[test]
106 fn test_buddhist_roundtrip_near_rd_zero() {
107 for i in -10000..=10000 {
108 let rd = RataDie::new(i);
109 let iso1 = Date::from_rata_die(rd, Iso);
110 let buddhist = iso1.to_calendar(Buddhist);
111 let iso2 = buddhist.to_calendar(Iso);
112 let result = iso2.to_rata_die();
113 assert_eq!(rd, result);
114 }
115 }
116
117 #[test]
118 fn test_buddhist_roundtrip_near_epoch() {
119 for i in -208326..=-188326 {
121 let rd = RataDie::new(i);
122 let iso1 = Date::from_rata_die(rd, Iso);
123 let buddhist = iso1.to_calendar(Buddhist);
124 let iso2 = buddhist.to_calendar(Iso);
125 let result = iso2.to_rata_die();
126 assert_eq!(rd, result);
127 }
128 }
129
130 #[test]
131 fn test_buddhist_directionality_near_rd_zero() {
132 for i in -100..=100 {
133 for j in -100..=100 {
134 let iso_i = Date::from_rata_die(RataDie::new(i), Iso);
135 let iso_j = Date::from_rata_die(RataDie::new(j), Iso);
136
137 let buddhist_i = Date::new_from_iso(iso_i, Buddhist);
138 let buddhist_j = Date::new_from_iso(iso_j, Buddhist);
139
140 assert_eq!(
141 i.cmp(&j),
142 iso_i.cmp(&iso_j),
143 "ISO directionality inconsistent with directionality for i: {i}, j: {j}"
144 );
145
146 assert_eq!(
147 i.cmp(&j),
148 buddhist_i.cmp(&buddhist_j),
149 "Buddhist directionality inconsistent with directionality for i: {i}, j: {j}"
150 );
151 }
152 }
153 }
154
155 #[test]
156 fn test_buddhist_directionality_near_epoch() {
157 for i in -198426..=-198226 {
159 for j in -198426..=-198226 {
160 let iso_i = Date::from_rata_die(RataDie::new(i), Iso);
161 let iso_j = Date::from_rata_die(RataDie::new(j), Iso);
162
163 let buddhist_i = Date::new_from_iso(iso_i, Buddhist);
164 let buddhist_j = Date::new_from_iso(iso_j, Buddhist);
165
166 assert_eq!(
167 i.cmp(&j),
168 iso_i.cmp(&iso_j),
169 "ISO directionality inconsistent with directionality for i: {i}, j: {j}"
170 );
171
172 assert_eq!(
173 i.cmp(&j),
174 buddhist_i.cmp(&buddhist_j),
175 "Buddhist directionality inconsistent with directionality for i: {i}, j: {j}"
176 );
177 }
178 }
179 }
180
181 #[derive(Debug)]
182 struct TestCase {
183 iso_year: i32,
184 iso_month: u8,
185 iso_day: u8,
186 buddhist_year: i32,
187 buddhist_month: u8,
188 buddhist_day: u8,
189 }
190
191 fn check_test_case(case: TestCase) {
192 let iso_year = case.iso_year;
193 let iso_month = case.iso_month;
194 let iso_day = case.iso_day;
195 let buddhist_year = case.buddhist_year;
196 let buddhist_month = case.buddhist_month;
197 let buddhist_day = case.buddhist_day;
198
199 let iso1 = Date::try_new_iso(iso_year, iso_month, iso_day).unwrap();
200 let buddhist1 = iso1.to_calendar(Buddhist);
201 assert_eq!(
202 buddhist1.era_year().year,
203 buddhist_year,
204 "Iso -> Buddhist year check failed for case: {case:?}"
205 );
206 assert_eq!(
207 buddhist1.month().ordinal,
208 buddhist_month,
209 "Iso -> Buddhist month check failed for case: {case:?}"
210 );
211 assert_eq!(
212 buddhist1.day_of_month().0,
213 buddhist_day,
214 "Iso -> Buddhist day check failed for case: {case:?}"
215 );
216
217 let buddhist2 =
218 Date::try_new_buddhist(buddhist_year, buddhist_month, buddhist_day).unwrap();
219 let iso2 = buddhist2.to_calendar(Iso);
220 assert_eq!(
221 iso2.era_year().year,
222 iso_year,
223 "Buddhist -> Iso year check failed for case: {case:?}"
224 );
225 assert_eq!(
226 iso2.month().ordinal,
227 iso_month,
228 "Buddhist -> Iso month check failed for case: {case:?}"
229 );
230 assert_eq!(
231 iso2.day_of_month().0,
232 iso_day,
233 "Buddhist -> Iso day check failed for case: {case:?}"
234 );
235 }
236
237 #[test]
238 fn test_buddhist_cases_near_rd_zero() {
239 let cases = [
240 TestCase {
241 iso_year: -100,
242 iso_month: 2,
243 iso_day: 15,
244 buddhist_year: 443,
245 buddhist_month: 2,
246 buddhist_day: 15,
247 },
248 TestCase {
249 iso_year: -3,
250 iso_month: 10,
251 iso_day: 29,
252 buddhist_year: 540,
253 buddhist_month: 10,
254 buddhist_day: 29,
255 },
256 TestCase {
257 iso_year: 0,
258 iso_month: 12,
259 iso_day: 31,
260 buddhist_year: 543,
261 buddhist_month: 12,
262 buddhist_day: 31,
263 },
264 TestCase {
265 iso_year: 1,
266 iso_month: 1,
267 iso_day: 1,
268 buddhist_year: 544,
269 buddhist_month: 1,
270 buddhist_day: 1,
271 },
272 TestCase {
273 iso_year: 4,
274 iso_month: 2,
275 iso_day: 29,
276 buddhist_year: 547,
277 buddhist_month: 2,
278 buddhist_day: 29,
279 },
280 ];
281
282 for case in cases {
283 check_test_case(case);
284 }
285 }
286
287 #[test]
288 fn test_buddhist_cases_near_epoch() {
289 let cases = [
291 TestCase {
292 iso_year: -554,
293 iso_month: 12,
294 iso_day: 31,
295 buddhist_year: -11,
296 buddhist_month: 12,
297 buddhist_day: 31,
298 },
299 TestCase {
300 iso_year: -553,
301 iso_month: 1,
302 iso_day: 1,
303 buddhist_year: -10,
304 buddhist_month: 1,
305 buddhist_day: 1,
306 },
307 TestCase {
308 iso_year: -544,
309 iso_month: 8,
310 iso_day: 31,
311 buddhist_year: -1,
312 buddhist_month: 8,
313 buddhist_day: 31,
314 },
315 TestCase {
316 iso_year: -543,
317 iso_month: 5,
318 iso_day: 12,
319 buddhist_year: 0,
320 buddhist_month: 5,
321 buddhist_day: 12,
322 },
323 TestCase {
324 iso_year: -543,
325 iso_month: 12,
326 iso_day: 31,
327 buddhist_year: 0,
328 buddhist_month: 12,
329 buddhist_day: 31,
330 },
331 TestCase {
332 iso_year: -542,
333 iso_month: 1,
334 iso_day: 1,
335 buddhist_year: 1,
336 buddhist_month: 1,
337 buddhist_day: 1,
338 },
339 TestCase {
340 iso_year: -541,
341 iso_month: 7,
342 iso_day: 9,
343 buddhist_year: 2,
344 buddhist_month: 7,
345 buddhist_day: 9,
346 },
347 ];
348
349 for case in cases {
350 check_test_case(case);
351 }
352 }
353}