1 // This is a part of Chrono.
2 // See README.md and LICENSE.txt for details.
3
4 //! The internal implementation of the calendar and ordinal date.
5 //!
6 //! The current implementation is optimized for determining year, month, day and day of week.
7 //! 4-bit `YearFlags` map to one of 14 possible classes of year in the Gregorian calendar,
8 //! which are included in every packed `NaiveDate` instance.
9 //! The conversion between the packed calendar date (`Mdf`) and the ordinal date (`Of`) is
10 //! based on the moderately-sized lookup table (~1.5KB)
11 //! and the packed representation is chosen for the efficient lookup.
12 //! Every internal data structure does not validate its input,
13 //! but the conversion keeps the valid value valid and the invalid value invalid
14 //! so that the user-facing `NaiveDate` can validate the input as late as possible.
15
16 #![allow(dead_code)] // some internal methods have been left for consistency
17 #![cfg_attr(feature = "__internal_bench", allow(missing_docs))]
18
19 use core::{fmt, i32};
20 use div::{div_rem, mod_floor};
21 use num_traits::FromPrimitive;
22 use Weekday;
23
24 /// The internal date representation. This also includes the packed `Mdf` value.
25 pub type DateImpl = i32;
26
27 pub const MAX_YEAR: DateImpl = i32::MAX >> 13;
28 pub const MIN_YEAR: DateImpl = i32::MIN >> 13;
29
30 /// The year flags (aka the dominical letter).
31 ///
32 /// There are 14 possible classes of year in the Gregorian calendar:
33 /// common and leap years starting with Monday through Sunday.
34 /// The `YearFlags` stores this information into 4 bits `abbb`,
35 /// where `a` is `1` for the common year (simplifies the `Of` validation)
36 /// and `bbb` is a non-zero `Weekday` (mapping `Mon` to 7) of the last day in the past year
37 /// (simplifies the day of week calculation from the 1-based ordinal).
38 #[derive(PartialEq, Eq, Copy, Clone)]
39 pub struct YearFlags(pub u8);
40
41 pub const A: YearFlags = YearFlags(0o15);
42 pub const AG: YearFlags = YearFlags(0o05);
43 pub const B: YearFlags = YearFlags(0o14);
44 pub const BA: YearFlags = YearFlags(0o04);
45 pub const C: YearFlags = YearFlags(0o13);
46 pub const CB: YearFlags = YearFlags(0o03);
47 pub const D: YearFlags = YearFlags(0o12);
48 pub const DC: YearFlags = YearFlags(0o02);
49 pub const E: YearFlags = YearFlags(0o11);
50 pub const ED: YearFlags = YearFlags(0o01);
51 pub const F: YearFlags = YearFlags(0o17);
52 pub const FE: YearFlags = YearFlags(0o07);
53 pub const G: YearFlags = YearFlags(0o16);
54 pub const GF: YearFlags = YearFlags(0o06);
55
56 static YEAR_TO_FLAGS: [YearFlags; 400] = [
57 BA, G, F, E, DC, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA,
58 G, F, E, DC, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G,
59 F, E, DC, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F,
60 E, DC, B, A, G, FE, D, C, B, AG, F, E, D, // 100
61 C, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, DC,
62 B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B,
63 A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B, A,
64 G, FE, D, C, B, AG, F, E, D, CB, A, G, F, // 200
65 E, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B, A, G, FE,
66 D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B, A, G, FE, D,
67 C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B, A, G, FE, D, C,
68 B, AG, F, E, D, CB, A, G, F, ED, C, B, A, // 300
69 G, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B, A, G, FE, D, C, B, AG,
70 F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B, A, G, FE, D, C, B, AG, F,
71 E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B, A, G, FE, D, C, B, AG, F, E,
72 D, CB, A, G, F, ED, C, B, A, GF, E, D, C, // 400
73 ];
74
75 static YEAR_DELTAS: [u8; 401] = [
76 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8,
77 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14,
78 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20,
79 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, // 100
80 25, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30,
81 30, 31, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, 36, 36, 36,
82 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42,
83 42, 43, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 48, 48, 48,
84 48, 49, 49, 49, // 200
85 49, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54,
86 54, 55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60,
87 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63, 64, 64, 64, 64, 65, 65, 65, 65, 66, 66, 66,
88 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 69, 69, 69, 70, 70, 70, 70, 71, 71, 71, 71, 72, 72, 72,
89 72, 73, 73, 73, // 300
90 73, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 77, 78, 78, 78,
91 78, 79, 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 82, 82, 82, 82, 83, 83, 83, 83, 84, 84, 84,
92 84, 85, 85, 85, 85, 86, 86, 86, 86, 87, 87, 87, 87, 88, 88, 88, 88, 89, 89, 89, 89, 90, 90, 90,
93 90, 91, 91, 91, 91, 92, 92, 92, 92, 93, 93, 93, 93, 94, 94, 94, 94, 95, 95, 95, 95, 96, 96, 96,
94 96, 97, 97, 97, 97, // 400+1
95 ];
96
cycle_to_yo(cycle: u32) -> (u32, u32)97 pub fn cycle_to_yo(cycle: u32) -> (u32, u32) {
98 let (mut year_mod_400, mut ordinal0) = div_rem(cycle, 365);
99 let delta = u32::from(YEAR_DELTAS[year_mod_400 as usize]);
100 if ordinal0 < delta {
101 year_mod_400 -= 1;
102 ordinal0 += 365 - u32::from(YEAR_DELTAS[year_mod_400 as usize]);
103 } else {
104 ordinal0 -= delta;
105 }
106 (year_mod_400, ordinal0 + 1)
107 }
108
yo_to_cycle(year_mod_400: u32, ordinal: u32) -> u32109 pub fn yo_to_cycle(year_mod_400: u32, ordinal: u32) -> u32 {
110 year_mod_400 * 365 + u32::from(YEAR_DELTAS[year_mod_400 as usize]) + ordinal - 1
111 }
112
113 impl YearFlags {
114 #[inline]
from_year(year: i32) -> YearFlags115 pub fn from_year(year: i32) -> YearFlags {
116 let year = mod_floor(year, 400);
117 YearFlags::from_year_mod_400(year)
118 }
119
120 #[inline]
from_year_mod_400(year: i32) -> YearFlags121 pub fn from_year_mod_400(year: i32) -> YearFlags {
122 YEAR_TO_FLAGS[year as usize]
123 }
124
125 #[inline]
ndays(&self) -> u32126 pub fn ndays(&self) -> u32 {
127 let YearFlags(flags) = *self;
128 366 - u32::from(flags >> 3)
129 }
130
131 #[inline]
isoweek_delta(&self) -> u32132 pub fn isoweek_delta(&self) -> u32 {
133 let YearFlags(flags) = *self;
134 let mut delta = u32::from(flags) & 0b0111;
135 if delta < 3 {
136 delta += 7;
137 }
138 delta
139 }
140
141 #[inline]
nisoweeks(&self) -> u32142 pub fn nisoweeks(&self) -> u32 {
143 let YearFlags(flags) = *self;
144 52 + ((0b0000_0100_0000_0110 >> flags as usize) & 1)
145 }
146 }
147
148 impl fmt::Debug for YearFlags {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result149 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
150 let YearFlags(flags) = *self;
151 match flags {
152 0o15 => "A".fmt(f),
153 0o05 => "AG".fmt(f),
154 0o14 => "B".fmt(f),
155 0o04 => "BA".fmt(f),
156 0o13 => "C".fmt(f),
157 0o03 => "CB".fmt(f),
158 0o12 => "D".fmt(f),
159 0o02 => "DC".fmt(f),
160 0o11 => "E".fmt(f),
161 0o01 => "ED".fmt(f),
162 0o10 => "F?".fmt(f),
163 0o00 => "FE?".fmt(f), // non-canonical
164 0o17 => "F".fmt(f),
165 0o07 => "FE".fmt(f),
166 0o16 => "G".fmt(f),
167 0o06 => "GF".fmt(f),
168 _ => write!(f, "YearFlags({})", flags),
169 }
170 }
171 }
172
173 pub const MIN_OL: u32 = 1 << 1;
174 pub const MAX_OL: u32 = 366 << 1; // larger than the non-leap last day `(365 << 1) | 1`
175 pub const MIN_MDL: u32 = (1 << 6) | (1 << 1);
176 pub const MAX_MDL: u32 = (12 << 6) | (31 << 1) | 1;
177
178 const XX: i8 = -128;
179 static MDL_TO_OL: [i8; MAX_MDL as usize + 1] = [
180 XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX,
181 XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX,
182 XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, // 0
183 XX, XX, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
184 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
185 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // 1
186 XX, XX, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
187 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
188 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, XX, XX, XX, XX, XX, // 2
189 XX, XX, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74,
190 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74,
191 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, // 3
192 XX, XX, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76,
193 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76,
194 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, XX, XX, // 4
195 XX, XX, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80,
196 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80,
197 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, // 5
198 XX, XX, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82,
199 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82,
200 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, XX, XX, // 6
201 XX, XX, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86,
202 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86,
203 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, // 7
204 XX, XX, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88,
205 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88,
206 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, // 8
207 XX, XX, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90,
208 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90,
209 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, XX, XX, // 9
210 XX, XX, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94,
211 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94,
212 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, // 10
213 XX, XX, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96,
214 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96,
215 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, XX, XX, // 11
216 XX, XX, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98,
217 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100,
218 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98,
219 100, // 12
220 ];
221
222 static OL_TO_MDL: [u8; MAX_OL as usize + 1] = [
223 0, 0, // 0
224 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
225 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
226 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // 1
227 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
228 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
229 66, 66, 66, 66, 66, 66, 66, 66, 66, // 2
230 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72,
231 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72,
232 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, // 3
233 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74,
234 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74,
235 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, // 4
236 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78,
237 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78,
238 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, // 5
239 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80,
240 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80,
241 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, // 6
242 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84,
243 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84,
244 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, // 7
245 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86,
246 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86,
247 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, // 8
248 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88,
249 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88,
250 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, // 9
251 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92,
252 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92,
253 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, // 10
254 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94,
255 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94,
256 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, // 11
257 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100,
258 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98,
259 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100, 98, 100,
260 98, // 12
261 ];
262
263 /// Ordinal (day of year) and year flags: `(ordinal << 4) | flags`.
264 ///
265 /// The whole bits except for the least 3 bits are referred as `Ol` (ordinal and leap flag),
266 /// which is an index to the `OL_TO_MDL` lookup table.
267 #[derive(PartialEq, PartialOrd, Copy, Clone)]
268 pub struct Of(pub u32);
269
270 impl Of {
271 #[inline]
clamp_ordinal(ordinal: u32) -> u32272 fn clamp_ordinal(ordinal: u32) -> u32 {
273 if ordinal > 366 {
274 0
275 } else {
276 ordinal
277 }
278 }
279
280 #[inline]
new(ordinal: u32, YearFlags(flags): YearFlags) -> Of281 pub fn new(ordinal: u32, YearFlags(flags): YearFlags) -> Of {
282 let ordinal = Of::clamp_ordinal(ordinal);
283 Of((ordinal << 4) | u32::from(flags))
284 }
285
286 #[inline]
from_mdf(Mdf(mdf): Mdf) -> Of287 pub fn from_mdf(Mdf(mdf): Mdf) -> Of {
288 let mdl = mdf >> 3;
289 match MDL_TO_OL.get(mdl as usize) {
290 Some(&v) => Of(mdf.wrapping_sub((i32::from(v) as u32 & 0x3ff) << 3)),
291 None => Of(0),
292 }
293 }
294
295 #[inline]
valid(&self) -> bool296 pub fn valid(&self) -> bool {
297 let Of(of) = *self;
298 let ol = of >> 3;
299 MIN_OL <= ol && ol <= MAX_OL
300 }
301
302 #[inline]
ordinal(&self) -> u32303 pub fn ordinal(&self) -> u32 {
304 let Of(of) = *self;
305 of >> 4
306 }
307
308 #[inline]
with_ordinal(&self, ordinal: u32) -> Of309 pub fn with_ordinal(&self, ordinal: u32) -> Of {
310 let ordinal = Of::clamp_ordinal(ordinal);
311 let Of(of) = *self;
312 Of((of & 0b1111) | (ordinal << 4))
313 }
314
315 #[inline]
flags(&self) -> YearFlags316 pub fn flags(&self) -> YearFlags {
317 let Of(of) = *self;
318 YearFlags((of & 0b1111) as u8)
319 }
320
321 #[inline]
with_flags(&self, YearFlags(flags): YearFlags) -> Of322 pub fn with_flags(&self, YearFlags(flags): YearFlags) -> Of {
323 let Of(of) = *self;
324 Of((of & !0b1111) | u32::from(flags))
325 }
326
327 #[inline]
weekday(&self) -> Weekday328 pub fn weekday(&self) -> Weekday {
329 let Of(of) = *self;
330 Weekday::from_u32(((of >> 4) + (of & 0b111)) % 7).unwrap()
331 }
332
333 #[inline]
isoweekdate_raw(&self) -> (u32, Weekday)334 pub fn isoweekdate_raw(&self) -> (u32, Weekday) {
335 // week ordinal = ordinal + delta
336 let Of(of) = *self;
337 let weekord = (of >> 4).wrapping_add(self.flags().isoweek_delta());
338 (weekord / 7, Weekday::from_u32(weekord % 7).unwrap())
339 }
340
341 #[inline]
to_mdf(&self) -> Mdf342 pub fn to_mdf(&self) -> Mdf {
343 Mdf::from_of(*self)
344 }
345
346 #[inline]
succ(&self) -> Of347 pub fn succ(&self) -> Of {
348 let Of(of) = *self;
349 Of(of + (1 << 4))
350 }
351
352 #[inline]
pred(&self) -> Of353 pub fn pred(&self) -> Of {
354 let Of(of) = *self;
355 Of(of - (1 << 4))
356 }
357 }
358
359 impl fmt::Debug for Of {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result360 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
361 let Of(of) = *self;
362 write!(
363 f,
364 "Of(({} << 4) | {:#04o} /*{:?}*/)",
365 of >> 4,
366 of & 0b1111,
367 YearFlags((of & 0b1111) as u8)
368 )
369 }
370 }
371
372 /// Month, day of month and year flags: `(month << 9) | (day << 4) | flags`
373 ///
374 /// The whole bits except for the least 3 bits are referred as `Mdl`
375 /// (month, day of month and leap flag),
376 /// which is an index to the `MDL_TO_OL` lookup table.
377 #[derive(PartialEq, PartialOrd, Copy, Clone)]
378 pub struct Mdf(pub u32);
379
380 impl Mdf {
381 #[inline]
clamp_month(month: u32) -> u32382 fn clamp_month(month: u32) -> u32 {
383 if month > 12 {
384 0
385 } else {
386 month
387 }
388 }
389
390 #[inline]
clamp_day(day: u32) -> u32391 fn clamp_day(day: u32) -> u32 {
392 if day > 31 {
393 0
394 } else {
395 day
396 }
397 }
398
399 #[inline]
new(month: u32, day: u32, YearFlags(flags): YearFlags) -> Mdf400 pub fn new(month: u32, day: u32, YearFlags(flags): YearFlags) -> Mdf {
401 let month = Mdf::clamp_month(month);
402 let day = Mdf::clamp_day(day);
403 Mdf((month << 9) | (day << 4) | u32::from(flags))
404 }
405
406 #[inline]
from_of(Of(of): Of) -> Mdf407 pub fn from_of(Of(of): Of) -> Mdf {
408 let ol = of >> 3;
409 match OL_TO_MDL.get(ol as usize) {
410 Some(&v) => Mdf(of + (u32::from(v) << 3)),
411 None => Mdf(0),
412 }
413 }
414
415 #[inline]
valid(&self) -> bool416 pub fn valid(&self) -> bool {
417 let Mdf(mdf) = *self;
418 let mdl = mdf >> 3;
419 match MDL_TO_OL.get(mdl as usize) {
420 Some(&v) => v >= 0,
421 None => false,
422 }
423 }
424
425 #[inline]
month(&self) -> u32426 pub fn month(&self) -> u32 {
427 let Mdf(mdf) = *self;
428 mdf >> 9
429 }
430
431 #[inline]
with_month(&self, month: u32) -> Mdf432 pub fn with_month(&self, month: u32) -> Mdf {
433 let month = Mdf::clamp_month(month);
434 let Mdf(mdf) = *self;
435 Mdf((mdf & 0b1_1111_1111) | (month << 9))
436 }
437
438 #[inline]
day(&self) -> u32439 pub fn day(&self) -> u32 {
440 let Mdf(mdf) = *self;
441 (mdf >> 4) & 0b1_1111
442 }
443
444 #[inline]
with_day(&self, day: u32) -> Mdf445 pub fn with_day(&self, day: u32) -> Mdf {
446 let day = Mdf::clamp_day(day);
447 let Mdf(mdf) = *self;
448 Mdf((mdf & !0b1_1111_0000) | (day << 4))
449 }
450
451 #[inline]
flags(&self) -> YearFlags452 pub fn flags(&self) -> YearFlags {
453 let Mdf(mdf) = *self;
454 YearFlags((mdf & 0b1111) as u8)
455 }
456
457 #[inline]
with_flags(&self, YearFlags(flags): YearFlags) -> Mdf458 pub fn with_flags(&self, YearFlags(flags): YearFlags) -> Mdf {
459 let Mdf(mdf) = *self;
460 Mdf((mdf & !0b1111) | u32::from(flags))
461 }
462
463 #[inline]
to_of(&self) -> Of464 pub fn to_of(&self) -> Of {
465 Of::from_mdf(*self)
466 }
467 }
468
469 impl fmt::Debug for Mdf {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result470 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
471 let Mdf(mdf) = *self;
472 write!(
473 f,
474 "Mdf(({} << 9) | ({} << 4) | {:#04o} /*{:?}*/)",
475 mdf >> 9,
476 (mdf >> 4) & 0b1_1111,
477 mdf & 0b1111,
478 YearFlags((mdf & 0b1111) as u8)
479 )
480 }
481 }
482
483 #[cfg(test)]
484 mod tests {
485 #[cfg(test)]
486 extern crate num_iter;
487
488 use self::num_iter::range_inclusive;
489 use super::{Mdf, Of};
490 use super::{YearFlags, A, AG, B, BA, C, CB, D, DC, E, ED, F, FE, G, GF};
491 use std::u32;
492 use Weekday;
493
494 const NONLEAP_FLAGS: [YearFlags; 7] = [A, B, C, D, E, F, G];
495 const LEAP_FLAGS: [YearFlags; 7] = [AG, BA, CB, DC, ED, FE, GF];
496 const FLAGS: [YearFlags; 14] = [A, B, C, D, E, F, G, AG, BA, CB, DC, ED, FE, GF];
497
498 #[test]
test_year_flags_ndays_from_year()499 fn test_year_flags_ndays_from_year() {
500 assert_eq!(YearFlags::from_year(2014).ndays(), 365);
501 assert_eq!(YearFlags::from_year(2012).ndays(), 366);
502 assert_eq!(YearFlags::from_year(2000).ndays(), 366);
503 assert_eq!(YearFlags::from_year(1900).ndays(), 365);
504 assert_eq!(YearFlags::from_year(1600).ndays(), 366);
505 assert_eq!(YearFlags::from_year(1).ndays(), 365);
506 assert_eq!(YearFlags::from_year(0).ndays(), 366); // 1 BCE (proleptic Gregorian)
507 assert_eq!(YearFlags::from_year(-1).ndays(), 365); // 2 BCE
508 assert_eq!(YearFlags::from_year(-4).ndays(), 366); // 5 BCE
509 assert_eq!(YearFlags::from_year(-99).ndays(), 365); // 100 BCE
510 assert_eq!(YearFlags::from_year(-100).ndays(), 365); // 101 BCE
511 assert_eq!(YearFlags::from_year(-399).ndays(), 365); // 400 BCE
512 assert_eq!(YearFlags::from_year(-400).ndays(), 366); // 401 BCE
513 }
514
515 #[test]
test_year_flags_nisoweeks()516 fn test_year_flags_nisoweeks() {
517 assert_eq!(A.nisoweeks(), 52);
518 assert_eq!(B.nisoweeks(), 52);
519 assert_eq!(C.nisoweeks(), 52);
520 assert_eq!(D.nisoweeks(), 53);
521 assert_eq!(E.nisoweeks(), 52);
522 assert_eq!(F.nisoweeks(), 52);
523 assert_eq!(G.nisoweeks(), 52);
524 assert_eq!(AG.nisoweeks(), 52);
525 assert_eq!(BA.nisoweeks(), 52);
526 assert_eq!(CB.nisoweeks(), 52);
527 assert_eq!(DC.nisoweeks(), 53);
528 assert_eq!(ED.nisoweeks(), 53);
529 assert_eq!(FE.nisoweeks(), 52);
530 assert_eq!(GF.nisoweeks(), 52);
531 }
532
533 #[test]
test_of()534 fn test_of() {
535 fn check(expected: bool, flags: YearFlags, ordinal1: u32, ordinal2: u32) {
536 for ordinal in range_inclusive(ordinal1, ordinal2) {
537 let of = Of::new(ordinal, flags);
538 assert!(
539 of.valid() == expected,
540 "ordinal {} = {:?} should be {} for dominical year {:?}",
541 ordinal,
542 of,
543 if expected { "valid" } else { "invalid" },
544 flags
545 );
546 }
547 }
548
549 for &flags in NONLEAP_FLAGS.iter() {
550 check(false, flags, 0, 0);
551 check(true, flags, 1, 365);
552 check(false, flags, 366, 1024);
553 check(false, flags, u32::MAX, u32::MAX);
554 }
555
556 for &flags in LEAP_FLAGS.iter() {
557 check(false, flags, 0, 0);
558 check(true, flags, 1, 366);
559 check(false, flags, 367, 1024);
560 check(false, flags, u32::MAX, u32::MAX);
561 }
562 }
563
564 #[test]
test_mdf_valid()565 fn test_mdf_valid() {
566 fn check(expected: bool, flags: YearFlags, month1: u32, day1: u32, month2: u32, day2: u32) {
567 for month in range_inclusive(month1, month2) {
568 for day in range_inclusive(day1, day2) {
569 let mdf = Mdf::new(month, day, flags);
570 assert!(
571 mdf.valid() == expected,
572 "month {} day {} = {:?} should be {} for dominical year {:?}",
573 month,
574 day,
575 mdf,
576 if expected { "valid" } else { "invalid" },
577 flags
578 );
579 }
580 }
581 }
582
583 for &flags in NONLEAP_FLAGS.iter() {
584 check(false, flags, 0, 0, 0, 1024);
585 check(false, flags, 0, 0, 16, 0);
586 check(true, flags, 1, 1, 1, 31);
587 check(false, flags, 1, 32, 1, 1024);
588 check(true, flags, 2, 1, 2, 28);
589 check(false, flags, 2, 29, 2, 1024);
590 check(true, flags, 3, 1, 3, 31);
591 check(false, flags, 3, 32, 3, 1024);
592 check(true, flags, 4, 1, 4, 30);
593 check(false, flags, 4, 31, 4, 1024);
594 check(true, flags, 5, 1, 5, 31);
595 check(false, flags, 5, 32, 5, 1024);
596 check(true, flags, 6, 1, 6, 30);
597 check(false, flags, 6, 31, 6, 1024);
598 check(true, flags, 7, 1, 7, 31);
599 check(false, flags, 7, 32, 7, 1024);
600 check(true, flags, 8, 1, 8, 31);
601 check(false, flags, 8, 32, 8, 1024);
602 check(true, flags, 9, 1, 9, 30);
603 check(false, flags, 9, 31, 9, 1024);
604 check(true, flags, 10, 1, 10, 31);
605 check(false, flags, 10, 32, 10, 1024);
606 check(true, flags, 11, 1, 11, 30);
607 check(false, flags, 11, 31, 11, 1024);
608 check(true, flags, 12, 1, 12, 31);
609 check(false, flags, 12, 32, 12, 1024);
610 check(false, flags, 13, 0, 16, 1024);
611 check(false, flags, u32::MAX, 0, u32::MAX, 1024);
612 check(false, flags, 0, u32::MAX, 16, u32::MAX);
613 check(false, flags, u32::MAX, u32::MAX, u32::MAX, u32::MAX);
614 }
615
616 for &flags in LEAP_FLAGS.iter() {
617 check(false, flags, 0, 0, 0, 1024);
618 check(false, flags, 0, 0, 16, 0);
619 check(true, flags, 1, 1, 1, 31);
620 check(false, flags, 1, 32, 1, 1024);
621 check(true, flags, 2, 1, 2, 29);
622 check(false, flags, 2, 30, 2, 1024);
623 check(true, flags, 3, 1, 3, 31);
624 check(false, flags, 3, 32, 3, 1024);
625 check(true, flags, 4, 1, 4, 30);
626 check(false, flags, 4, 31, 4, 1024);
627 check(true, flags, 5, 1, 5, 31);
628 check(false, flags, 5, 32, 5, 1024);
629 check(true, flags, 6, 1, 6, 30);
630 check(false, flags, 6, 31, 6, 1024);
631 check(true, flags, 7, 1, 7, 31);
632 check(false, flags, 7, 32, 7, 1024);
633 check(true, flags, 8, 1, 8, 31);
634 check(false, flags, 8, 32, 8, 1024);
635 check(true, flags, 9, 1, 9, 30);
636 check(false, flags, 9, 31, 9, 1024);
637 check(true, flags, 10, 1, 10, 31);
638 check(false, flags, 10, 32, 10, 1024);
639 check(true, flags, 11, 1, 11, 30);
640 check(false, flags, 11, 31, 11, 1024);
641 check(true, flags, 12, 1, 12, 31);
642 check(false, flags, 12, 32, 12, 1024);
643 check(false, flags, 13, 0, 16, 1024);
644 check(false, flags, u32::MAX, 0, u32::MAX, 1024);
645 check(false, flags, 0, u32::MAX, 16, u32::MAX);
646 check(false, flags, u32::MAX, u32::MAX, u32::MAX, u32::MAX);
647 }
648 }
649
650 #[test]
test_of_fields()651 fn test_of_fields() {
652 for &flags in FLAGS.iter() {
653 for ordinal in range_inclusive(1u32, 366) {
654 let of = Of::new(ordinal, flags);
655 if of.valid() {
656 assert_eq!(of.ordinal(), ordinal);
657 }
658 }
659 }
660 }
661
662 #[test]
test_of_with_fields()663 fn test_of_with_fields() {
664 fn check(flags: YearFlags, ordinal: u32) {
665 let of = Of::new(ordinal, flags);
666
667 for ordinal in range_inclusive(0u32, 1024) {
668 let of = of.with_ordinal(ordinal);
669 assert_eq!(of.valid(), Of::new(ordinal, flags).valid());
670 if of.valid() {
671 assert_eq!(of.ordinal(), ordinal);
672 }
673 }
674 }
675
676 for &flags in NONLEAP_FLAGS.iter() {
677 check(flags, 1);
678 check(flags, 365);
679 }
680 for &flags in LEAP_FLAGS.iter() {
681 check(flags, 1);
682 check(flags, 366);
683 }
684 }
685
686 #[test]
test_of_weekday()687 fn test_of_weekday() {
688 assert_eq!(Of::new(1, A).weekday(), Weekday::Sun);
689 assert_eq!(Of::new(1, B).weekday(), Weekday::Sat);
690 assert_eq!(Of::new(1, C).weekday(), Weekday::Fri);
691 assert_eq!(Of::new(1, D).weekday(), Weekday::Thu);
692 assert_eq!(Of::new(1, E).weekday(), Weekday::Wed);
693 assert_eq!(Of::new(1, F).weekday(), Weekday::Tue);
694 assert_eq!(Of::new(1, G).weekday(), Weekday::Mon);
695 assert_eq!(Of::new(1, AG).weekday(), Weekday::Sun);
696 assert_eq!(Of::new(1, BA).weekday(), Weekday::Sat);
697 assert_eq!(Of::new(1, CB).weekday(), Weekday::Fri);
698 assert_eq!(Of::new(1, DC).weekday(), Weekday::Thu);
699 assert_eq!(Of::new(1, ED).weekday(), Weekday::Wed);
700 assert_eq!(Of::new(1, FE).weekday(), Weekday::Tue);
701 assert_eq!(Of::new(1, GF).weekday(), Weekday::Mon);
702
703 for &flags in FLAGS.iter() {
704 let mut prev = Of::new(1, flags).weekday();
705 for ordinal in range_inclusive(2u32, flags.ndays()) {
706 let of = Of::new(ordinal, flags);
707 let expected = prev.succ();
708 assert_eq!(of.weekday(), expected);
709 prev = expected;
710 }
711 }
712 }
713
714 #[test]
test_mdf_fields()715 fn test_mdf_fields() {
716 for &flags in FLAGS.iter() {
717 for month in range_inclusive(1u32, 12) {
718 for day in range_inclusive(1u32, 31) {
719 let mdf = Mdf::new(month, day, flags);
720 if mdf.valid() {
721 assert_eq!(mdf.month(), month);
722 assert_eq!(mdf.day(), day);
723 }
724 }
725 }
726 }
727 }
728
729 #[test]
test_mdf_with_fields()730 fn test_mdf_with_fields() {
731 fn check(flags: YearFlags, month: u32, day: u32) {
732 let mdf = Mdf::new(month, day, flags);
733
734 for month in range_inclusive(0u32, 16) {
735 let mdf = mdf.with_month(month);
736 assert_eq!(mdf.valid(), Mdf::new(month, day, flags).valid());
737 if mdf.valid() {
738 assert_eq!(mdf.month(), month);
739 assert_eq!(mdf.day(), day);
740 }
741 }
742
743 for day in range_inclusive(0u32, 1024) {
744 let mdf = mdf.with_day(day);
745 assert_eq!(mdf.valid(), Mdf::new(month, day, flags).valid());
746 if mdf.valid() {
747 assert_eq!(mdf.month(), month);
748 assert_eq!(mdf.day(), day);
749 }
750 }
751 }
752
753 for &flags in NONLEAP_FLAGS.iter() {
754 check(flags, 1, 1);
755 check(flags, 1, 31);
756 check(flags, 2, 1);
757 check(flags, 2, 28);
758 check(flags, 2, 29);
759 check(flags, 12, 31);
760 }
761 for &flags in LEAP_FLAGS.iter() {
762 check(flags, 1, 1);
763 check(flags, 1, 31);
764 check(flags, 2, 1);
765 check(flags, 2, 29);
766 check(flags, 2, 30);
767 check(flags, 12, 31);
768 }
769 }
770
771 #[test]
test_of_isoweekdate_raw()772 fn test_of_isoweekdate_raw() {
773 for &flags in FLAGS.iter() {
774 // January 4 should be in the first week
775 let (week, _) = Of::new(4 /* January 4 */, flags).isoweekdate_raw();
776 assert_eq!(week, 1);
777 }
778 }
779
780 #[test]
test_of_to_mdf()781 fn test_of_to_mdf() {
782 for i in range_inclusive(0u32, 8192) {
783 let of = Of(i);
784 assert_eq!(of.valid(), of.to_mdf().valid());
785 }
786 }
787
788 #[test]
test_mdf_to_of()789 fn test_mdf_to_of() {
790 for i in range_inclusive(0u32, 8192) {
791 let mdf = Mdf(i);
792 assert_eq!(mdf.valid(), mdf.to_of().valid());
793 }
794 }
795
796 #[test]
test_of_to_mdf_to_of()797 fn test_of_to_mdf_to_of() {
798 for i in range_inclusive(0u32, 8192) {
799 let of = Of(i);
800 if of.valid() {
801 assert_eq!(of, of.to_mdf().to_of());
802 }
803 }
804 }
805
806 #[test]
test_mdf_to_of_to_mdf()807 fn test_mdf_to_of_to_mdf() {
808 for i in range_inclusive(0u32, 8192) {
809 let mdf = Mdf(i);
810 if mdf.valid() {
811 assert_eq!(mdf, mdf.to_of().to_mdf());
812 }
813 }
814 }
815 }
816