summaryrefslogtreecommitdiff
path: root/src/date.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/date.rs')
-rw-r--r--src/date.rs47
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 {