Skip to content
Open
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
9 changes: 8 additions & 1 deletion components/calendar/src/cal/abstract_gregorian.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,13 @@ pub(crate) trait GregorianYears: Clone + core::fmt::Debug {
fn extended_from_era_year(&self, era: Option<&[u8]>, year: i32)
-> Result<i32, UnknownEraError>;

fn era_year_from_extended(&self, extended_year: i32, month: u8, day: u8) -> EraYear;
fn era_year_from_extended(
&self,
extended_year: i32,
related_gregorian: i32,
month: u8,
day: u8,
) -> EraYear;

fn calendar_algorithm(&self) -> Option<CalendarAlgorithm> {
None
Expand Down Expand Up @@ -164,6 +170,7 @@ impl<Y: GregorianYears> Calendar for AbstractGregorian<Y> {
fn year_info(&self, date: &Self::DateInner) -> Self::Year {
self.0.era_year_from_extended(
date.year() - Y::EXTENDED_YEAR_OFFSET,
date.year(),
date.month(),
date.day(),
)
Expand Down
9 changes: 8 additions & 1 deletion components/calendar/src/cal/buddhist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,18 @@ impl GregorianYears for BuddhistEra {
}
}

fn era_year_from_extended(&self, extended_year: i32, _month: u8, _day: u8) -> types::EraYear {
fn era_year_from_extended(
&self,
extended_year: i32,
related_gregorian: i32,
_month: u8,
_day: u8,
) -> types::EraYear {
types::EraYear {
era: tinystr!(16, "be"),
era_index: Some(0),
year: extended_year,
related_gregorian,
extended_year,
ambiguity: types::YearAmbiguity::CenturyRequired,
}
Expand Down
42 changes: 42 additions & 0 deletions components/calendar/src/cal/coptic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,15 @@ impl Calendar for Coptic {

fn year_info(&self, date: &Self::DateInner) -> Self::Year {
let year = date.0.year();
let related_gregorian = calendrical_calculations::gregorian::year_from_fixed(
calendrical_calculations::coptic::fixed_from_coptic(year, 1, 1),
)
.unwrap_or_else(|e| e.saturate());
types::EraYear {
era: tinystr!(16, "am"),
era_index: Some(0),
year,
related_gregorian,
extended_year: year,
ambiguity: types::YearAmbiguity::CenturyRequired,
}
Expand Down Expand Up @@ -289,4 +294,41 @@ mod tests {
let date = Date::try_from_fields(fields, options, Coptic).unwrap();
assert_eq!(date.day_of_month().0, 6, "Day was successfully constrained");
}

#[test]
fn related_gregorian() {
assert_eq!(
Date::try_new_gregorian(2025, 8, 18)
.unwrap()
.to_calendar(Coptic)
.era_year()
.related_gregorian,
2024
);
assert_eq!(
Date::try_new_gregorian(2025, 9, 18)
.unwrap()
.to_calendar(Coptic)
.era_year()
.related_gregorian,
2025
);

// By 16702 the Coptic calendar is a full year ahead
// of the Gregorian calendar
assert_eq!(
Date::try_new_coptic(16419, 1, 1)
.unwrap()
.era_year()
.related_gregorian,
16702
);
assert_eq!(
Date::try_new_coptic(16420, 1, 1)
.unwrap()
.era_year()
.related_gregorian,
16704
);
}
}
49 changes: 44 additions & 5 deletions components/calendar/src/cal/ethiopian.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,26 +207,28 @@ impl Calendar for Ethiopian {
}

fn year_info(&self, date: &Self::DateInner) -> Self::Year {
let coptic_year = date.0 .0.year();
let coptic_year = Coptic.year_info(&date.0);
let extended_year = if self.0 == EthiopianEraStyle::AmeteAlem {
coptic_year - AMETE_ALEM_OFFSET
coptic_year.extended_year - AMETE_ALEM_OFFSET
} else {
coptic_year - AMETE_MIHRET_OFFSET
coptic_year.extended_year - AMETE_MIHRET_OFFSET
};

if self.0 == EthiopianEraStyle::AmeteAlem || extended_year <= 0 {
types::EraYear {
era: tinystr!(16, "aa"),
era_index: Some(0),
year: coptic_year - AMETE_ALEM_OFFSET,
year: coptic_year.year - AMETE_ALEM_OFFSET,
related_gregorian: coptic_year.related_gregorian,
extended_year,
ambiguity: types::YearAmbiguity::CenturyRequired,
}
} else {
types::EraYear {
era: tinystr!(16, "am"),
era_index: Some(1),
year: coptic_year - AMETE_MIHRET_OFFSET,
year: coptic_year.year - AMETE_MIHRET_OFFSET,
related_gregorian: coptic_year.related_gregorian,
extended_year,
ambiguity: types::YearAmbiguity::CenturyRequired,
}
Expand Down Expand Up @@ -390,4 +392,41 @@ mod test {
1
);
}

#[test]
fn related_gregorian() {
assert_eq!(
Date::try_new_gregorian(2025, 8, 18)
.unwrap()
.to_calendar(Ethiopian::new())
.era_year()
.related_gregorian,
2024
);
assert_eq!(
Date::try_new_gregorian(2025, 9, 18)
.unwrap()
.to_calendar(Ethiopian::new())
.era_year()
.related_gregorian,
2025
);

// By 16702 the Ethiopian calendar is a full year ahead
// of the Gregorian calendar
assert_eq!(
Date::try_new_ethiopian(EthiopianEraStyle::AmeteMihret, 16695, 1, 1)
.unwrap()
.era_year()
.related_gregorian,
16702
);
assert_eq!(
Date::try_new_ethiopian(EthiopianEraStyle::AmeteMihret, 16696, 1, 1)
.unwrap()
.era_year()
.related_gregorian,
16704
);
}
}
10 changes: 9 additions & 1 deletion components/calendar/src/cal/gregorian.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,19 @@ impl GregorianYears for CeBce {
}
}

fn era_year_from_extended(&self, extended_year: i32, _month: u8, _day: u8) -> types::EraYear {
fn era_year_from_extended(
&self,
extended_year: i32,
related_gregorian: i32,
_month: u8,
_day: u8,
) -> types::EraYear {
if extended_year > 0 {
types::EraYear {
era: tinystr!(16, "ce"),
era_index: Some(1),
year: extended_year,
related_gregorian,
extended_year,
ambiguity: match extended_year {
..=999 => types::YearAmbiguity::EraAndCenturyRequired,
Expand All @@ -49,6 +56,7 @@ impl GregorianYears for CeBce {
era: tinystr!(16, "bce"),
era_index: Some(0),
year: 1 - extended_year,
related_gregorian,
extended_year,
ambiguity: types::YearAmbiguity::EraAndCenturyRequired,
}
Expand Down
41 changes: 41 additions & 0 deletions components/calendar/src/cal/hebrew.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,10 +316,14 @@ impl Calendar for Hebrew {

fn year_info(&self, date: &Self::DateInner) -> Self::Year {
let extended_year = date.0.year().value;
let related_gregorian =
calendrical_calculations::gregorian::year_from_fixed(date.0.year().new_year())
.unwrap_or_else(|e| e.saturate());
types::EraYear {
era_index: Some(0),
era: tinystr!(16, "am"),
year: extended_year,
related_gregorian,
extended_year,
ambiguity: types::YearAmbiguity::CenturyRequired,
}
Expand Down Expand Up @@ -524,4 +528,41 @@ mod tests {
// https://www.hebcal.com/converter?hd=1&hm=Tishrei&hy=3760&h2g=1
assert_eq!(dt.weekday(), Weekday::Saturday);
}

#[test]
fn related_gregorian() {
assert_eq!(
Date::try_new_gregorian(2025, 9, 18)
.unwrap()
.to_calendar(Hebrew)
.era_year()
.related_gregorian,
2024
);
assert_eq!(
Date::try_new_gregorian(2025, 10, 18)
.unwrap()
.to_calendar(Hebrew)
.era_year()
.related_gregorian,
2025
);

// By 22203 the Hebrew calendar is a full year ahead
// of the Gregorian calendar
assert_eq!(
Date::try_new_from_codes(None, 25962, TISHREI.code(), 1, Hebrew)
.unwrap()
.era_year()
.related_gregorian,
22201
);
assert_eq!(
Date::try_new_from_codes(None, 25963, TISHREI.code(), 1, Hebrew)
.unwrap()
.era_year()
.related_gregorian,
22203
);
}
}
25 changes: 25 additions & 0 deletions components/calendar/src/cal/hijri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -911,11 +911,15 @@ impl<R: Rules> Calendar for Hijri<R> {

fn year_info(&self, date: &Self::DateInner) -> Self::Year {
let extended_year = date.0.year().extended_year;
let related_gregorian =
calendrical_calculations::gregorian::year_from_fixed(date.0.year().new_year())
.unwrap_or_else(|e| e.saturate());
if extended_year > 0 {
types::EraYear {
era: tinystr!(16, "ah"),
era_index: Some(0),
year: extended_year,
related_gregorian,
extended_year,
ambiguity: types::YearAmbiguity::CenturyRequired,
}
Expand All @@ -925,6 +929,7 @@ impl<R: Rules> Calendar for Hijri<R> {
era_index: Some(1),
year: 1 - extended_year,
extended_year,
related_gregorian,
ambiguity: types::YearAmbiguity::CenturyRequired,
}
}
Expand Down Expand Up @@ -1951,4 +1956,24 @@ mod test {
single_roundtrip(mixed2, start_1600 - 1).unwrap();
single_roundtrip(mixed2, start_1600 - 4).unwrap();
}

#[test]
fn related_gregorian() {
assert_eq!(
Date::try_new_gregorian(2025, 6, 18)
.unwrap()
.to_calendar(Hijri::new_umm_al_qura())
.era_year()
.related_gregorian,
2024
);
assert_eq!(
Date::try_new_gregorian(2025, 7, 18)
.unwrap()
.to_calendar(Hijri::new_umm_al_qura())
.era_year()
.related_gregorian,
2025
);
}
}
21 changes: 21 additions & 0 deletions components/calendar/src/cal/indian.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ impl Calendar for Indian {
era: tinystr!(16, "shaka"),
year: extended_year,
extended_year,
related_gregorian: extended_year + YEAR_OFFSET + 1,
ambiguity: types::YearAmbiguity::CenturyRequired,
}
}
Expand Down Expand Up @@ -544,4 +545,24 @@ mod tests {
}
}
}

#[test]
fn related_gregorian() {
assert_eq!(
Date::try_new_gregorian(2025, 3, 18)
.unwrap()
.to_calendar(Indian)
.era_year()
.related_gregorian,
2025
);
assert_eq!(
Date::try_new_gregorian(2025, 4, 18)
.unwrap()
.to_calendar(Indian)
.era_year()
.related_gregorian,
2026
);
}
}
9 changes: 8 additions & 1 deletion components/calendar/src/cal/iso.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,18 @@ impl GregorianYears for IsoEra {
}
}

fn era_year_from_extended(&self, extended_year: i32, _month: u8, _day: u8) -> types::EraYear {
fn era_year_from_extended(
&self,
extended_year: i32,
related_gregorian: i32,
_month: u8,
_day: u8,
) -> types::EraYear {
types::EraYear {
era_index: Some(0),
era: tinystr!(16, "default"),
year: extended_year,
related_gregorian,
extended_year,
ambiguity: types::YearAmbiguity::Unambiguous,
}
Expand Down
11 changes: 9 additions & 2 deletions components/calendar/src/cal/japanese.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,13 @@ impl GregorianYears for &'_ Japanese {
Ok(era_start.year + year - 1)
}

fn era_year_from_extended(&self, year: i32, month: u8, day: u8) -> types::EraYear {
fn era_year_from_extended(
&self,
year: i32,
related_gregorian: i32,
month: u8,
day: u8,
) -> types::EraYear {
let date: EraStartDate = EraStartDate { year, month, day };

let (start, era) = if date >= MEIJI_START
Expand Down Expand Up @@ -255,7 +261,7 @@ impl GregorianYears for &'_ Japanese {
return types::EraYear {
// TODO: return era indices?
era_index: None,
..CeBce.era_year_from_extended(year, month, day)
..CeBce.era_year_from_extended(year, related_gregorian, month, day)
};
}
Ok(index) => data.get(index).unwrap(),
Expand All @@ -267,6 +273,7 @@ impl GregorianYears for &'_ Japanese {
era,
era_index: None,
year: year - start.year + 1,
related_gregorian,
extended_year: year,
ambiguity: types::YearAmbiguity::CenturyRequired,
}
Expand Down
Loading
Loading