1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
//! Proleptic Gregorian calendar date and leap year calculations.
//!
//! Provides conversion between civil dates (`year`, `month`, `day`) and total days
//! elapsed since the Unix epoch (`1970-01-01`), accounting for 400-year leap cycles.
//!
//! # Arithmetic domain
//!
//! The conversions are Howard Hinnant's `days_from_civil` / `civil_from_days`
//! pair, which is exact over the entire proleptic Gregorian calendar. Every
//! step below is written with `checked_*`, `saturating_*` or `div_euclid`
//! rather than the bare operators, because this workspace forbids
//! `clippy::arithmetic_side_effects`; the comment at each site names the bound
//! that makes the choice exact rather than merely non-panicking.
//!
//! The domain the rest of the crate exercises is the four-digit RFC 3339 year
//! `0..=9999` enforced by [`super::parse`], where no intermediate comes within
//! twelve orders of magnitude of an `i64` bound. The wider `i64` domain is
//! still total: [`civil_from_days`] is exact for every `i64` day count, and
//! [`days_from_civil`] saturates only past ±2.5e16 years.
/// Days in one 400-year Gregorian era: `365 * 400 + 97` leap days.
const DAYS_PER_ERA: i64 = 146_097;
/// Days from `1970-01-01` back to the start of era 0 (`0000-03-01`), the
/// epoch the era decomposition below is written against.
const EPOCH_ERA_OFFSET: i64 = 719_468;
/// Whole 400-year eras inside [`EPOCH_ERA_OFFSET`]: `4 * 146_097 = 584_388`.
const EPOCH_WHOLE_ERAS: i64 = 4;
/// Days left over after [`EPOCH_WHOLE_ERAS`]: `719_468 - 584_388 = 135_080`.
const EPOCH_ERA_REMAINDER: i64 = 135_080;
/// Truncating integer division that cannot trap.
///
/// `clippy::integer_division` forbids the bare `/` operator, and every call
/// site divides by a non-zero constant, so the `None` arm of `checked_div` is
/// unreachable and exists only to keep the function total.
/// Determines whether the given astronomical year index is a leap year (366 days).
///
/// `year` is an astronomical year index: year `0` is 1 BCE, and negative values
/// run backwards from there. The rule is the Gregorian one: every fourth year
/// is a leap year except century years, which are leap years only when
/// divisible by 400. It holds for negative years too, because `%` here is
/// only ever compared against zero, where truncation and flooring agree.
/// Returns the number of days in the specified month (1..=12) for a given year.
///
/// Returns [`None`] when `month` is outside `1..=12`, so an out-of-range month
/// is a value the caller must handle rather than a panic inside the library.
/// Use this in preference to [`days_in_month`] whenever the month has not
/// already been range-checked.
/// Returns the number of days in the specified month (1..=12) for a given year,
/// or `0` when `month` is outside `1..=12`.
///
/// `0` is a sentinel, not a month length: a caller that uses the result as an
/// inclusive upper bound for a day of month fails closed, because no day can
/// satisfy `1..=0`. Callers that need to distinguish "empty month" from
/// "invalid month" should use [`try_days_in_month`] instead.
/// Splits a civil year into a 400-year era index and a `0..=399` year within
/// that era.
///
/// January and February are counted as the tail of the *previous* era year: the
/// calendar is re-based onto a March-start year so that February (the month
/// whose length is the only one that varies) sits at the end of the cycle,
/// where a single linear day-of-year formula can absorb it.
///
/// `div_euclid` floors toward negative infinity, which is the era boundary the
/// algorithm needs for years before era 0; `saturating_mul(400)` cannot
/// saturate because `|era * 400| <= |adjusted_year| + 399`.
/// Days since 1970-01-01 for a proleptic Gregorian date.
///
/// `month` must be in `1..=12` and `day` a valid day of that month; the RFC
/// 3339 parser enforces both before calling, and every caller in this module
/// passes a day in `1..=31`. Under those preconditions the result is exact for
/// any representable civil date, i.e. for `|year|` up to about 2.5e16.
///
/// # Saturation
///
/// `era * 146_097` is the only step that can leave `i64`, and it does so only
/// once the day count itself is out of range: it saturates for `|year|` beyond
/// roughly 2.5e16 (±25 quadrillion years), and the result is then clamped to
/// `i64::MAX` or `i64::MIN` on the same side as `year`, because the day count
/// is strictly increasing in `year` (a year is 365 or 366 days). The clamp is
/// exact to within the final `719_468`-day epoch shift; no RFC 3339 stamp and
/// no `SystemTime` an operating system can produce comes within fifteen orders
/// of magnitude of the boundary.
/// Splits days-since-1970-01-01 into a 400-year era index and a `0..146_097`
/// day offset within that era.
///
/// This is the remainder-and-quotient of `days + 719_468` by `146_097`, but it
/// never forms that sum: `days + 719_468` overflows `i64` for the top ~1_970
/// years of the `i64` range, whereas the re-based form below stays inside it
/// for every input.
///
/// `719_468 = 4 * 146_097 + 135_080`, so the epoch sits four whole eras plus
/// `135_080` days into the cycle. Re-basing onto that boundary can carry at
/// most once, because `146_096 + 135_080 < 2 * 146_097`.
/// Converts an era index and a `0..146_097` day offset within it into a
/// March-based year and the `0..=365` day of that year.
///
/// `day_of_era` is bounded by `146_096`, which is what keeps every intermediate
/// here small: the year-of-era correction is `0..=399`, `era * 400` is a civil
/// year, and `365 * year_of_era` is at most `145_635`. Every division is
/// truncating on a non-negative numerator, matching `/` for the operands the
/// algorithm can supply.
/// Converts a March-based year and its `0..=365` day into a civil
/// `(year, month, day)`.
///
/// Returns `i64` components rather than the public `u32` ones so that the
/// narrowing happens once, at the public boundary, where the range is known.
/// `day_of_year` is `0..=365`, so `month_prime` is `0..=12`, the day of month
/// is `1..=31`, and the month is `1..=12`.
/// The proleptic Gregorian date for a count of days since 1970-01-01.
///
/// The inverse of [`days_from_civil`]. Exact for every `i64` day count: the
/// re-basing in `shifted_to_era` avoids the one addition that could overflow,
/// and `146_097` is what bounds every remaining intermediate, so the reported
/// year stays inside `i64` even when the day count is at its extreme.
///
/// `shifted_to_era` is named rather than linked because it is private: a public
/// item's docs cannot reach a private one without `--document-private-items`,
/// and `rustdoc::private_intra_doc_links` is denied here.