Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion components/calendar/src/cal/abstract_gregorian.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ impl<Y: GregorianYears> DateFieldsResolver for AbstractGregorian<Y> {
#[inline]
fn reference_year_from_month_day(
&self,
_month_code: types::MonthCode,
_month_code: types::ValidMonthCode,
_day: u8,
) -> Result<Self::YearInfo, EcmaReferenceYearError> {
Ok(REFERENCE_YEAR)
Expand Down
98 changes: 35 additions & 63 deletions components/calendar/src/cal/chinese.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::error::{
use crate::options::{DateAddOptions, DateDifferenceOptions};
use crate::options::{DateFromFieldsOptions, Overflow};
use crate::provider::chinese_based::PackedChineseBasedYearInfo;
use crate::types::{MonthCode, MonthInfo};
use crate::types::{MonthInfo, ValidMonthCode};
use crate::AsCalendar;
use crate::{types, Calendar, Date};
use calendrical_calculations::chinese_based::{
Expand All @@ -22,7 +22,6 @@ use calendrical_calculations::chinese_based::{
use calendrical_calculations::rata_die::RataDie;
use icu_locale_core::preferences::extensions::unicode::keywords::CalendarAlgorithm;
use icu_provider::prelude::*;
use tinystr::tinystr;

#[path = "chinese/china_data.rs"]
mod china_data;
Expand Down Expand Up @@ -122,10 +121,11 @@ pub trait Rules: Clone + core::fmt::Debug + crate::cal::scaffold::UnstableSealed
/// [`MissingFieldsStrategy::Ecma`]: crate::options::MissingFieldsStrategy::Ecma
fn ecma_reference_year(
&self,
_month_code: types::MonthCode,
// TODO: Consider accepting ValidMonthCode
_month_code: (u8, bool),
_day: u8,
) -> Result<i32, EcmaReferenceYearError> {
Err(EcmaReferenceYearError::NotEnoughFields)
Err(EcmaReferenceYearError::Unimplemented)
}

/// The debug name for the calendar defined by these [`Rules`].
Expand Down Expand Up @@ -205,12 +205,12 @@ impl Rules for China {

fn ecma_reference_year(
&self,
month_code: types::MonthCode,
month_code: (u8, bool),
day: u8,
) -> Result<i32, EcmaReferenceYearError> {
let (number, is_leap) = month_code.try_parse()?;
let (number, is_leap) = month_code;
// Computed by `generate_reference_years`
Ok(match (number, is_leap, day > 29) {
let extended_year = match (number, is_leap, day > 29) {
(1, false, false) => 1972,
(1, false, true) => 1970,
(1, true, false) => 1898,
Expand Down Expand Up @@ -263,7 +263,8 @@ impl Rules for China {
(12, true, false) => 1878,
(12, true, true) => 1783,
_ => return Err(EcmaReferenceYearError::UnknownMonthCodeForCalendar),
})
};
Ok(extended_year)
}

fn calendar_algorithm(&self) -> Option<CalendarAlgorithm> {
Expand Down Expand Up @@ -386,12 +387,12 @@ impl Rules for Korea {

fn ecma_reference_year(
&self,
month_code: types::MonthCode,
month_code: (u8, bool),
day: u8,
) -> Result<i32, EcmaReferenceYearError> {
let (number, is_leap) = month_code.try_parse()?;
let (number, is_leap) = month_code;
// Computed by `generate_reference_years`
Ok(match (number, is_leap, day > 29) {
let extended_year = match (number, is_leap, day > 29) {
(1, false, false) => 1972,
(1, false, true) => 1970,
(1, true, false) => 1898,
Expand Down Expand Up @@ -444,7 +445,8 @@ impl Rules for Korea {
(12, true, false) => 1878,
(12, true, true) => 1783,
_ => return Err(EcmaReferenceYearError::UnknownMonthCodeForCalendar),
})
};
Ok(extended_year)
}

fn calendar_algorithm(&self) -> Option<CalendarAlgorithm> {
Expand Down Expand Up @@ -577,18 +579,18 @@ impl<R: Rules> DateFieldsResolver for LunarChinese<R> {
#[inline]
fn reference_year_from_month_day(
&self,
month_code: types::MonthCode,
month_code: types::ValidMonthCode,
day: u8,
) -> Result<Self::YearInfo, EcmaReferenceYearError> {
Ok(self
.0
.year_data(self.0.ecma_reference_year(month_code, day)?))
self.0
.ecma_reference_year(month_code.to_tuple(), day)
.map(|y| self.0.year_data(y))
}

fn ordinal_month_from_code(
&self,
year: &Self::YearInfo,
month_code: types::MonthCode,
month_code: types::ValidMonthCode,
options: DateFromFieldsOptions,
) -> Result<u8, MonthCodeError> {
match year.parse_month_code(month_code) {
Expand Down Expand Up @@ -975,25 +977,11 @@ impl LunarChineseYearData {
// ordinally `month 2`, zero-indexed)
// 14 is a sentinel value
let leap_month = self.leap_month().unwrap_or(14);
let code_inner = if leap_month == month {
let valid_month_code = if leap_month == month {
// Month cannot be 1 because a year cannot have a leap month before the first actual month,
// and the maximum num of months ina leap year is 13.
debug_assert!((2..=13).contains(&month));
match month {
2 => tinystr!(4, "M01L"),
3 => tinystr!(4, "M02L"),
4 => tinystr!(4, "M03L"),
5 => tinystr!(4, "M04L"),
6 => tinystr!(4, "M05L"),
7 => tinystr!(4, "M06L"),
8 => tinystr!(4, "M07L"),
9 => tinystr!(4, "M08L"),
10 => tinystr!(4, "M09L"),
11 => tinystr!(4, "M10L"),
12 => tinystr!(4, "M11L"),
13 => tinystr!(4, "M12L"),
_ => tinystr!(4, "und"),
}
ValidMonthCode::new_unchecked(month - 1, true)
} else {
let mut adjusted_ordinal = month;
if month > leap_month {
Expand All @@ -1005,27 +993,14 @@ impl LunarChineseYearData {
adjusted_ordinal -= 1;
}
debug_assert!((1..=12).contains(&adjusted_ordinal));
match adjusted_ordinal {
1 => tinystr!(4, "M01"),
2 => tinystr!(4, "M02"),
3 => tinystr!(4, "M03"),
4 => tinystr!(4, "M04"),
5 => tinystr!(4, "M05"),
6 => tinystr!(4, "M06"),
7 => tinystr!(4, "M07"),
8 => tinystr!(4, "M08"),
9 => tinystr!(4, "M09"),
10 => tinystr!(4, "M10"),
11 => tinystr!(4, "M11"),
12 => tinystr!(4, "M12"),
_ => tinystr!(4, "und"),
}
ValidMonthCode::new_unchecked(adjusted_ordinal, false)
};
let code = MonthCode(code_inner);
let month_code = valid_month_code.to_month_code();
MonthInfo {
ordinal: month,
standard_code: code,
formatting_code: code,
valid_standard_code: valid_month_code,
standard_code: month_code,
formatting_code: month_code,
}
}

Expand Down Expand Up @@ -1056,12 +1031,12 @@ impl LunarChineseYearData {
}

/// Get the ordinal lunar month from a code for chinese-based calendars.
fn parse_month_code(self, code: MonthCode) -> ComputedOrdinalMonth {
fn parse_month_code(self, code: ValidMonthCode) -> ComputedOrdinalMonth {
// 14 is a sentinel value, greater than all other months, for the purpose of computation only;
// it is impossible to actually have 14 months in a year.
let leap_month = self.leap_month().unwrap_or(14);

let Some((unadjusted @ 1..13, leap)) = code.parsed() else {
let (unadjusted @ 1..13, leap) = code.to_tuple() else {
return ComputedOrdinalMonth::NotFound;
};

Expand Down Expand Up @@ -1561,12 +1536,13 @@ mod test {
(13, tinystr!(4, "M12")),
];
for ordinal_code_pair in codes {
let code = MonthCode(ordinal_code_pair.1);
let ordinal = year.parse_month_code(code);
let print_code = ordinal_code_pair.1;
let valid_code = MonthCode(ordinal_code_pair.1).validated().unwrap();
let ordinal = year.parse_month_code(valid_code);
assert_eq!(
ordinal,
ComputedOrdinalMonth::Exact(ordinal_code_pair.0),
"Code to ordinal failed for year: {}, code: {code}",
"Code to ordinal failed for year: {}, code: {print_code}",
year.related_iso
);
}
Expand All @@ -1577,10 +1553,6 @@ mod test {
let non_leap_year = 4659;
let leap_year = 4660;
let invalid_codes = [
(non_leap_year, tinystr!(4, "M2")),
(leap_year, tinystr!(4, "M0")),
(non_leap_year, tinystr!(4, "J01")),
(leap_year, tinystr!(4, "3M")),
(non_leap_year, tinystr!(4, "M04L")),
(leap_year, tinystr!(4, "M04L")),
(non_leap_year, tinystr!(4, "M13")),
Expand All @@ -1589,8 +1561,8 @@ mod test {
for (year, code) in invalid_codes {
// construct using ::default() to force recomputation
let year = LunarChinese::new_china().0.year_data(year);
let code = MonthCode(code);
let ordinal = year.parse_month_code(code);
let valid_code = MonthCode(code).validated().unwrap();
let ordinal = year.parse_month_code(valid_code);
assert!(
!matches!(ordinal, ComputedOrdinalMonth::Exact(_)),
"Invalid month code failed for year: {}, code: {code}",
Expand Down Expand Up @@ -1774,7 +1746,7 @@ mod test {
.0
.parse()
.unwrap();
if new_lunar_month == lunar_month.parsed().unwrap().0 {
if new_lunar_month == lunar_month.validated().unwrap().number() {
lunar_month = MonthCode::new_leap(new_lunar_month).unwrap();
} else {
lunar_month = MonthCode::new_normal(new_lunar_month).unwrap();
Expand Down
10 changes: 5 additions & 5 deletions components/calendar/src/cal/coptic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ impl DateFieldsResolver for Coptic {
#[inline]
fn reference_year_from_month_day(
&self,
month_code: types::MonthCode,
month_code: types::ValidMonthCode,
day: u8,
) -> Result<Self::YearInfo, EcmaReferenceYearError> {
Coptic::reference_year_from_month_day(month_code, day)
Expand All @@ -116,10 +116,10 @@ impl DateFieldsResolver for Coptic {
fn ordinal_month_from_code(
&self,
_year: &Self::YearInfo,
month_code: types::MonthCode,
month_code: types::ValidMonthCode,
_options: DateFromFieldsOptions,
) -> Result<u8, MonthCodeError> {
match month_code.try_parse()? {
match month_code.to_tuple() {
(month_number @ 1..=13, false) => Ok(month_number),
_ => Err(MonthCodeError::UnknownMonthCodeForCalendar),
}
Expand All @@ -128,10 +128,10 @@ impl DateFieldsResolver for Coptic {

impl Coptic {
pub(crate) fn reference_year_from_month_day(
month_code: types::MonthCode,
month_code: types::ValidMonthCode,
day: u8,
) -> Result<i32, EcmaReferenceYearError> {
let (ordinal_month, _is_leap) = month_code.try_parse()?;
let ordinal_month = month_code.number();
// December 31, 1972 occurs on 4th month, 22nd day, 1689 AM
let anno_martyrum_year = if ordinal_month < 4 || (ordinal_month == 4 && day <= 22) {
1689
Expand Down
6 changes: 3 additions & 3 deletions components/calendar/src/cal/ethiopian.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ impl DateFieldsResolver for Ethiopian {
#[inline]
fn reference_year_from_month_day(
&self,
month_code: types::MonthCode,
month_code: types::ValidMonthCode,
day: u8,
) -> Result<Self::YearInfo, EcmaReferenceYearError> {
crate::cal::Coptic::reference_year_from_month_day(month_code, day)
Expand All @@ -112,10 +112,10 @@ impl DateFieldsResolver for Ethiopian {
fn ordinal_month_from_code(
&self,
_year: &Self::YearInfo,
month_code: types::MonthCode,
month_code: types::ValidMonthCode,
_options: DateFromFieldsOptions,
) -> Result<u8, MonthCodeError> {
match month_code.try_parse()? {
match month_code.to_tuple() {
(month_number @ 1..=13, false) => Ok(month_number),
_ => Err(MonthCodeError::UnknownMonthCodeForCalendar),
}
Expand Down
Loading
Loading