time_compute 1.0.0

Dependency-free date/time computation library, with an API closely mirroring chrono
Documentation
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
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
# `time_compute` API Reference

This document is an exhaustive, function-by-function reference of `time_compute`'s public API. It explains what each item does and why it exists, without usage examples (see `docs/Use_Example.md` for worked examples, and the crate's rustdoc/doctests for runnable code).

The reference is split in two parts, matching the crate's own design split (see `docs/Architecture.md`):

- **Part 1** covers the API that mirrors `chrono` 1:1 -- same names, same signatures, same behavior, organized by type/module.
- **Part 2** covers the `time_compute`-only extensions: everything with no `chrono` equivalent, each marked in the source with a `# time_compute extension -- not part of chrono` comment.

Deprecated methods (kept only for API parity with older `chrono` releases, each pointing to its non-deprecated replacement) are listed alongside their replacement rather than in a separate section, since that is how a reader will actually encounter them.

---

# Part 1 -- The chrono-compatible API

## 1. `NaiveDate`

A date in the proleptic Gregorian calendar (year, month, day) with no time-of-day or time zone. Internally a `(year: i32, month: u32, day: u32)` triple; all arithmetic routes through `calendar.rs`'s civil-date/day-count conversion.

**Constants**

- `MIN` / `MAX` -- the smallest and largest representable dates. The accepted year range is `-5,000,000..=5,000,000`, deliberately far wider than chrono's own (chrono tops out around +/-262,000/-400,000 years depending on the exact date); every date chrono accepts is accepted here, plus some extreme dates chrono would reject.
- `MIN_DATE` / `MAX_DATE` -- deprecated aliases of `MIN`/`MAX`.

**Constructors** (each has a panicking form, deprecated in favor of the `_opt` form, and a non-panicking `_opt` form returning `Option<NaiveDate>`)

- `from_ymd_opt(year, month, day)` / `from_ymd` (deprecated) -- from year, month (1-12), day of month. `None`/panics on an invalid or non-existent calendar day (bad month, day out of range, February 29 in a non-leap year, year out of bounds).
- `from_yo_opt(year, ordinal)` / `from_yo` (deprecated) -- from year and day-of-year (1-365 or 366).
- `from_isoywd_opt(iso_year, week, weekday)` / `from_isoywd` (deprecated) -- from an ISO 8601 year, week number (1-53) and weekday. Fails if the combination doesn't correspond to a real date (e.g. week 53 in a year with only 52).
- `from_num_days_from_ce_opt(days)` / `from_num_days_from_ce` (deprecated) -- from the day count since the proleptic 0001-01-01 (day 1 = 0001-01-01).
- `from_epoch_days(days)` -- from the day count since the Unix epoch (1970-01-01 = day 0). Returns `None` if out of range.
- `from_weekday_of_month_opt(year, month, weekday, n)` / `from_weekday_of_month` (deprecated) -- the `n`-th (1-indexed) occurrence of `weekday` in the given month, e.g. the 2nd Friday of March.

**Basic accessors and day-count conversions**

- `to_epoch_days()` -- day count since the Unix epoch.
- `num_days_from_ce()` -- day count since the proleptic 0001-01-01 (also available as `Datelike::num_days_from_ce`, a default trait method with the same formula).
- `leap_year()` -- whether this date's year is a leap year.
- `weeks_from(day)` *(crate-private)* -- internal helper backing the `%U`/`%W` format specifiers.

**Successor/predecessor and day/duration arithmetic**

- `succ_opt()` / `succ` (deprecated) -- the next day, `None`/panics at `MAX`.
- `pred_opt()` / `pred` (deprecated) -- the previous day, `None`/panics at `MIN`.
- `checked_add_days(Days)` / `checked_sub_days(Days)` -- add/subtract a whole number of days, `None` on overflow of the representable range.
- `checked_add_months(Months)` / `checked_sub_months(Months)` -- add/subtract whole months; if the original day of the month doesn't exist in the resulting month (e.g. January 31 + 1 month), clamps to that month's last valid day rather than failing.
- `checked_add_signed(Duration)` / `checked_sub_signed(Duration)` -- add/subtract a signed `Duration`/`TimeDelta`, truncated to a whole number of days.
- `signed_duration_since(other)` -- signed `Duration` between two dates (`self - other`), in whole days.
- `abs_diff(rhs)` -- unsigned `Days` between two dates regardless of order.
- `years_since(base)` -- whole years elapsed from `base` to `self` (anniversary-aware), `None` if `self` is before `base`.
- Operators: `Add<Duration>`, `Sub<Duration>`, `AddAssign`/`SubAssign` (panic on overflow -- use the `checked_*` methods for a non-panicking version); `Add<Months>`/`Sub<Months>`; `Add<Days>`/`Sub<Days>`; `Sub<NaiveDate> -> Duration`.

**`Datelike` trait implementation** -- `year`, `month`, `month0`, `day`, `day0`, `ordinal`, `ordinal0`, `weekday`, `iso_week`, and the `with_year`/`with_month`/`with_month0`/`with_day`/`with_day0`/`with_ordinal`/`with_ordinal0` mutators (each returns `Option<NaiveDate>`, `None` if the resulting date would not exist). See section 8 for the trait's own default methods (`year_ce`, `quarter`, `num_days_from_ce`, `num_days_in_month`).

**Combining with a time of day**

- `and_time(NaiveTime)` -- combines with a `NaiveTime` into a `NaiveDateTime`.
- `and_hms_opt` / `and_hms` (deprecated), `and_hms_milli_opt` / `and_hms_milli` (deprecated), `and_hms_micro_opt` / `and_hms_micro` (deprecated), `and_hms_nano_opt` / `and_hms_nano` (deprecated) -- convenience constructors combining this date with an hour/minute/second (optionally with milli-/micro-/nanosecond precision, which may exceed the normal range to represent a leap second).

**Iteration and week**

- `iter_days()` -- an iterator over `NaiveDate`, stepping one day at a time up to and including `MAX` (`NaiveDateDaysIterator`, see section 5).
- `iter_weeks()` -- same, stepping 7 days at a time (`NaiveDateWeeksIterator`).
- `week(start: Weekday)` -- the `NaiveWeek` (section 4) that this date belongs to, anchored on a chosen starting weekday.

**Parsing and formatting**

- `parse_from_str(s, fmt)` -- parses a `NaiveDate` from a string using a `strftime`-style format (section 13).
- `parse_and_remainder(s, fmt)` -- same, also returning the unparsed remainder of the string.
- `format(fmt)` / `format_with_items(items)` -- returns a `DelayedFormat` (section 13), converted to a string only when actually displayed.
- `format_localized(fmt, locale)` / `format_localized_with_items(items, locale)` -- locale-aware variants, gated behind the `unstable-locales` feature.

**Trait implementations** -- `Display`/`Debug` (`YYYY-MM-DD`, with a `+`/`-` sign and no fixed width for years outside `0..=9999`), `Default` (1970-01-01), `FromStr` (parses `%Y-%m-%d`), `Clone`/`Copy`/`PartialEq`/`Eq`/`PartialOrd`/`Ord`/`Hash`; `serde` (as an ISO 8601 string, feature-gated); `rkyv` (as `ArchivedNaiveDate`, feature-gated); `arbitrary` (feature-gated, for fuzzing); `defmt::Format` (feature-gated).

### 1.1 `IsoWeek`

