pub struct Date { /* private fields */ }Expand description
A Gregorian-calendar date — (year, month, day).
A Date is created by Date::ymd (validating) or
Date::ymd_unchecked (caller asserts validity); the field layout is
private so the invariant that the triple names a real date cannot be
violated by direct construction. The type is Copy and allocates
nothing.
PartialOrd / Ord follow the natural chronological order — equivalent
to lexicographic order on (year, month, day), which is the same thing
for Gregorian dates.
The accepted year range is 1583..=9999: the Gregorian calendar took
effect in October 1582, and from 1583 onward every day-count and
holiday-calendar rule this crate implements is defined uniformly.
§Examples
use regit_daycount::Date;
let d = Date::ymd(2026, 5, 23).unwrap();
assert_eq!(d.year(), 2026);
assert_eq!(d.month(), 5);
assert_eq!(d.day(), 23);Implementations§
Source§impl Date
impl Date
Sourcepub const MIN_YEAR: i32 = 1583
pub const MIN_YEAR: i32 = 1583
Smallest accepted year (1583 — the first full year after the Gregorian reform of October 1582).
Sourcepub const MAX_YEAR: i32 = 9999
pub const MAX_YEAR: i32 = 9999
Largest accepted year (9999 — keeps the year an i16-fittable
value and matches every published holiday-calendar horizon).
Sourcepub fn ymd(year: i32, month: u8, day: u8) -> Result<Self, ValidationError>
pub fn ymd(year: i32, month: u8, day: u8) -> Result<Self, ValidationError>
Constructs a validated Date from a (year, month, day) triple.
Validation, in order: the year is in MIN_YEAR..=MAX_YEAR, the
month is in 1..=12, and the day is in 1..=days_in_month(year, month) — which accounts for leap years.
§Errors
ValidationError::OutOfRangewithwhat = "year < 1583"orwhat = "year > 9999"if the year is outside the supported range.ValidationError::InvalidDatewithrule = "month-out-of-range"if the month is not in1..=12.ValidationError::InvalidDatewithrule = "day-out-of-range"if the day is not in1..=days_in_month(year, month).
§Examples
use regit_daycount::{Date, ValidationError};
// A valid date.
assert!(Date::ymd(2026, 5, 23).is_ok());
// 2025 is not a leap year — 29 February is rejected.
assert_eq!(
Date::ymd(2025, 2, 29),
Err(ValidationError::InvalidDate { rule: "day-out-of-range" }),
);Sourcepub const fn ymd_unchecked(year: i32, month: u8, day: u8) -> Self
pub const fn ymd_unchecked(year: i32, month: u8, day: u8) -> Self
Constructs a Date without validating the triple.
The caller asserts that (year, month, day) names a real Gregorian
date inside the supported year range. This exists for const-context
construction and for reconstructing a Date from fields validated
earlier; prefer Date::ymd for any untrusted input.
§Examples
use regit_daycount::Date;
let d = Date::ymd_unchecked(2026, 5, 23);
assert_eq!(d.year(), 2026);Sourcepub const fn year(&self) -> i32
pub const fn year(&self) -> i32
Returns the year.
§Examples
use regit_daycount::Date;
assert_eq!(Date::ymd_unchecked(2026, 5, 23).year(), 2026);Sourcepub const fn month(&self) -> u8
pub const fn month(&self) -> u8
Returns the month, 1..=12.
§Examples
use regit_daycount::Date;
assert_eq!(Date::ymd_unchecked(2026, 5, 23).month(), 5);Sourcepub const fn day(&self) -> u8
pub const fn day(&self) -> u8
Returns the day of the month, 1..=31.
§Examples
use regit_daycount::Date;
assert_eq!(Date::ymd_unchecked(2026, 5, 23).day(), 23);Sourcepub const fn is_leap_year(year: i32) -> bool
pub const fn is_leap_year(year: i32) -> bool
Returns true if year is a Gregorian leap year.
A year is a leap year if it is divisible by 4 and either not divisible by 100 or divisible by 400. Hence 1900 is not a leap year, 2000 is, and 2100 is not.
§Examples
use regit_daycount::Date;
assert!( Date::is_leap_year(2000));
assert!( Date::is_leap_year(2024));
assert!(!Date::is_leap_year(1900));
assert!(!Date::is_leap_year(2025));Sourcepub const fn days_in_month(year: i32, month: u8) -> u8
pub const fn days_in_month(year: i32, month: u8) -> u8
Returns the number of days in (year, month).
February takes 29 days in a leap year and 28 otherwise; every other
month is the conventional 30 or 31. If month is not in 1..=12,
returns 0 (the caller is expected to validate the month first;
Date::ymd does).
§Examples
use regit_daycount::Date;
assert_eq!(Date::days_in_month(2024, 2), 29);
assert_eq!(Date::days_in_month(2025, 2), 28);
assert_eq!(Date::days_in_month(2026, 4), 30);
assert_eq!(Date::days_in_month(2026, 7), 31);Sourcepub fn day_of_week(self) -> Weekday
pub fn day_of_week(self) -> Weekday
Returns the day of the week for self.
Computed by reducing the Hinnant civil-day count modulo 7 (the civil epoch 1970-01-01 was a Thursday).
§Examples
use regit_daycount::{Date, Weekday};
assert_eq!(Date::ymd(2026, 5, 23).unwrap().day_of_week(), Weekday::Sat);
assert_eq!(Date::ymd(2000, 1, 1).unwrap().day_of_week(), Weekday::Sat);
assert_eq!(Date::ymd(2024, 12, 25).unwrap().day_of_week(), Weekday::Wed);Sourcepub fn add_days(self, days: i32) -> Self
pub fn add_days(self, days: i32) -> Self
Returns self advanced by days calendar days (negative goes back).
Implemented by converting self to its Hinnant civil-day count,
adding days, and converting back. The intermediate arithmetic is
i64, so a 32-bit days cannot overflow. The result is constructed
via Self::ymd_unchecked and is not re-validated against the
[1583, 9999] window — arithmetic that escapes that window is the
caller’s responsibility.
§Examples
use regit_daycount::Date;
// Plain forward step into the next month.
assert_eq!(
Date::ymd(2026, 1, 1).unwrap().add_days(31),
Date::ymd(2026, 2, 1).unwrap(),
);
// Leap-year boundary.
assert_eq!(
Date::ymd(2024, 2, 28).unwrap().add_days(1),
Date::ymd(2024, 2, 29).unwrap(),
);Sourcepub fn add_months_eom_aware(self, months: i32) -> Self
pub fn add_months_eom_aware(self, months: i32) -> Self
Returns self advanced by months months, clamping the day of the
month to the last day of the resulting month when the original day
does not exist there.
The rule is: compute the new year and month from (self.year * 12 + self.month - 1) + months, then set the day to min(self.day, days_in_month(new_year, new_month)). So 2026-01-31 + 1 month = 2026-02-28 (not a leap year) and 2024-01-31 + 1 month = 2024-02-29 (leap year).
The result is constructed via Self::ymd_unchecked and is not
re-validated against the [1583, 9999] window.
§Examples
use regit_daycount::Date;
assert_eq!(
Date::ymd(2026, 1, 31).unwrap().add_months_eom_aware(1),
Date::ymd(2026, 2, 28).unwrap(),
);
assert_eq!(
Date::ymd(2024, 1, 31).unwrap().add_months_eom_aware(1),
Date::ymd(2024, 2, 29).unwrap(),
);Sourcepub fn nth_weekday_of_month(
year: i32,
month: u8,
n: u8,
weekday: Weekday,
) -> Result<Self, ValidationError>
pub fn nth_weekday_of_month( year: i32, month: u8, n: u8, weekday: Weekday, ) -> Result<Self, ValidationError>
Returns the date of the n-th occurrence of weekday in
(year, month).
n = 1 is the first occurrence, n = 5 is the fifth (if it
exists). Computed by finding the first occurrence of weekday in
the month and adding (n - 1) * 7 days.
§Errors
ValidationError::OutOfRangewithwhat = "n must be 1..=5"ifnis not in1..=5.ValidationError::InvalidDatewithrule = "month-out-of-range"ifmonthis not in1..=12.ValidationError::OutOfRangewithwhat = "year < 1583"/"year > 9999"if the year is outside the supported range.ValidationError::OutOfRangewithwhat = "nth weekday does not exist in this month"if the computed date would fall after the last day of the month (e.g. the 5th Monday of a 28-day February).
§Examples
use regit_daycount::{Date, Weekday};
// The 3rd Friday of June 2026 is 2026-06-19.
assert_eq!(
Date::nth_weekday_of_month(2026, 6, 3, Weekday::Fri).unwrap(),
Date::ymd(2026, 6, 19).unwrap(),
);Sourcepub fn easter_sunday(year: i32) -> Self
pub fn easter_sunday(year: i32) -> Self
Returns the date of Easter Sunday in the (Western, Gregorian) year
year.
Implemented by the Anonymous Gregorian / Computus algorithm (Meeus / Butcher form): a closed-form integer-only computation that is exact for every Gregorian year. See Jean Meeus, Astronomical Algorithms (2nd ed., 1998), §8 — “The date of Easter”.
The TARGET2 holiday rule derives Good Friday and Easter Monday from this date.
§Examples
use regit_daycount::Date;
// Easter Sunday 2026 falls on 5 April.
assert_eq!(Date::easter_sunday(2026), Date::ymd(2026, 4, 5).unwrap());Sourcepub fn days_between(self, other: Self) -> i32
pub fn days_between(self, other: Self) -> i32
Returns the signed number of days from self to other.
The convention is end-exclusive, start-inclusive: a one-day interval
[2026-01-01, 2026-01-02) returns 1. Computed by subtracting the
two Hinnant civil-day counts; the result is i32 and fits comfortably
for any pair of dates in the supported year range (the full window
1583–9999 spans roughly 3.1 * 10⁶ days, well inside i32).
§Examples
use regit_daycount::Date;
let a = Date::ymd(2026, 1, 1).unwrap();
let b = Date::ymd(2026, 1, 2).unwrap();
assert_eq!(a.days_between(b), 1);
assert_eq!(b.days_between(a), -1);
assert_eq!(a.days_between(a), 0);