sac13/lib.rs
1/*!
2
3# sac13
4
5<a href="https://sac13.net"><img alt="Static Badge" src="https://img.shields.io/badge/web-SAC13-yellow"></a>
6<a href="https://codeberg.org/SAC13/sac13.rs"><img alt="Repository link icon" src="https://img.shields.io/badge/repo-sac13.rs-blue"></a>
7<a href="https://crates.io/crates/sac13"><img alt="Crates.io Version" src="https://img.shields.io/crates/v/sac13"></a>
8<a href="https://docs.rs/sac13"><img alt="docs.rs" src="https://img.shields.io/docsrs/sac13"></a>
9
10SAC13 is a 13-month solar calendar with fixed four-week months,
11starting each year with the March Equinox.
12
13This library is the Rust reference implementation for SAC13 and maintains data types and functions
14to convert from the Gregorian Calendar to SAC13 and vice versa.
15
16If you want to interop with other calendar systems it also provides,
17among others, conversions from and to
18
19 - [JulianDay](crate::day_counts::JulianDay)s
20 - [UnixDay](crate::day_counts::UnixDay)s (days since 1970-01-01)
21
22*/
23
24#![no_std]
25
26#[cfg(test)]
27#[macro_use]
28extern crate std;
29
30/// Creates a [SAC13 year](Year) with a statically and compile time checked value.
31///
32/// # Example
33///
34/// ```
35/// use sac13::year;
36///
37/// let year = year!(M020);
38///
39/// let year_zero = year!(A000);
40/// let last_year = year!(Z999);
41///
42/// // The following lines are invalid years (or format) and would fail during compilation:
43/// // let year = year!(m020);
44/// // let year = year!(20020);
45/// // let year = year!(-100);
46/// // let year = year!(20);
47/// ```
48#[macro_export]
49macro_rules! year {
50 ($year:ident) => {
51 const {
52 $crate::Year::try_from_str(core::stringify!($year))
53 .expect(concat!("Invalid SAC13 year: ", stringify!($year)))
54 }
55 };
56}
57
58/// Creates a [Gregorian Calendar date](GregorianDate) with a statically known and compile time checked value.
59///
60/// # Example
61///
62/// ```
63/// use sac13::prelude::*;
64///
65/// let date = date_greg!(2020 - 04 - 17);
66/// let date = date_greg!(2020 - 02 - 29); // leap year
67///
68/// // the following line would not compile (because 2021 wasn't a leap year)
69/// // let date = date_greg!(2021 - 02 - 29);
70/// ```
71#[macro_export]
72macro_rules! date_greg {
73 ($year:literal - $month:literal - $day:literal) => {
74 const {
75 #[allow(clippy::zero_prefixed_literal)]
76 let y = $year;
77
78 #[allow(clippy::zero_prefixed_literal)]
79 let m = $month;
80
81 #[allow(clippy::zero_prefixed_literal)]
82 let d = $day;
83
84 $crate::GregorianDate::from_ymd(y, m, d)
85 .expect("The given input was not a valid Gregorian Calendar date")
86 }
87 };
88}
89
90/// Creates a [SAC13 date](Date) with a statically known and compile time checked value.
91///
92/// # Example
93///
94/// ```
95/// use sac13::prelude::*;
96///
97/// let date = date!(M020 - 04 - 14); // "regular" day
98/// let date = date!(M020 - 13 - 29); // year day
99/// let date = date!(M021 - 06 - 29); // leap day
100///
101/// // the following lines would not compile
102///
103/// // date = date!(M022 - 06 - 29); // M022 is not a leap year
104/// // date = date!(M022 - 04 - 29); // No month except August on leap years and Addenduary have more than 28 days
105///
106/// ```
107#[macro_export]
108macro_rules! date {
109 ($year:ident - $month:literal - $day:literal) => {
110 const {
111 let y = $crate::year!($year);
112
113 #[allow(clippy::zero_prefixed_literal)]
114 let m = $month;
115
116 #[allow(clippy::zero_prefixed_literal)]
117 let d = $day;
118
119 let m = $crate::Month::new(m).expect(concat!(
120 "Month must be a value from 1 - 13. Given: ",
121 $month
122 ));
123
124 $crate::Date::from_ymd(y, m, d).expect("The given input was not a valid SAC13 date")
125 }
126 };
127}
128
129macro_rules! ok {
130 ($opt:expr) => {
131 match $opt {
132 ::core::option::Option::None => return ::core::option::Option::None,
133 ::core::option::Option::Some(x) => x,
134 }
135 };
136}
137
138/// The type of the year.
139///
140/// A [`YearType::Common`] year has 365 days and a [`YearType::Leap`] year has 366 days.
141#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
142pub enum YearType {
143 Common,
144 Leap,
145}
146
147mod date_gregorian;
148mod date_sac13;
149mod month;
150mod parse;
151mod scalars;
152
153#[cfg(test)]
154mod tests;
155
156mod traits;
157
158pub mod prelude;
159
160/// Primitive types for linear day counts like the [Julian Day Number](crate::scalars::JulianDay).
161pub mod day_counts {
162 pub use crate::date_sac13::raw_date::YearOrdinal;
163 pub use crate::scalars::{CycleEpochDay, JulianDay, Sac13Day, UnixDay};
164}
165
166pub use parse::ComponentOrder;
167pub use parse::GregorianOrSac13;
168pub use parse::ParsedDate;
169pub use parse::parse_date_str;
170
171pub use date_gregorian::GregorianDate;
172pub use date_sac13::Date;
173pub use scalars::Year;
174pub use traits::CalendarDate;
175
176pub use month::Month;