A week in the ISO 8601 calendar (ISO year + week number), returned by `Datelike::iso_week()`. The ISO year can differ from the plain calendar year for the handful of days at the very start/end of a year that belong to a week counted under the adjacent year.

- `year()` -- the ISO 8601 year.
- `week()` -- the week number, 1 to 52 or 53.
- `week0()` -- the week number, 0-indexed.
- `Display` -- prints as `YYYY-Www`.
- `Clone`/`Copy`/`PartialEq`/`Eq`/`PartialOrd`/`Ord`/`Hash`/`Debug`; `rkyv`/`defmt` support (feature-gated). No `serde` impl, matching chrono (which has none for `IsoWeek` either).

## 2. `NaiveTime`

A time of day (hour, minute, second, nanosecond) with no associated date or time zone. Internally `(secs: u32` since midnight in `0..86_400`, `frac: u32` nanoseconds in `0..1_000_000_000`, or `1_000_000_000..2_000_000_000` to represent a leap second`)`.

**Constants** -- `MIN` (midnight, the earliest representable time).

**Constructors** (each with a deprecated panicking form and a non-panicking `_opt` form)

- `from_hms_opt` / `from_hms` (deprecated) -- from hour/minute/second (no leap second representable this way).
- `from_hms_milli_opt` / `from_hms_milli` (deprecated) -- with a millisecond component (may exceed 1,000 for a leap second, only when `sec == 59`).
- `from_hms_micro_opt` / `from_hms_micro` (deprecated) -- with a microsecond component (same leap-second allowance).
- `from_hms_nano_opt` / `from_hms_nano` (deprecated) -- with a nanosecond component (may go up to 1,999,999,999 for a leap second).
- `from_num_seconds_from_midnight_opt` / `from_num_seconds_from_midnight` (deprecated) -- from the number of seconds since midnight plus a nanosecond remainder.

**Arithmetic**

- `overflowing_add_signed(Duration)` / `overflowing_sub_signed(Duration)` -- add/subtract a signed duration, wrapping around a single day; also returns the signed number of seconds carried into/out of the day (0 if no day boundary was crossed), so a caller can apply that carry to an accompanying date. Never fails.
- `signed_duration_since(rhs)` -- signed duration between two times (`self - rhs`), always within +/-1 day.
- Operators: `Add`/`Sub<Duration>`, `AddAssign`/`SubAssign<Duration>`; `Add`/`Sub<core::time::Duration>` (wraps, like the signed operators); `Sub<NaiveTime> -> Duration`; `Add`/`Sub<FixedOffset>` (wraps around a day, used internally when combining a time with an offset).

**`Timelike` trait implementation** -- `hour`, `minute`, `second` (never reports 60 even for a leap second -- inspect `nanosecond()` or formatting to see it), `nanosecond`, and the `with_hour`/`with_minute`/`with_second`/`with_nanosecond` mutators. See section 8 for the trait's default methods (`hour12`, `num_seconds_from_midnight`).

**Parsing and formatting**

- `parse_from_str(s, fmt)` / `parse_and_remainder(s, fmt)` -- as for `NaiveDate`.
- `format(fmt)` / `format_with_items(items)` -- as for `NaiveDate` (no `format_localized` variant -- a bare time of day has no locale-dependent representation beyond what the date-aware types already cover).

**Trait implementations** -- `Debug`/`Display` (`HH:MM:SS[.fraction]`, a leap second prints as second `60`), `Default` (midnight), `FromStr` (parses `%H:%M:%S%.f` with seconds and the fractional part optional), the usual `Clone`/`Copy`/`PartialEq`/`Eq`/`PartialOrd`/`Ord`/`Hash`; `serde`/`rkyv`/`arbitrary`/`defmt` support (feature-gated), same pattern as `NaiveDate`.

## 3. `NaiveDateTime`

A date and time of day combined, still without an associated time zone. Internally a `(NaiveDate, NaiveTime)` pair.

**Constants** -- `MIN` / `MAX`; `UNIX_EPOCH` (deprecated, use `DateTime::UNIX_EPOCH` instead); `MIN_DATETIME` / `MAX_DATETIME` (deprecated aliases of `MIN`/`MAX`).

**Construction and components**

- `new(date, time)` -- combines a `NaiveDate` and `NaiveTime` (equivalent to `date.and_time(time)`).
- `date()` / `time()` -- the date/time-of-day components.

**Unix-timestamp interop (all deprecated in favor of the `DateTime<Utc>`-based equivalents, since a naive value has no time zone to make a timestamp meaningful without an explicit UTC assumption)**

- `from_timestamp(secs, nsecs)` -- panics on out-of-range input; superseded by `DateTime::from_timestamp`.
- `timestamp()` -- non-leap seconds since the Unix epoch, assuming UTC.
- `from_timestamp_millis` / `timestamp_millis`, `from_timestamp_micros` / `timestamp_micros`, `from_timestamp_nanos` / `timestamp_nanos` / `timestamp_nanos_opt`, `from_timestamp_opt` -- millisecond/microsecond/nanosecond equivalents.
- `timestamp_subsec_millis` / `timestamp_subsec_micros` / `timestamp_subsec_nanos` -- the sub-second remainder.

**Arithmetic**

- `checked_add_signed(TimeDelta)` / `checked_sub_signed(TimeDelta)` -- add/subtract a signed duration, wrapping across day boundaries; `None` on overflow of the representable date range. Leap-second handling: assumes there is no leap second ever, except when `self` itself represents one.
- `checked_add_months(Months)` / `checked_sub_months(Months)` -- shifts the date part only (clamping the day of month as needed), time of day unchanged.
- `checked_add_days(Days)` / `checked_sub_days(Days)` -- shifts the date part by whole days.
- `signed_duration_since(rhs)` -- signed `TimeDelta` between two datetimes, never overflows.
- `checked_add_offset(FixedOffset)` / `checked_sub_offset(FixedOffset)` -- add/subtract a fixed UTC offset (used to convert between local and UTC readings), preserving any leap second (unlike `checked_add_signed`). `None` if the result would be out of `NaiveDateTime`'s range.
- Operators: `Add`/`Sub<TimeDelta>`, `Add`/`Sub<core::time::Duration>`, `AddAssign`/`SubAssign` for both; `Add<FixedOffset>`; `Add`/`Sub<Months>`; `Add`/`Sub<Days>`; `Sub<NaiveDateTime> -> TimeDelta`. All panic on overflow -- prefer the `checked_*` methods for a non-panicking version.
- `From<NaiveDate>` -- a date at midnight.

**Time zone attachment**

- `and_utc()` -- wraps into a `DateTime<Utc>`.
- `and_local_timezone(tz)` -- wraps into a `MappedLocalTime<DateTime<Tz>>` for an arbitrary `TimeZone` implementation.

**`Datelike`/`Timelike` trait implementations** -- delegate to the wrapped `NaiveDate`/`NaiveTime`.

**Parsing and formatting** -- `parse_from_str`, `parse_and_remainder`, `format`, `format_with_items`, as for `NaiveDate`/`NaiveTime` (parsing/formatting both the date and time parts together).

**Trait implementations** -- `Debug` (`YYYY-MM-DDTHH:MM:SS[.fraction]`), `Display` (same but with a space instead of `T`), `Default` (Unix epoch, no time zone), `FromStr` (parses `%Y-%m-%dT%H:%M:%S%.f`), the usual comparison/hash traits; `serde` (RFC 3339-ish string) and the `crate::naive::serde` submodule described in section 14; `rkyv`/`arbitrary`/`defmt` (feature-gated).

