diff options
Diffstat (limited to 'src/date.rs')
| -rw-r--r-- | src/date.rs | 47 |
1 files changed, 40 insertions, 7 deletions
diff --git a/src/date.rs b/src/date.rs index 49a7642..194fd02 100644 --- a/src/date.rs +++ b/src/date.rs @@ -12,12 +12,10 @@ pub struct Date { impl Date { /// The earliest date which can be represented - pub const MIN: Self = - unsafe { Self::from_calendar_date_unchecked(Year::MIN, Month::January, 1) }; + pub const MIN: Self = unsafe { Self::from_ymd_unchecked(Year::MIN, Month::January, 1) }; /// The latest date which can be represented - pub const MAX: Self = - unsafe { Self::from_calendar_date_unchecked(Year::MAX, Month::December, 31) }; + pub const MAX: Self = unsafe { Self::from_ymd_unchecked(Year::MAX, Month::December, 31) }; // TODO validated from_calendar_date @@ -26,17 +24,17 @@ impl Date { /// # Example /// /// ``` - /// use botic::Date; + /// use botic::{Date, Month, Year}; /// /// let y2k = unsafe { - /// Date::from_calendar_date_unchecked(Year::from(2000), Month::January, 1) + /// Date::from_ymd_unchecked(Year::from(2000), Month::January, 1) /// }; /// ``` /// /// # Safety /// /// This function results in undefined behavior if the given date is not a real date - pub const unsafe fn from_calendar_date_unchecked(year: Year, month: Month, day: u8) -> Self { + pub const unsafe fn from_ymd_unchecked(year: Year, month: Month, day: u8) -> Self { Self { year, month, day } } @@ -53,6 +51,41 @@ impl Date { pub const fn day(self) -> u8 { self.day } + + pub const fn is_leap_year(self) -> bool { + self.year.is_leap_year() + } + + // TODO handle BCE properly + pub const fn days_after_common_era(self) -> isize { + let year = self.year.wrapping_sub(1); + let leap_years = (year.as_i16() / 4 - year.as_i16() / 100 + year.as_i16() / 400) as isize; + let month_last_day_ordinal = self.month.last_day_ordinal(self.is_leap_year()) as isize; + + year.as_i16() as isize * 365 + leap_years + month_last_day_ordinal + self.day as isize - 1 + } + + // TODO test + pub const fn from_days_after_common_era(days: isize) -> Self { + let era = days / 146097; // an era is a period of 400 year + let day_of_era = days - (era * 146097); + let year_of_era = day_of_era / 365; + let year = year_of_era + (era * 400); + let ordinal = day_of_era - (365 * year + year / 4 - year / 100); + // TODO look at as's + let year = Year::from_i16(year as i16); + let month = Month::from_ordinal(ordinal as u16, year.is_leap_year()); + let day = ordinal as u16 - month.previous().last_day_ordinal(year.is_leap_year()); + let day = day as u8; + + unsafe { Self::from_ymd_unchecked(year, month, day) } + } + + #[must_use] + pub const fn add_days(self, days: isize) -> Self { + let total_days_since_ce = self.days_after_common_era() + days; + Self::from_days_after_common_era(total_days_since_ce) + } } impl PartialOrd for Date { |
