Skip to content

Commit

Permalink
Improve FormattableYear
Browse files Browse the repository at this point in the history
  • Loading branch information
Manishearth committed Sep 6, 2024
1 parent 901390e commit 02def68
Show file tree
Hide file tree
Showing 24 changed files with 343 additions and 321 deletions.
7 changes: 4 additions & 3 deletions components/calendar/src/any_calendar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -508,11 +508,12 @@ impl Calendar for AnyCalendar {
}
}

/// The calendar-specific year represented by `date`
fn year(&self, date: &Self::DateInner) -> types::FormattableYear {
fn year(&self, date: &Self::DateInner) -> types::YearInfo {
match_cal_and_date!(match (self, date): (c, d) => c.year(d))
}

fn formattable_year(&self, date: &Self::DateInner) -> types::FormattableYear {
match_cal_and_date!(match (self, date): (c, d) => c.formattable_year(d))
}
/// The calendar-specific check if `date` is in a leap year
fn is_in_leap_year(&self, date: &Self::DateInner) -> bool {
match_cal_and_date!(match (self, date): (c, d) => c.is_in_leap_year(d))
Expand Down
20 changes: 10 additions & 10 deletions components/calendar/src/buddhist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,15 @@ impl Calendar for Buddhist {
}

/// The calendar-specific year represented by `date`
fn year(&self, date: &Self::DateInner) -> types::FormattableYear {
fn year(&self, date: &Self::DateInner) -> types::YearInfo {
iso_year_as_buddhist(date.0.year)
}

/// The calendar-specific year represented by `date`
fn formattable_year(&self, date: &Self::DateInner) -> types::FormattableYear {
iso_year_as_buddhist(date.0.year).into()
}

fn is_in_leap_year(&self, date: &Self::DateInner) -> bool {
Iso.is_in_leap_year(date)
}
Expand All @@ -144,9 +149,9 @@ impl Calendar for Buddhist {
types::DayOfYearInfo {
day_of_year: Iso::day_of_year(*date),
days_in_year: Iso::days_in_year_direct(date.0.year),
prev_year: iso_year_as_buddhist(prev_year),
prev_year: iso_year_as_buddhist(prev_year).into(),
days_in_prev_year: Iso::days_in_year_direct(prev_year),
next_year: iso_year_as_buddhist(next_year),
next_year: iso_year_as_buddhist(next_year).into(),
}
}

Expand Down Expand Up @@ -218,14 +223,9 @@ impl DateTime<Buddhist> {
}
}

fn iso_year_as_buddhist(year: i32) -> types::FormattableYear {
fn iso_year_as_buddhist(year: i32) -> types::YearInfo {
let buddhist_year = year + BUDDHIST_ERA_OFFSET;
types::FormattableYear {
era: types::Era(tinystr!(16, "be")),
number: buddhist_year,
cyclic: None,
related_iso: None,
}
types::YearInfo::new(buddhist_year, tinystr!(16, "be"), buddhist_year)
}

#[cfg(test)]
Expand Down
7 changes: 5 additions & 2 deletions components/calendar/src/calendar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,11 @@ pub trait Calendar {
fn debug_name(&self) -> &'static str;
// fn since(&self, from: &Date<Self>, to: &Date<Self>) -> Duration<Self>, Error;

/// The calendar-specific year represented by `date`
fn year(&self, date: &Self::DateInner) -> types::FormattableYear;
/// Information about the year
fn year(&self, date: &Self::DateInner) -> types::YearInfo;

/// Information about the calendar-specific year as needed for formatting
fn formattable_year(&self, date: &Self::DateInner) -> types::FormattableYear;

/// Calculate if a date is in a leap year
fn is_in_leap_year(&self, date: &Self::DateInner) -> bool;
Expand Down
52 changes: 20 additions & 32 deletions components/calendar/src/chinese.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,13 @@
//!
//! // `Date` checks
//! assert_eq!(chinese_date.year().number, 4660);
//! assert_eq!(chinese_date.year().related_iso, Some(2023));
//! assert_eq!(chinese_date.year().cyclic.unwrap().get(), 40);
//! assert_eq!(chinese_date.formattable_year().cyclic().unwrap().get(), 40);
//! assert_eq!(chinese_date.month().ordinal, 6);
//! assert_eq!(chinese_date.day_of_month().0, 6);
//!
//! // `DateTime` checks
//! assert_eq!(chinese_datetime.date.year().number, 4660);
//! assert_eq!(chinese_datetime.date.year().related_iso, Some(2023));
//! assert_eq!(chinese_datetime.date.year().cyclic.unwrap().get(), 40);
//! assert_eq!(chinese_datetime.date.formattable_year().cyclic().unwrap().get(), 40);
//! assert_eq!(chinese_datetime.date.month().ordinal, 6);
//! assert_eq!(chinese_datetime.date.day_of_month().0, 6);
//! assert_eq!(chinese_datetime.time.hour.number(), 13);
Expand All @@ -48,7 +46,7 @@ use crate::chinese_based::{
use crate::error::DateError;
use crate::iso::Iso;
use crate::provider::chinese_based::ChineseCacheV1Marker;
use crate::types::{Era, FormattableYear};
use crate::types::FormattableYear;
use crate::AsCalendar;
use crate::{types, Calendar, Date, DateDuration, DateDurationUnit, DateTime, Time};
use core::cmp::Ordering;
Expand Down Expand Up @@ -268,8 +266,11 @@ impl Calendar for Chinese {
Self::DEBUG_NAME
}

/// The calendar-specific year represented by `date`
fn year(&self, date: &Self::DateInner) -> types::FormattableYear {
fn year(&self, date: &Self::DateInner) -> types::YearInfo {
types::YearInfo::new(date.0 .0.year, tinystr!(16, "chinese"), date.0 .0.year)
}

fn formattable_year(&self, date: &Self::DateInner) -> types::FormattableYear {
Self::format_chinese_year(date.0 .0.year, Some(date.0 .0.year_info))
}

Expand Down Expand Up @@ -331,8 +332,8 @@ impl<A: AsCalendar<Calendar = Chinese>> Date<A> {
/// .expect("Failed to initialize Chinese Date instance.");
///
/// assert_eq!(date_chinese.year().number, 4660);
/// assert_eq!(date_chinese.year().cyclic.unwrap().get(), 40);
/// assert_eq!(date_chinese.year().related_iso, Some(2023));
/// assert_eq!(date_chinese.formattable_year().cyclic().unwrap().get(), 40);
/// assert_eq!(date_chinese.formattable_year().related_iso(), Some(2023));
/// assert_eq!(date_chinese.month().ordinal, 6);
/// assert_eq!(date_chinese.day_of_month().0, 11);
/// ```
Expand Down Expand Up @@ -372,8 +373,7 @@ impl<A: AsCalendar<Calendar = Chinese>> DateTime<A> {
/// .expect("Failed to initialize Chinese DateTime instance.");
///
/// assert_eq!(chinese_datetime.date.year().number, 4660);
/// assert_eq!(chinese_datetime.date.year().related_iso, Some(2023));
/// assert_eq!(chinese_datetime.date.year().cyclic.unwrap().get(), 40);
/// assert_eq!(chinese_datetime.date.formattable_year().cyclic().unwrap().get(), 40);
/// assert_eq!(chinese_datetime.date.month().ordinal, 6);
/// assert_eq!(chinese_datetime.date.day_of_month().0, 11);
/// assert_eq!(chinese_datetime.time.hour.number(), 13);
Expand Down Expand Up @@ -407,32 +407,20 @@ impl ChineseBasedWithDataLoading for Chinese {
impl Chinese {
/// Get a FormattableYear from an integer Chinese year; optionally, a `ChineseBasedYearInfo`
/// can be passed in for faster results.
///
/// `era` is always `Era(tinystr!(16, "chinese"))`
/// `number` is the year since the inception of the Chinese calendar (see [`Chinese`])
/// `cyclic` is an option with the current year in the sexagesimal cycle (see [`Chinese`])
/// `related_iso` is the ISO year in which the given Chinese year begins (see [`Chinese`])
fn format_chinese_year(
year: i32,
year_info_option: Option<ChineseBasedYearInfo>,
) -> FormattableYear {
let era = Era(tinystr!(16, "chinese"));
let number = year;
let cyclic = (number - 1).rem_euclid(60) as u8;
let cyclic = NonZeroU8::new(cyclic + 1); // 1-indexed
let cyclic = (year - 1).rem_euclid(60) as u8;
let cyclic = NonZeroU8::new(cyclic + 1).unwrap_or(NonZeroU8::MIN); // 1-indexed
let rata_die_in_year = if let Some(info) = year_info_option {
info.new_year::<ChineseCB>(year)
} else {
Inner::fixed_mid_year_from_year(number)
Inner::fixed_mid_year_from_year(year)
};
let iso_formattable_year = Iso::iso_from_fixed(rata_die_in_year).year();
let related_iso = Some(iso_formattable_year.number);
types::FormattableYear {
era,
number,
cyclic,
related_iso,
}
let related_iso = iso_formattable_year.number;
types::FormattableYear::new_cyclic(year, cyclic, related_iso)
}
}

Expand Down Expand Up @@ -666,8 +654,8 @@ mod test {
assert_eq!(chinese.month().ordinal, 1);
assert_eq!(chinese.month().code.0, "M01");
assert_eq!(chinese.day_of_month().0, 1);
assert_eq!(chinese.year().cyclic.unwrap().get(), 1);
assert_eq!(chinese.year().related_iso, Some(-2636));
assert_eq!(chinese.formattable_year().cyclic().unwrap().get(), 1);
assert_eq!(chinese.formattable_year().related_iso(), Some(-2636));
},
)
}
Expand Down Expand Up @@ -1113,8 +1101,8 @@ mod test {
&chinese_cached,
|chinese, calendar_type| {
let chinese = iso.to_calendar(chinese);
let chinese_rel_iso = chinese.year().related_iso;
let chinese_cyclic = chinese.year().cyclic;
let chinese_rel_iso = chinese.formattable_year().related_iso();
let chinese_cyclic = chinese.formattable_year().cyclic();
let chinese_month = chinese.month().ordinal;
let chinese_day = chinese.day_of_month().0;

Expand Down
3 changes: 1 addition & 2 deletions components/calendar/src/chinese_based.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
//! let chinese_date = Date::new_from_iso(iso_date, Chinese::new());
//!
//! assert_eq!(chinese_date.year().number, 4660);
//! assert_eq!(chinese_date.year().related_iso, Some(2023));
//! assert_eq!(chinese_date.year().cyclic.unwrap().get(), 40);
//! assert_eq!(chinese_date.formattable_year().cyclic().unwrap().get(), 40);
//! assert_eq!(chinese_date.month().ordinal, 6);
//! assert_eq!(chinese_date.day_of_month().0, 6);
//! ```
Expand Down
27 changes: 10 additions & 17 deletions components/calendar/src/coptic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,14 @@ impl Calendar for Coptic {
date1.0.until(date2.0, _largest_unit, _smallest_unit)
}

fn year(&self, date: &Self::DateInner) -> types::FormattableYear {
fn year(&self, date: &Self::DateInner) -> types::YearInfo {
year_as_coptic(date.0.year)
}

fn formattable_year(&self, date: &Self::DateInner) -> types::FormattableYear {
year_as_coptic(date.0.year).into()
}

fn is_in_leap_year(&self, date: &Self::DateInner) -> bool {
Self::is_leap_year(date.0.year, ())
}
Expand All @@ -206,9 +210,9 @@ impl Calendar for Coptic {
types::DayOfYearInfo {
day_of_year: date.0.day_of_year(),
days_in_year: date.0.days_in_year(),
prev_year: year_as_coptic(prev_year),
prev_year: year_as_coptic(prev_year).into(),
days_in_prev_year: Coptic::days_in_year_direct(prev_year),
next_year: year_as_coptic(next_year),
next_year: year_as_coptic(next_year).into(),
}
}

Expand Down Expand Up @@ -301,24 +305,13 @@ impl DateTime<Coptic> {
}
}

fn year_as_coptic(year: i32) -> types::FormattableYear {
fn year_as_coptic(year: i32) -> types::YearInfo {
if year > 0 {
types::FormattableYear {
era: types::Era(tinystr!(16, "ad")),
number: year,
cyclic: None,
related_iso: None,
}
types::YearInfo::new(year, tinystr!(16, "ad"), year)
} else {
types::FormattableYear {
era: types::Era(tinystr!(16, "bd")),
number: 1 - year,
cyclic: None,
related_iso: None,
}
types::YearInfo::new(year, tinystr!(16, "bd"), 1 - year)
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
48 changes: 20 additions & 28 deletions components/calendar/src/dangi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,13 @@
//!
//! // `Date` checks
//! assert_eq!(dangi_date.year().number, 4356);
//! assert_eq!(dangi_date.year().related_iso, Some(2023));
//! assert_eq!(dangi_date.year().cyclic.unwrap().get(), 40);
//! assert_eq!(dangi_date.formattable_year().cyclic().unwrap().get(), 40);
//! assert_eq!(dangi_date.month().ordinal, 6);
//! assert_eq!(dangi_date.day_of_month().0, 6);
//!
//! // `DateTime` checks
//! assert_eq!(dangi_datetime.date.year().number, 4356);
//! assert_eq!(dangi_datetime.date.year().related_iso, Some(2023));
//! assert_eq!(dangi_datetime.date.year().cyclic.unwrap().get(), 40);
//! assert_eq!(dangi_datetime.date.formattable_year().cyclic().unwrap().get(), 40);
//! assert_eq!(dangi_datetime.date.month().ordinal, 6);
//! assert_eq!(dangi_datetime.date.day_of_month().0, 6);
//! assert_eq!(dangi_datetime.time.hour.number(), 13);
Expand All @@ -50,7 +48,7 @@ use crate::provider::chinese_based::DangiCacheV1Marker;
use crate::AsCalendar;
use crate::{
chinese_based::ChineseBasedDateInner,
types::{self, Era, FormattableYear},
types::{self, FormattableYear},
Calendar, Date, DateTime, Iso, Time,
};
use core::cmp::Ordering;
Expand Down Expand Up @@ -252,7 +250,10 @@ impl Calendar for Dangi {
Self::DEBUG_NAME
}

fn year(&self, date: &Self::DateInner) -> crate::types::FormattableYear {
fn year(&self, date: &Self::DateInner) -> crate::types::YearInfo {
types::YearInfo::new(date.0 .0.year, tinystr!(16, "dangi"), date.0 .0.year)
}
fn formattable_year(&self, date: &Self::DateInner) -> crate::types::FormattableYear {
Self::format_dangi_year(date.0 .0.year, Some(date.0 .0.year_info))
}

Expand Down Expand Up @@ -308,8 +309,7 @@ impl<A: AsCalendar<Calendar = Dangi>> Date<A> {
/// .expect("Failed to initialize Dangi Date instance.");
///
/// assert_eq!(date_dangi.year().number, 4356);
/// assert_eq!(date_dangi.year().cyclic.unwrap().get(), 40);
/// assert_eq!(date_dangi.year().related_iso, Some(2023));
/// assert_eq!(date_dangi.formattable_year().cyclic().unwrap().get(), 40);
/// assert_eq!(date_dangi.month().ordinal, 6);
/// assert_eq!(date_dangi.day_of_month().0, 18);
/// ```
Expand Down Expand Up @@ -349,8 +349,7 @@ impl<A: AsCalendar<Calendar = Dangi>> DateTime<A> {
/// .expect("Failed to initialize Dangi DateTime instance.");
///
/// assert_eq!(dangi_datetime.date.year().number, 4356);
/// assert_eq!(dangi_datetime.date.year().related_iso, Some(2023));
/// assert_eq!(dangi_datetime.date.year().cyclic.unwrap().get(), 40);
/// assert_eq!(dangi_datetime.date.formattable_year().cyclic().unwrap().get(), 40);
/// assert_eq!(dangi_datetime.date.month().ordinal, 6);
/// assert_eq!(dangi_datetime.date.day_of_month().0, 6);
/// assert_eq!(dangi_datetime.time.hour.number(), 13);
Expand Down Expand Up @@ -388,24 +387,17 @@ impl Dangi {
year: i32,
year_info_option: Option<ChineseBasedYearInfo>,
) -> FormattableYear {
let era = Era(tinystr!(16, "dangi"));
let number = year;
// constant 364 from https://github.com/EdReingold/calendar-code2/blob/main/calendar.l#L5704
let cyclic = (number as i64 - 1 + 364).rem_euclid(60) as u8;
let cyclic = NonZeroU8::new(cyclic + 1); // 1-indexed
let cyclic = (year as i64 - 1 + 364).rem_euclid(60) as u8;
let cyclic = NonZeroU8::new(cyclic + 1).unwrap_or(NonZeroU8::MIN); // 1-indexed
let rata_die_in_year = if let Some(info) = year_info_option {
info.new_year::<DangiCB>(year)
} else {
Inner::fixed_mid_year_from_year(number)
Inner::fixed_mid_year_from_year(year)
};
let iso_formattable_year = Iso::iso_from_fixed(rata_die_in_year).year();
let related_iso = Some(iso_formattable_year.number);
types::FormattableYear {
era,
number,
cyclic,
related_iso,
}
let related_iso = iso_formattable_year.number;
types::FormattableYear::new_cyclic(year, cyclic, related_iso)
}
}

Expand All @@ -430,14 +422,14 @@ mod test {
let iso = Date::try_new_iso_date(year, 6, 6).unwrap();
let chinese = iso.to_calendar(Chinese::new_always_calculating());
let dangi = iso.to_calendar(Dangi::new_always_calculating());
let chinese_year = chinese.year().cyclic;
let korean_year = dangi.year().cyclic;
let chinese_year = chinese.formattable_year().cyclic();
let korean_year = dangi.formattable_year().cyclic();
assert_eq!(
chinese_year, korean_year,
"Cyclic year failed for year: {year}"
);
let chinese_rel_iso = chinese.year().related_iso;
let korean_rel_iso = dangi.year().related_iso;
let chinese_rel_iso = chinese.formattable_year().related_iso();
let korean_rel_iso = dangi.formattable_year().related_iso();
assert_eq!(
chinese_rel_iso, korean_rel_iso,
"Rel. ISO year equality failed for year: {year}"
Expand Down Expand Up @@ -998,8 +990,8 @@ mod test {
let iso = Date::try_new_iso_date(case.iso_year, case.iso_month, case.iso_day).unwrap();
do_twice(&dangi_calculating, &dangi_cached, |dangi, calendar_type| {
let dangi = iso.to_calendar(dangi);
let dangi_rel_iso = dangi.year().related_iso;
let dangi_cyclic = dangi.year().cyclic;
let dangi_rel_iso = dangi.formattable_year().related_iso();
let dangi_cyclic = dangi.formattable_year().cyclic();
let dangi_month = dangi.month().ordinal;
let dangi_day = dangi.day_of_month().0;

Expand Down
Loading

0 comments on commit 02def68

Please sign in to comment.