## 4. `NaiveWeek`

The calendar week a given `NaiveDate` belongs to, anchored on a chosen starting weekday. Obtained via `NaiveDate::week(start)`.

- `first_day()` / `checked_first_day()` -- the first day of the week (panics vs. returns `None` if that day would fall outside `NaiveDate`'s representable range).
- `last_day()` / `checked_last_day()` -- the last day of the week, same panic/`None` distinction.
- `days()` / `checked_days()` -- the full 7-day range as a `RangeInclusive<NaiveDate>`.
- `PartialEq`/`Eq`/`Hash` -- based on the week's first day, not the originating date used to look it up (two dates in the same week compare equal).

## 5. Iterators over `NaiveDate`

Created by `NaiveDate::iter_days()`/`iter_weeks()`.

- `NaiveDateDaysIterator` -- advances one day at a time. `Iterator`, `DoubleEndedIterator` (steps backward via `pred_opt`), `ExactSizeIterator`, `FusedIterator`. Note: an iterator whose current value is already `NaiveDate::MAX` yields nothing at all (not even `MAX` itself), a quirk inherited from the `?`-based short-circuit in `next()` and confirmed to mirror chrono's own iterator.
- `NaiveDateWeeksIterator` -- same, advancing 7 days at a time.

## 6. `DateTime<Tz>`

A date and time of day together with a time zone, generic over any `TimeZone` implementation (`Utc`, `FixedOffset`, or `Local`). Internally a `(NaiveDateTime` in UTC, `Tz::Offset)` pair.

**Constants** -- `DateTime::<Utc>::MIN_UTC` / `MAX_UTC`; `DateTime::<Utc>::UNIX_EPOCH`; `MIN_DATETIME` / `MAX_DATETIME` (deprecated aliases of `MIN_UTC`/`MAX_UTC`).

**Low-level construction** (prefer `TimeZone::from_local_datetime`/`with_ymd_and_hms`/`timestamp_opt` or `NaiveDateTime::and_local_timezone` for regular use)

- `from_naive_utc_and_offset(datetime, offset)` -- builds directly from a UTC `NaiveDateTime` and an offset.
- `from_utc(datetime, offset)` (deprecated) -- same, older name.
- `from_local(datetime, offset)` (deprecated) -- builds from a *local* `NaiveDateTime` and an offset; panics if converting to UTC overflows.

**`DateTime<Utc>`-specific constructors**

- `from_timestamp_secs(secs)` -- from a Unix timestamp in whole seconds.
- `from_timestamp(secs, nsecs)` -- from a Unix timestamp plus a nanosecond remainder (which may exceed 1,000,000,000 for a leap second, only when `secs % 60 == 59`).
- `from_timestamp_millis` / `from_timestamp_micros` -- millisecond/microsecond equivalents.
- `from_timestamp_nanos` -- nanosecond equivalent; never fails (an `i64` of nanoseconds always fits).

**`DateTime<FixedOffset>`-specific parsing**

- `parse_from_rfc2822(s)` -- parses an RFC 2822 date-and-time string (e.g. `Tue, 1 Jul 2003 10:52:37 +0200`).
- `parse_from_rfc3339(s)` -- parses an RFC 3339/ISO 8601 date-and-time string.
- `parse_from_str(s, fmt)` / `parse_and_remainder(s, fmt)` -- parses using a user format string; unlike `NaiveDateTime::parse_from_str`, this *requires* a time zone in the input.

**Components and timestamps**

- `date_naive()` -- the local date component (panics if the offset pushes it outside `NaiveDate`'s range).
- `time()` -- the local time-of-day component.
- `timestamp()` -- non-leap seconds since the Unix epoch.
- `timestamp_millis()` / `timestamp_micros()` -- millisecond/microsecond equivalents.
- `timestamp_nanos()` (deprecated, panics beyond the ~584-year range an `i64` of nanoseconds can span) / `timestamp_nanos_opt()` -- nanosecond equivalent.
- `timestamp_subsec_millis()` / `timestamp_subsec_micros()` / `timestamp_subsec_nanos()` -- the sub-second remainder.
- `offset()` -- the offset from UTC in effect at this instant.
- `timezone()` -- reconstructs the associated `TimeZone` value from the stored offset.

**Conversions**

- `with_timezone(&tz)` -- changes the associated time zone, preserving the instant (not the wall-clock reading).
- `fixed_offset()` -- drops the generic time zone in favor of a plain `FixedOffset`, keeping the current offset.
- `to_utc()` -- converts to `DateTime<Utc>`, dropping the offset/time zone.
- `naive_utc()` -- a view of the underlying UTC `NaiveDateTime` (no offset applied).
- `naive_local()` -- a view with the offset applied (panics if that pushes the value outside `NaiveDateTime`'s range).

**Arithmetic**

- `checked_add_signed(TimeDelta)` / `checked_sub_signed(TimeDelta)` -- `None` on overflow.
- `checked_add_months(Months)` / `checked_sub_months(Months)` -- clamps to the last valid day of the resulting month; `None` if the resulting date is out of range or the local time at that date does not exist or is ambiguous (a DST transition).
- `checked_add_days(Days)` / `checked_sub_days(Days)` -- same ambiguity/range caveats as the month variants.
- `signed_duration_since(rhs)` -- signed `TimeDelta` since another `DateTime` (accepts by value or reference, even across different `Tz` types).
- `years_since(base)` -- whole years elapsed, anniversary-aware.
- `with_time(time)` -- replaces the time-of-day part, keeping the date; returns `MappedLocalTime::None` if that would push the value out of range.
- Operators: `Add`/`Sub<TimeDelta>`, `Add`/`Sub<core::time::Duration>`, `AddAssign`/`SubAssign` for both, `Add<FixedOffset>` (shifts the instant while the offset field is unchanged), `Add`/`Sub<Months>`, `Add`/`Sub<Days>`, `Sub<DateTime<Tz>> -> TimeDelta` (by value or by reference). All panic on overflow/ambiguity -- prefer the `checked_*` methods.

**`Datelike`/`Timelike` trait implementations** -- delegate to the local (offset-applied) reading; the `with_*` mutators return `None` (via `MappedLocalTime` collapsed to `Option`) when the resulting local time doesn't exist or is ambiguous, or falls outside the representable UTC range.

**Comparisons** -- `PartialEq`/`Eq` across any two `Tz`/`Tz2` (compares the underlying UTC instant, ignoring the time zone); `PartialOrd`/`Ord` likewise; `Hash`; `Copy` whenever `Tz::Offset: Copy` (`Tz` itself isn't stored).

**RFC-standard string output** (only when `Tz::Offset: Display`)

- `to_rfc2822()` -- e.g. `Tue, 1 Jul 2003 10:52:37 +0200`; panics if the year is outside 0..=9999 (RFC 2822's representable range).
- `to_rfc3339()` -- e.g. `1996-12-19T16:39:57-08:00`.
- `to_rfc3339_opts(secform, use_z)` -- like `to_rfc3339`, with explicit sub-second formatting (`SecondsFormat`, section 13) and an option to print `Z` instead of `+00:00` for UTC.

**Parsing and formatting** -- `format`, `format_with_items`, `format_localized`, `format_localized_with_items` (locale variants feature-gated), as for the naive types, plus the time zone's offset in the output.

**Interop and conversions**

- `From<std::time::SystemTime>` for `DateTime<Utc>`/`DateTime<Local>`; `From<DateTime<Tz>>` for `std::time::SystemTime`.
- `From<DateTime<Utc>>`/`From<DateTime<FixedOffset>>`/`From<DateTime<Local>>` for each of the other two time zones (six conversions total), all implemented via `with_timezone`.
- `Default` for `DateTime<Utc>`, `DateTime<Local>`, `DateTime<FixedOffset>` (Unix epoch, in each respective zone).
- `FromStr` for `DateTime<Utc>`/`DateTime<Local>` -- parses a relaxed RFC 3339 string (via the `DateTime<FixedOffset>` parser), then converts.
- `Debug`/`Display` (`Display` only when `Tz::Offset: Display`).

**`time_compute` extension living here** -- see Part 2, section 1 (`age`).

## 7. Time zones (`offset` module)

### 7.1 `TimeZone` trait

Computes the offset(s) between UTC and local time for a given zone; the primary way to construct `DateTime<Tz>` values.

- `type Offset: Offset` -- the associated offset type cached inside date/time values.
- `with_ymd_and_hms(year, month, day, hour, min, sec)` -- builds a `DateTime` from calendar components; `MappedLocalTime::None` on invalid input.
- `timestamp(secs, nsecs)` (deprecated, panics) / `timestamp_opt(secs, nsecs)` -- from a Unix timestamp plus nanosecond remainder.
- `timestamp_millis(millis)` (deprecated, panics) / `timestamp_millis_opt(millis)` -- millisecond equivalent.
- `timestamp_nanos(nanos)` -- nanosecond equivalent; never fails.
- `timestamp_micros(micros)` -- microsecond equivalent, `MappedLocalTime::None` on out-of-range input.
- `from_offset(&Self::Offset)` -- reconstructs the time zone from one of its offsets.
- `offset_from_local_date(&NaiveDate)` / `offset_from_local_datetime(&NaiveDateTime)` -- the offset(s) applicable to a given *local* date/datetime (may be ambiguous or nonexistent -- hence `MappedLocalTime`).
- `from_local_datetime(&NaiveDateTime)` -- converts a local `NaiveDateTime` to a timezone-aware `DateTime`, given the above.
- `offset_from_utc_date(&NaiveDate)` / `offset_from_utc_datetime(&NaiveDateTime)` -- the offset for a given *UTC* date/datetime; cannot fail (the UTC timeline has no gaps or folds).
- `from_utc_datetime(&NaiveDateTime)` -- converts a UTC `NaiveDateTime` to the local time.

### 7.2 `Offset` trait

- `fix()` -- the fixed offset from UTC that this value represents, as a `FixedOffset`.

### 7.3 `MappedLocalTime<T>` (alias: `LocalResult<T>`)

The result of mapping a local time to a concrete instant: unambiguous (`Single`), ambiguous (`Ambiguous(earliest, latest)`, e.g. during a DST fold), or nonexistent (`None`, e.g. during a DST gap, or on any other error).

- `single()` -- `Some` only for the unambiguous case.
- `earliest()` / `latest()` -- the earliest/latest candidate, for `Single` or `Ambiguous` (`None` for the `None` variant).
- `map(f)` -- transforms the contained value(s) with a function.
- `unwrap()` -- returns the single value or panics (best used with zones where the mapping can't practically fail, like `Utc`).

### 7.4 `Utc`

The UTC time zone; a zero-sized type also used as its own `Offset`.

- `now()` -- the current date and time in UTC (reads the system clock).
- `TimeZone`/`Offset` implementations are all trivial (UTC has no offset variation).
- `Debug` prints `Z`, `Display` prints `UTC`.

### 7.5 `FixedOffset`

A time zone with a fixed offset from UTC, from -23:59:59 to +23:59:59.

- `east(secs)` (deprecated, panics) / `east_opt(secs)` -- an offset for the Eastern Hemisphere (positive = ahead of UTC); `None`/panics if `secs` is not strictly within +/-86,400 seconds (24h).
- `west(secs)` (deprecated, panics) / `west_opt(secs)` -- same for the Western Hemisphere (sign flipped).
- `local_minus_utc()` -- seconds to add to UTC to get the local time.
- `utc_minus_local()` -- the inverse.
- `TimeZone`/`Offset` implementations are trivial (a fixed offset never varies by date).
- `Debug`/`Display` -- `+HH:MM`, `-HH:MM`, or `+HH:MM:SS` when the offset has a non-zero seconds component.
- `FromStr` -- parses strings like `+09:00`, `-0400`, `+02` (colon optional, any amount of surrounding whitespace).

### 7.6 `Local`

The system's local time zone; the one place in the crate depending on an external time zone database (`tzdb`/`tz-rs`, reading the IANA database).

- `now()` -- the current date and time in the local zone.
- `TimeZone` implementation resolves offsets via the system's configured zone, falling back to UTC if it cannot be determined (matching chrono's own documented fallback policy); correctly distinguishes a DST fold (ambiguous) from a gap (`None`) by checking whether the returned wall-clock time actually matches what was requested.

## 8. `Datelike` / `Timelike` traits

Read/write access to the components of any date-bearing (`Datelike`) or time-bearing (`Timelike`) type -- implemented by `NaiveDate`/`NaiveDateTime`/`DateTime<Tz>` (`Datelike`) and `NaiveTime`/`NaiveDateTime`/`DateTime<Tz>` (`Timelike`).

**`Datelike`** -- `year`, `year_ce()` (absolute year number from 1, paired with a CE/BCE flag; default method), `quarter()` (1-4, default method), `month`, `month0`, `day`, `day0`, `ordinal`, `ordinal0`, `weekday`, `iso_week`, the `with_*` mutators (abstract, implemented per type), `num_days_from_ce()` (default method, proleptic day count), `num_days_in_month()` (default method, length of the month this date falls in).

**`Timelike`** -- `hour`, `hour12()` (12-hour reading paired with an AM/PM flag; default method), `minute`, `second` (never 60, even for a leap second), `nanosecond` (`1,000,000,000..2,000,000,000` represents a leap second), the `with_*` mutators, `num_seconds_from_midnight()` (default method).

## 9. `Weekday` / `WeekdaySet`

### 9.1 `Weekday`

An enum, Monday through Sunday (ISO 8601 week convention).

- `succ()` / `pred()` -- the next/previous day, wrapping around the week.
- `num_days_from_monday()` / `num_days_from_sunday()` -- 0-indexed day number from the given start.
- `number_from_monday()` / `number_from_sunday()` -- 1-indexed equivalents.
- `days_since(other)` -- days since the previous (or same) occurrence of `other`, always in `0..7`.
- `Display` -- prints the 3-letter English abbreviation (e.g. `Mon`), matching the `%a` format specifier.
- `FromStr` -- accepts short or long English names, case-insensitively; returns `ParseWeekdayError` otherwise.
- `serde` support: serializes as the 3-letter name, deserializes short or long names.

### 9.2 `WeekdaySet`

A compact, `Copy` set of `Weekday`s packed into a single byte.

- `EMPTY` / `ALL` -- the empty set and the full 7-day set.
- `from_array([Weekday; C])` -- builds a set from an array (duplicates fine).
- `single(weekday)` -- a set containing exactly one day.
- `single_day()` -- the single day in the set, or `None` if empty or holding more than one.
- `insert(day)` / `remove(day)` -- mutate the set, reporting whether membership actually changed.
- `is_subset(other)`, `intersection(other)`, `union(other)`, `symmetric_difference(other)`, `difference(other)` -- standard set operations.
- `first()` / `last()` -- the earliest/latest day in the set (Monday-first ordering).
- `iter(start)` -- iterates the set's days starting at `start` and wrapping around the week (`WeekdaySetIter`, a `DoubleEndedIterator` + `ExactSizeIterator` + `FusedIterator`; not itself nameable outside the crate, matching chrono).
- `contains(day)`, `is_empty()`, `len()`.
- `Debug` -- prints the raw 7-bit mask (e.g. `WeekdaySet(0000001)`).
- `Display` -- prints a bracketed, comma-separated, Monday-first list (e.g. `[Mon, Fri, Sun]`).
- `FromIterator<Weekday>`.

## 10. `Month`

The month of the year as a standalone enum (`January`=0 through `December`=11), distinct from the plain `u32` returned by `Datelike::month()`.

- `succ()` / `pred()` -- next/previous month, wrapping across the year boundary.
- `number_from_month()` -- 1-indexed month number.
- `name()` -- full English name (e.g. `"January"`).
- `num_days(year)` -- the number of days in this month for a given year (accounts for leap years in February; `None` only if `year` is out of `NaiveDate`'s range).
- `TryFrom<u8>` -- builds a `Month` from a 1-12 number, `OutOfRange` error otherwise.
- `FromStr` -- accepts the short (3-letter) or full English name, case-insensitive; `ParseMonthError` otherwise.
- `serde` support: serializes as the full name, deserializes short or long names.

## 11. Durations (`duration` module)

### 11.1 `TimeDelta` (alias: `Duration`)

A signed span of time with nanosecond precision. Internal representation: `secs` carries the sign, `nanos` is always a non-negative remainder in `0..1_000_000_000`.

- `MIN` / `MAX` -- the representable range is restricted to +/- `i64::MAX` milliseconds (so `MIN` is not perfectly symmetric with `MAX` once sub-millisecond precision is considered), matching chrono exactly.
- `zero()` / `is_zero()`.
- `new(secs, nanos)` -- from whole seconds and a nanosecond remainder; `None` if out of range.
- `try_weeks`/`weeks`, `try_days`/`days`, `try_hours`/`hours`, `try_minutes`/`minutes`, `try_seconds`/`seconds` -- each pair is a fallible (`Option`) and panicking constructor from the named unit.
- `try_milliseconds`/`milliseconds` -- fallible/panicking; `milliseconds`/`try_milliseconds(-i64::MAX)` is exactly `MIN` and must succeed (a real overflow bug in the internal multiplication was found and fixed here via wrapping arithmetic).
- `microseconds`, `nanoseconds` -- infallible (the full `i64` range of micro-/nanoseconds always fits in the representable range).
- `num_weeks()`, `num_days()`, `num_hours()`, `num_minutes()`, `num_seconds()` -- whole-unit counts, truncated toward zero.
- `as_seconds_f64()` / `as_seconds_f32()` -- fractional-second representation.
- `num_milliseconds()` -- total milliseconds (never overflows, thanks to the constructors' bounds).
- `subsec_millis()` -- the fractional-second part in milliseconds.
- `num_microseconds()` / `num_nanoseconds()` -- total micro-/nanoseconds, `None` on overflow.
- `subsec_micros()` / `subsec_nanos()` -- fractional-second part, sign-matched to the whole duration (unlike the internal always-non-negative `nanos` field).
- `checked_add(rhs)` / `checked_sub(rhs)` -- `None` on overflow instead of panicking.
- `checked_mul(rhs: i32)` -- `None` if the result wouldn't fit in an `i64` number of seconds (checked against `i64`'s range, not `MIN`/`MAX`, matching chrono's own -- narrower -- documented behavior deliberately).
- `checked_div(rhs: i32)` -- `None` if `rhs` is zero.
- `abs()` -- absolute (non-negative) value.
- `from_std(core::time::Duration)` / `to_std()` -- conversion to/from the standard library's unsigned duration type, each returning `Result<_, OutOfRangeError>`.
- Operators: `Neg`, `Add`, `Sub`, `AddAssign`, `SubAssign`, `Mul<i32>`, `Div<i32>` (panics on division by zero), `Sum<&TimeDelta>`/`Sum<TimeDelta>` (for `.sum()` over an iterator).
- `Display` -- ISO 8601 duration format (e.g. `PT1.5S`), with a non-standard leading `-` for negative durations.
- `serde` support: serializes as a `(secs, nanos)` tuple.

### 11.2 `Days`

An increment expressed in whole days, used with `NaiveDate::checked_add_days`/`checked_sub_days` and the `Add`/`Sub<Days>` operators.

- `new(num_days: u64)`.

### 11.3 `Months`

An increment expressed in calendar months (distinct from `TimeDelta`, which has no notion of variable-length months), used with `checked_add_months`/`checked_sub_months`.

- `new(num_months: u32)`.
- `as_u32()`.

### 11.4 `OutOfRangeError`

Returned by `TimeDelta::from_std`/`to_std` when the source value doesn't fit the target type. Implements `std::error::Error` and `Display`.

## 12. Rounding (`round` module)

### 12.1 `SubsecRound` trait

Rounds or truncates a value's sub-second precision to a maximum number of fractional digits. Blanket-implemented for any `Timelike + Add<TimeDelta, Output = Self> + Sub<TimeDelta, Output = Self>` (i.e. `NaiveTime`, `NaiveDateTime`, `DateTime<Tz>`).

- `round_subsecs(digits)` -- rounds (halfway values round away from zero); unchanged at 9+ digits.
- `trunc_subsecs(digits)` -- truncates; unchanged at 9+ digits.

### 12.2 `DurationRound` trait

Rounds or truncates a date/time by an arbitrary `TimeDelta` span (e.g. the nearest 15 minutes). Implemented for `NaiveDateTime` and `DateTime<Tz>`. Fails (via the associated `Err` type) whenever the span or the value's nanosecond timestamp doesn't fit in an `i64`, or the span is zero or negative.

- `duration_round(duration)` -- rounds to the nearest multiple (halfway rounds up).
- `duration_trunc(duration)` -- truncates down to the previous multiple.
- `duration_round_up(duration)` -- rounds up to the next multiple (or stays put if already an exact multiple).

### 12.3 `RoundingError`

The error type for `DurationRound`. Variants: `DurationExceedsTimestamp` (kept for chrono parity; no longer actually produced), `DurationExceedsLimit` (the span doesn't fit in an `i64` of nanoseconds, or is zero/negative), `TimestampExceedsLimit` (the value's own nanosecond timestamp doesn't fit). Implements `Display`/`Debug`.

## 13. Formatting and parsing (`format` module)

The shared engine behind every type's `format`/`parse_from_str` methods, and the `strftime`-style format-string syntax.

### 13.1 The `strftime` specifier table

Format strings use a syntax closely resembling C's `strftime`, documented in full in the `strftime` module. Every specifier below works both for formatting and (except where noted) parsing.

Date specifiers: `%Y` full year (zero-padded to 4 digits, accepts a sign outside 0..=9999), `%C` year/100, `%y` year%100, `%q` quarter (1-4), `%m` month (01-12), `%b`/`%h` abbreviated month name, `%B` full month name, `%d` day of month (01-31), `%e` day of month space-padded, `%a` abbreviated weekday, `%A` full weekday, `%w` weekday (Sun=0), `%u` ISO weekday (Mon=1), `%U` week number (Sunday-first), `%W` week number (Monday-first), `%G`/`%g` ISO week-date year (full/mod 100), `%V` ISO week number, `%j` day of year (001-366), `%D`/`%x` `%m/%d/%y`, `%F` `%Y-%m-%d`, `%v` `%e-%b-%Y`.

Time specifiers: `%H` hour (00-23), `%k` hour space-padded, `%I` hour (01-12), `%l` hour (12h) space-padded, `%P`/`%p` am/pm (lower/upper case), `%M` minute, `%S` second (00-60, accounts for leap seconds), `%f` nanoseconds since the last whole second, `%.f`/`%.3f`/`%.6f`/`%.9f` decimal fraction of a second (auto/3/6/9 digits, with leading dot), `%3f`/`%6f`/`%9f` same without the leading dot, `%R` `%H:%M`, `%T`/`%X` `%H:%M:%S`, `%r` `%I:%M:%S %p`.

Time zone specifiers: `%Z` offset only (no time zone name/abbreviation support), `%z` `+HHMM`, `%:z` `+HH:MM`, `%::z` `+HH:MM:SS`, `%:::z` `+HH` (offset without minutes), `%#z` parsing-only, allows minutes to be missing or present.

Date & time specifiers: `%c` `%a %b %e %H:%M:%S %Y`, `%+` ISO 8601/RFC 3339, `%s` Unix timestamp.

Special specifiers: `%t` tab, `%n` newline, `%%` literal percent.

Padding override modifiers (numeric specifiers only): `%-?` no padding, `%_?` space padding, `%0?` zero padding.

`%x`/`%X`/`%c`/`%r` and month/weekday names are always English/POSIX by default; `unstable-locales` (section 13.6) makes them locale-aware.

### 13.2 `StrftimeItems`

A parsing iterator turning a format string into a sequence of `Item`s.

- `new(s)` -- standard constructor; yields `Item::Error` on an invalid specifier.
- `new_lenient(s)` -- like `new`, but yields `Item::Literal` instead of erroring.
- `new_with_locale(s, locale)` -- adjusts `%x`/`%X`/`%c`/`%r` to the given locale (feature-gated).
- `parse()` -- collects into a `Vec<Item>`, useful to avoid re-parsing the same format string repeatedly.
- `parse_to_owned()` -- same, with no borrowed references into the original format string.

### 13.3 Items, numeric/fixed specifiers, padding

- `Item<'a>` -- the common intermediate representation for both formatting and parsing: `Literal`/`OwnedLiteral`, `Space`/`OwnedSpace`, `Numeric(Numeric, Pad)`, `Fixed(Fixed)`, `Error`.
- `Numeric` -- non-exhaustive enum of numeric field kinds (`Year`, `YearDiv100`, `YearMod100`, `IsoYear` and its Div100/Mod100 variants, `Quarter`, `Month`, `Day`, `WeekFromSun`, `WeekFromMon`, `IsoWeek`, `NumDaysFromSun`, `WeekdayFromMon`, `Ordinal`, `Hour`, `Hour12`, `Minute`, `Second`, `Nanosecond`, `Timestamp`, plus an opaque `Internal` variant for crate-internal use).
- `Fixed` -- non-exhaustive enum of fixed-format field kinds (month/weekday names, AM/PM markers, the `Nanosecond`/`Nanosecond3`/`Nanosecond6`/`Nanosecond9` fractional-second variants, the timezone-name/offset variants, `RFC2822`, `RFC3339`, plus an opaque `Internal` variant).
- `Pad` -- `None`, `Zero`, `Space`.
- `OffsetFormat` / `OffsetPrecision` / `Colons` -- structured description of how to render a UTC offset (precision, colon style, whether to allow `Z` for zero offset, hour padding); used internally by the RFC 3339/2822 writers.

### 13.4 Parsing functions

- `parse(parsed: &mut Parsed, s, items)` -- parses `s` against a sequence of `Item`s into `Parsed`; errors if any input remains unconsumed (`Item::Space` at the end can absorb trailing whitespace). Greedy (prefers the longest valid match for names) and padding-agnostic (ignores the requested `Pad`, so any amount of leading whitespace/zeros is accepted), but obeys each item's fixed parsing width.
- `parse_and_remainder(parsed, s, items)` -- same, returning the unparsed remainder instead of erroring on it.

### 13.5 `Parsed`

An incrementally-built, consistency-checked collection of parsed date/time fields; used internally by every parsing function, and public so custom parsers can reuse the same resolution logic.

- `new()`.
- `set_year`, `set_year_div_100`, `set_year_mod_100`, `set_isoyear`, `set_isoyear_div_100`, `set_isoyear_mod_100`, `set_quarter`, `set_month`, `set_week_from_sun`, `set_week_from_mon`, `set_isoweek`, `set_weekday`, `set_ordinal`, `set_day`, `set_ampm`, `set_hour12`, `set_hour`, `set_minute`, `set_second`, `set_nanosecond`, `set_timestamp`, `set_offset` -- each range-checks the value and, if the field was already set, requires consistency with the new value (`Impossible` error on conflict).
- `to_naive_date()` -- resolves a `NaiveDate` from whichever consistent subset of fields is available (year+month+day, year+ordinal, year+week+weekday, or ISO week date).
- `to_naive_time()` -- resolves a `NaiveTime` from hour(+AM/PM)/minute(/second(/nanosecond)); handles a leap second (`second == 60`).
- `to_naive_datetime_with_offset(offset)` -- resolves a combined `NaiveDateTime`, either from date+time fields or from a single `timestamp` field (the given `offset` is assumed, not cross-checked against any parsed offset field).
- `to_fixed_offset()` -- resolves a `FixedOffset` from the parsed `offset` field.
- `to_datetime()` -- resolves a full `DateTime<FixedOffset>` from date/time/offset fields and/or a timestamp.
- `to_datetime_with_timezone(&tz)` -- same, additionally validating (and disambiguating, where possible) against a specific `TimeZone`.
- Accessors mirroring every `set_*` field (`year()`, `year_div_100()`, ..., `offset()`) -- each returns `Option<T>`, `Some` only if that field was set.

### 13.6 `DelayedFormat` / `SecondsFormat` / `Locale`

- `DelayedFormat<I>` -- a lazily-rendered formatting result (only actually formats when displayed via `Display`/`to_string`/`write_to`); constructed via `new`, `new_with_offset`, `new_with_locale` (feature-gated), `new_with_offset_and_locale` (feature-gated). `write_to(writer)` performs the formatting into any `core::fmt::Write`.
- `SecondsFormat` -- non-exhaustive enum controlling sub-second precision in `to_rfc3339_opts`: `Secs`, `Millis`, `Micros`, `Nanos`, `AutoSi` (auto-selects based on the non-zero digits present).
- `Locale` -- re-export of `pure_rust_locales::Locale` (only present with the `unstable-locales` feature); selects the locale used by `format_localized`/`new_with_locale` and friends. Without the feature, formatting/parsing is always English/POSIX-only.

### 13.7 Errors

- `ParseError` -- opaque wrapper; `.kind()` returns the `ParseErrorKind`. Implements `Display`/`std::error::Error`.
- `ParseErrorKind` -- non-exhaustive: `OutOfRange` (a field's value is out of its permitted range), `Impossible` (fields are mutually inconsistent), `NotEnough` (insufficient fields to build the requested value), `Invalid` (unparseable character sequence), `TooShort` (input ended prematurely), `TooLong` (trailing unparsed input), `BadFormat` (bad/unsupported format string).
- `ParseResult<T>` -- alias for `Result<T, ParseError>`.

## 14. `serde` support (crate feature `serde`)

Available at `time_compute::serde` (re-exported from `datetime::serde`) and `time_compute::naive::serde` (re-exported from `naive::datetime::serde`).

`time_compute::serde` (for `DateTime<Tz>`, which (de)serializes to/from an RFC 3339 string by default): `ts_seconds`, `ts_milliseconds`, `ts_microseconds`, `ts_nanoseconds`, and their `_option` variants -- each a module with `serialize`/`deserialize` functions intended for serde's `#[serde(with = "...")]` field attribute, (de)serializing `DateTime<Utc>` (or `Option<DateTime<Utc>>`) as a Unix timestamp in the named unit instead of a string.

`time_compute::naive::serde` -- the same eight modules (`ts_seconds[_option]` through `ts_nanoseconds[_option]`), but for `NaiveDateTime` instead of `DateTime<Utc>` (internally assumes UTC to compute the timestamp).

Every other public type with a natural string form (`NaiveDate`, `NaiveTime`, `Weekday`, `Month`, `TimeDelta`, `IsoWeek` has none, matching chrono) also implements `serde::Serialize`/`Deserialize` directly (not gated behind a submodule), each documented alongside that type above.

## 15. `rkyv` support (crate features `rkyv`, `rkyv-16`, `rkyv-32`, `rkyv-64`; `rkyv-validation` adds `Archive: CheckBytes`)

Available at `time_compute::rkyv`, re-exporting the `Archived*` counterpart of every type with an `rkyv` derive: `ArchivedDateTime`, `ArchivedTimeDelta` (also aliased `ArchivedDuration`), `ArchivedMonth`, `ArchivedIsoWeek`, `ArchivedNaiveDate`, `ArchivedNaiveDateTime`, `ArchivedNaiveTime`, `ArchivedFixedOffset`, `ArchivedLocal`, `ArchivedUtc`, `ArchivedWeekday`.

---

# Part 2 -- `time_compute` extensions (no chrono equivalent)

Every item below is explicitly marked in the source with a `# time_compute extension -- not part of chrono` doc-comment section. None of it is guaranteed to match any future `chrono` API (there is nothing in chrono to match); all of it is still held to the same quality bar as the core (tests, docs, `#[must_use]`, `const fn` wherever the algorithm allows).

## 1. Age calculation

- `NaiveDate::age(&self, on: Self) -> Option<u32>` -- age in whole years as of `on`, e.g. `date_of_birth.age(today)`. Exactly `on.years_since(*self)` with the argument order that reads naturally for this use case. `NaiveDate` never reads the system clock; the caller passes "today" explicitly.
- `DateTime::age(&self, on: Self) -> Option<u32>` -- same idea for a timezone-aware instant, e.g. `date_of_birth.age(Utc::now())`.

Both are inspired by WLanguage's `Age()` function and were added as a deliberate, explicitly-authorized addition on top of the frozen chrono-compatible surface.

## 2. Christian movable feasts

All computed directly in the proleptic Gregorian calendar, `const fn`, no floating point.

- `NaiveDate::easter(year)` -- western (Catholic/Protestant) Easter Sunday, via the "anonymous Gregorian algorithm" (Meeus/Jones/Butcher), implemented from scratch (chrono itself has no equivalent; its ecosystem relies on the separate `computus` crate).
- `NaiveDate::orthodox_easter(year)` -- Eastern Orthodox Easter: computed via the Julian-calendar Paschal-full-moon reckoning (Meeus's Julian algorithm), then converted to the Gregorian calendar via the standard closed-form Julian/Gregorian drift (`year/100 - year/400 - 2` days).
- `NaiveDate::mardi_gras(year)` -- Fat Tuesday/Shrove Tuesday, 47 days before Easter.
- `NaiveDate::ash_wednesday(year)` -- first day of Lent, 46 days before Easter.
- `NaiveDate::palm_sunday(year)` -- 7 days before Easter.
- `NaiveDate::ascension(year)` -- 39 days after Easter.
- `NaiveDate::pentecost(year)` -- 49 days after Easter.

## 3. Hebrew calendar

A lunisolar calendar computed via the mean lunar conjunction (*molad*) of Tishrei, the 19-year Metonic cycle, and the four traditional postponement rules ("Lo ADU Rosh", "Molad Zaken", "GaTaRaD", "BeTuTeKaFoT"). All-integer arithmetic (no floating point), anchored to one independently verified real date (1 Tishrei 5783 = Monday 26 September 2022) so no ancient epoch conversion is needed -- every other year is reached by pure day counting from that anchor.

- `NaiveDate::from_hebrew_ymd(year, month, day)` -- Hebrew date to Gregorian `NaiveDate` (civil month numbering: 1 = Tishrei).
- `NaiveDate::to_hebrew_ymd(&self)` -- the exact inverse, `(year, month, day)`.
- `NaiveDate::passover(year)` -- 15 Nisan (Pessah), for the Gregorian year given (uses Hebrew year `year + 3760`).
- `NaiveDate::rosh_hashanah(year)` -- 1 Tishrei, the Hebrew New Year (Hebrew year `year + 3761`, since it falls in autumn).
- `NaiveDate::yom_kippur(year)` -- 10 Tishrei, 9 days after Rosh Hashanah.
- `NaiveDate::sukkot(year)` -- 15 Tishrei, 14 days after Rosh Hashanah.
- `NaiveDate::hanukkah(year)` -- 25 Kislev, accounting for the variable length of Cheshvan/Kislev that year.
- `NaiveDate::purim(year)` -- 14 Adar (or 14 Adar II in a leap year), using the winter-appropriate Hebrew year `year + 3760`.
- `NaiveDate::shavuot(year)` -- 6 Sivan.

## 4. Hijri/Islamic calendar (tabular)

Implements the "tabular" (also "civil"/"Kuwaiti algorithm") Islamic calendar: a fixed arithmetical approximation (odd months 30 days, even months 29, except Dhu al-Hijjah which gains a day in leap years; 11 leap years per 30-year cycle at fixed cycle positions), the same scheme used by, among others, Microsoft Windows. Anchored to two independently verified real dates (1 Muharram 1446 AH = Sunday 7 July 2024; 1 Muharram 1447 AH = Thursday 26 June 2025) rather than the 7th-century epoch. Integer-only, `const fn`.

**Important limitation, inherent to any tabular calendar, not specific to this implementation:** real-world religious observance is based on actual moon sighting (or, in some countries, the Umm al-Qura astronomical calendar), which routinely differs from this tabular approximation by a day or two. Use these functions for consistent, reproducible conversions, not to determine an officially announced observance date.

- `NaiveDate::from_hijri_ymd(year, month, day)` -- Hijri date (`year` = AH year, `month` 1-12) to Gregorian `NaiveDate`.
- `NaiveDate::to_hijri_ymd(&self)` -- the exact inverse.
- `NaiveDate::hijri_new_year(hijri_year)` -- 1 Muharram of the given **Hijri** year (not Gregorian -- the Hijri calendar drifts through all Gregorian seasons over roughly 33 years, so there is no fixed Gregorian-to-Hijri year mapping the way there is for the Hebrew calendar).
- `NaiveDate::ramadan_start(hijri_year)` -- 1 Ramadan.
- `NaiveDate::eid_al_fitr(hijri_year)` -- 1 Shawwal, marking the end of Ramadan.
- `NaiveDate::eid_al_adha(hijri_year)` -- 10 Dhu al-Hijjah.

## 5. Japanese calendar and festivals

### 5.1 `JapaneseEra`

An enum covering the five **modern** eras ("one reign, one era name" system formalized in 1868): `Meiji`, `Taisho`, `Showa`, `Heisei`, `Reiwa`. Pre-Meiji era names (over 200, some lasting only months) are out of scope.

- `start_date()` -- the first day of the era (the dates commonly used in software such as ICU/Unicode CLDR for Gregorian conversion).
- `end_date_exclusive()` -- the first day of the *next* era, or `None` for the current, open-ended era (Reiwa today).
- `name()` -- romanized name (e.g. `"Reiwa"`).
- `Display` -- prints `name()`.

### 5.2 Era conversion

- `NaiveDate::japanese_era(&self)` -- the `(JapaneseEra, era_year)` containing this date; `None` for dates before 25 January 1868.
- `NaiveDate::from_japanese_era_ymd(era, era_year, month, day)` -- the exact inverse; `None` if the date falls outside that era's actual span.

### 5.3 Fixed-date festivals (no astronomical calculation needed)

- `NaiveDate::shogatsu(year)` -- Japanese New Year, 1 January.
- `NaiveDate::hana_matsuri(year)` -- the Buddha's birthday observance in Japan, 8 April (unlike most Buddhist traditions, which use a lunar-calendar date, Japan fixed this to the Gregorian calendar).
- `NaiveDate::tanabata(year)` -- the star festival, 7 July (the date used in most of Japan; a minority of regions instead observe a lunar-calendar-equivalent date roughly a month later, not covered here).
- `NaiveDate::obon_start(year)` -- start of the ancestor-veneration festival, 13 August (most of Japan; some regions such as Okinawa follow the traditional lunisolar date instead, not covered here).
- `NaiveDate::shichi_go_san(year)` -- the children's rite-of-passage festival, 15 November.

### 5.4 Solar-term festivals (real astronomical calculation)

The crate's only floating-point, non-`const fn` functions, delegating to the `astro` crate (Meeus' algorithms) for the Sun's true ecliptic longitude -- a deliberate, explicitly-authorized exception to the crate's near-zero-dependency design, since an equinox/solar-term crossing has no closed-form integer solution. Accurate to well within a day for any plausible year; supports years roughly `-32768..=32767` only (bounded by `astro`'s internal `i16` year representation, unlike the rest of the crate's much wider range).

- `NaiveDate::shunbun_no_hi(year)` -- Vernal Equinox Day (春分の日): the JST calendar day containing the moment the Sun's longitude crosses 0 degrees. Also the midpoint of the spring "Higan" Buddhist observance week.
- `NaiveDate::shuubun_no_hi(year)` -- Autumnal Equinox Day (秋分の日): longitude crossing 180 degrees.
- `NaiveDate::setsubun(year)` -- the day before Risshun (立春, solar-term start of spring, longitude crossing 315 degrees), marked by the bean-throwing ritual (mamemaki).

## 6. Chinese lunisolar calendar

Implements the standard modern Chinese calendar algorithm (in use, with minor refinements, since the 1645 calendar reform; formalized in China's national standard GB/T 33661-2017): a lunar month begins on the China-Standard-Time (UTC+8) day of a new moon; the month containing the December solstice is always month 11; a "suì" (year, one "month 11" to the next) has 12 or 13 lunar months, with exactly one leap ("intercalary") month -- the first one after month 11 containing no "zhongqi" (major solar term) -- when it has 13. Backed by real astronomical computation via the `astro` crate (same dependency and precision notes as the Japanese solar-term functions above), with a `thread_local!` memoization cache for the underlying year-structure computation (`sui_months`) to keep repeated queries fast.

- `NaiveDate::chinese_new_year(year)` -- New Year's Day (first day of month 1) of the Chinese year whose New Year falls in Gregorian year `year` (the common "civil year" convention most Chinese calendar software uses; the traditional 60-year sexagenary cycle name is not implemented).
- `NaiveDate::to_chinese_ymd(&self)` -- converts to `(year, month, is_leap, day)` in the Chinese calendar.
- `NaiveDate::from_chinese_ymd(year, month, is_leap, day)` -- the exact inverse; `None` if `month`/`is_leap` doesn't identify a real month of that Chinese year, or `day` exceeds that month's actual length (29 or 30).
- `NaiveDate::duanwu(year)` -- Dragon Boat Festival (端午節), month 5 day 5.
- `NaiveDate::zhongqiu(year)` -- Mid-Autumn Festival (中秋節), month 8 day 15.
- `NaiveDate::qingming(year)` -- Qingming (清明, tomb-sweeping day): unlike `duanwu`/`zhongqiu`, a *solar-term* festival (Sun's longitude crossing 15 degrees, roughly April 4-5), not a Chinese-calendar month/day.

## 7. Thai/Buddhist lunisolar calendar

Implements the traditional Thai ("Chulasakarat") lunisolar reckoning used to fix the four principal Buddhist observances, plus the start/end of the Buddhist Lent. Unlike the Chinese calendar or the Japanese solar-term functions, this is **not** based on real astronomical positions: it is a centuries-old, purely arithmetic mean-motion model (integer counters -- "horakhun", "kammacapon", "avoman", "tithi" -- tracked against a fixed epoch), so this is integer-only, no floating point and no `astro` dependency. Because it tracks mean rates rather than true positions, its dates can differ by a day or two from true astronomical new moons, and even from other published Thai calendars using slightly different historical corrections to the same underlying system.

- `NaiveDate::magha_bucha(year)` -- commemorates the spontaneous gathering of 1,250 of the Buddha's disciples: full moon of the 3rd lunar month (4th, in an intercalary-month year).
- `NaiveDate::visakha_bucha(year)` -- Vesak, the most important Buddhist holy day (the Buddha's birth, enlightenment and death, traditionally held to have all occurred on the same full-moon day): full moon of the 6th lunar month (7th, in an intercalary year).
- `NaiveDate::asalha_bucha(year)` -- commemorates the Buddha's first sermon: full moon of the 8th lunar month (the *second*, repeated, occurrence of month 8 in an intercalary year -- a different shift rule than Magha/Visakha Bucha).
- `NaiveDate::khao_phansa(year)` -- start of the three-lunar-month Buddhist Lent, the day immediately after Asalha Bucha.
- `NaiveDate::awk_phansa(year)` -- end of the Buddhist Lent: full moon of the 11th lunar month. Never itself shifted by an intercalary month (whichever intercalation happens that year has already occurred earlier, at month 8).

## 8. Matariki (Māori New Year)

- `NaiveDate::matariki(year)` -- the date of Matariki, New Zealand's midwinter observance marking the pre-dawn rising of the Matariki star cluster (the Pleiades). Unlike every other function in this crate, **not** computed from any formula: New Zealand's Matariki Advisory Committee sets the date each year (the Friday closest to a several-day lunar phase window that is not itself reducible to a single instant) and it is legislated as a public holiday. This method is a fixed lookup table transcribed from the Museum of New Zealand Te Papa Tongarewa's officially published dates (2022-2052); returns `None` for any year outside that range rather than guessing, since the committee has not published dates beyond 2052 as of this writing.