Skip to content

Commit 30866f3

Browse files
Remove CalendarArithmetic trait (#7088)
Most methods on this trait are only called by the calendar's `Calendar` implementation, or are not called at all. Only two methods are used by the from-fields code, which I moved to the `DateFieldsResolver` trait. Not indirecting the logic through 3 intermediate functions allowed for some improvements.
1 parent b98668d commit 30866f3

File tree

11 files changed

+219
-436
lines changed

11 files changed

+219
-436
lines changed

components/calendar/src/cal/abstract_gregorian.rs

Lines changed: 23 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
44

55
use crate::cal::iso::{IsoDateInner, IsoEra};
6-
use crate::calendar_arithmetic::{
7-
ArithmeticDate, ArithmeticDateBuilder, CalendarArithmetic, DateFieldsResolver,
8-
};
6+
use crate::calendar_arithmetic::{ArithmeticDate, ArithmeticDateBuilder, DateFieldsResolver};
97
use crate::error::{DateError, DateFromFieldsError, EcmaReferenceYearError, UnknownEraError};
108
use crate::options::DateFromFieldsOptions;
119
use crate::options::{DateAddOptions, DateDifferenceOptions};
@@ -44,7 +42,15 @@ impl ArithmeticDate<AbstractGregorian<IsoEra>> {
4442
}
4543
}
4644

47-
impl CalendarArithmetic for AbstractGregorian<IsoEra> {
45+
pub(crate) const REFERENCE_YEAR: i32 = 1972;
46+
#[cfg(test)]
47+
pub(crate) const LAST_DAY_OF_REFERENCE_YEAR: RataDie =
48+
calendrical_calculations::gregorian::day_before_year(REFERENCE_YEAR + 1);
49+
50+
impl<Y: GregorianYears> DateFieldsResolver for AbstractGregorian<Y> {
51+
// Gregorian year
52+
type YearInfo = i32;
53+
4854
fn days_in_provided_month(year: i32, month: u8) -> u8 {
4955
// https://www.youtube.com/watch?v=J9KijLyP-yg&t=1394s
5056
if month == 2 {
@@ -58,36 +64,6 @@ impl CalendarArithmetic for AbstractGregorian<IsoEra> {
5864
12
5965
}
6066

61-
fn provided_year_is_leap(year: i32) -> bool {
62-
calendrical_calculations::gregorian::is_leap_year(year)
63-
}
64-
65-
fn last_month_day_in_provided_year(_year: i32) -> (u8, u8) {
66-
(12, 31)
67-
}
68-
69-
fn days_in_provided_year(year: i32) -> u16 {
70-
365 + calendrical_calculations::gregorian::is_leap_year(year) as u16
71-
}
72-
73-
fn day_of_provided_year(year: Self::YearInfo, month: u8, day: u8) -> u16 {
74-
calendrical_calculations::gregorian::days_before_month(year, month) + day as u16
75-
}
76-
77-
fn date_from_provided_year_day(year: Self::YearInfo, year_day: u16) -> (u8, u8) {
78-
calendrical_calculations::gregorian::year_day(year, year_day)
79-
}
80-
}
81-
82-
pub(crate) const REFERENCE_YEAR: i32 = 1972;
83-
#[cfg(test)]
84-
pub(crate) const LAST_DAY_OF_REFERENCE_YEAR: RataDie =
85-
calendrical_calculations::gregorian::day_before_year(REFERENCE_YEAR + 1);
86-
87-
impl<Y: GregorianYears> DateFieldsResolver for AbstractGregorian<Y> {
88-
// Gregorian year
89-
type YearInfo = i32;
90-
9167
#[inline]
9268
fn year_info_from_era(
9369
&self,
@@ -131,8 +107,10 @@ impl<Y: GregorianYears> Calendar for AbstractGregorian<Y> {
131107

132108
fn from_rata_die(&self, date: RataDie) -> Self::DateInner {
133109
let iso = match calendrical_calculations::gregorian::gregorian_from_fixed(date) {
134-
Err(I32CastError::BelowMin) => ArithmeticDate::<AbstractGregorian<IsoEra>>::min_date(),
135-
Err(I32CastError::AboveMax) => ArithmeticDate::max_date(),
110+
Err(I32CastError::BelowMin) => {
111+
ArithmeticDate::<AbstractGregorian<IsoEra>>::new_unchecked(i32::MIN, 1, 1)
112+
}
113+
Err(I32CastError::AboveMax) => ArithmeticDate::new_unchecked(i32::MAX, 12, 31),
136114
Ok((year, month, day)) => ArithmeticDate::new_unchecked(year, month, day),
137115
};
138116

@@ -160,15 +138,15 @@ impl<Y: GregorianYears> Calendar for AbstractGregorian<Y> {
160138
}
161139

162140
fn months_in_year(&self, date: &Self::DateInner) -> u8 {
163-
date.months_in_year()
141+
AbstractGregorian::<IsoEra>::months_in_provided_year(date.year)
164142
}
165143

166144
fn days_in_year(&self, date: &Self::DateInner) -> u16 {
167-
date.days_in_year()
145+
365 + calendrical_calculations::gregorian::is_leap_year(date.year) as u16
168146
}
169147

170148
fn days_in_month(&self, date: &Self::DateInner) -> u8 {
171-
date.days_in_month()
149+
AbstractGregorian::<IsoEra>::days_in_provided_month(date.year, date.month)
172150
}
173151

174152
fn add(
@@ -195,19 +173,22 @@ impl<Y: GregorianYears> Calendar for AbstractGregorian<Y> {
195173
}
196174

197175
fn is_in_leap_year(&self, date: &Self::DateInner) -> bool {
198-
AbstractGregorian::<IsoEra>::provided_year_is_leap(date.year)
176+
calendrical_calculations::gregorian::is_leap_year(date.year)
199177
}
200178

201179
fn month(&self, date: &Self::DateInner) -> types::MonthInfo {
202180
self.month_code_from_ordinal(&date.year, date.month)
203181
}
204182

205183
fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth {
206-
date.day_of_month()
184+
types::DayOfMonth(date.day)
207185
}
208186

209187
fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear {
210-
date.day_of_year()
188+
types::DayOfYear(
189+
calendrical_calculations::gregorian::days_before_month(date.year, date.month)
190+
+ date.day as u16,
191+
)
211192
}
212193

213194
fn debug_name(&self) -> &'static str {

components/calendar/src/cal/chinese.rs

Lines changed: 13 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44

55
use crate::cal::iso::{Iso, IsoDateInner};
66
use crate::calendar_arithmetic::DateFieldsResolver;
7-
use crate::calendar_arithmetic::{
8-
ArithmeticDate, ArithmeticDateBuilder, CalendarArithmetic, ToExtendedYear,
9-
};
7+
use crate::calendar_arithmetic::{ArithmeticDate, ArithmeticDateBuilder, ToExtendedYear};
108
use crate::error::{
119
DateError, DateFromFieldsError, EcmaReferenceYearError, MonthCodeError, UnknownEraError,
1210
};
@@ -524,7 +522,9 @@ impl LunarChinese<China> {
524522
}
525523
}
526524

527-
impl<R: Rules> CalendarArithmetic for LunarChinese<R> {
525+
impl<R: Rules> DateFieldsResolver for LunarChinese<R> {
526+
type YearInfo = LunarChineseYearData;
527+
528528
fn days_in_provided_month(year: LunarChineseYearData, month: u8) -> u8 {
529529
year.days_in_month(month)
530530
}
@@ -534,31 +534,6 @@ impl<R: Rules> CalendarArithmetic for LunarChinese<R> {
534534
year.months_in_year()
535535
}
536536

537-
/// Returns true if the given year is a leap year, and false if not.
538-
fn provided_year_is_leap(year: LunarChineseYearData) -> bool {
539-
year.leap_month().is_some()
540-
}
541-
542-
/// Returns the (month, day) of the last day in a Chinese year (the day before Chinese New Year).
543-
/// The last month in a year will always be 12 in a common year or 13 in a leap year. The day is
544-
/// determined by finding the day immediately before the next new year and calculating the number
545-
/// of days since the last new moon (beginning of the last month in the year).
546-
fn last_month_day_in_provided_year(year: LunarChineseYearData) -> (u8, u8) {
547-
if year.leap_month().is_some() {
548-
(13, year.days_in_month(13))
549-
} else {
550-
(12, year.days_in_month(12))
551-
}
552-
}
553-
554-
fn days_in_provided_year(year: LunarChineseYearData) -> u16 {
555-
year.days_in_year()
556-
}
557-
}
558-
559-
impl<R: Rules> DateFieldsResolver for LunarChinese<R> {
560-
type YearInfo = LunarChineseYearData;
561-
562537
#[inline]
563538
fn year_info_from_era(
564539
&self,
@@ -632,13 +607,12 @@ impl<R: Rules> Calendar for LunarChinese<R> {
632607
fn from_rata_die(&self, rd: RataDie) -> Self::DateInner {
633608
let iso = Iso.from_rata_die(rd);
634609
let y = {
635-
let actual_iso = iso.0.extended_year();
636-
let candidate = self.0.year_data(actual_iso);
610+
let candidate = self.0.year_data(iso.0.year);
637611

638612
if rd >= candidate.new_year() {
639613
candidate
640614
} else {
641-
self.0.year_data(actual_iso - 1)
615+
self.0.year_data(iso.0.year - 1)
642616
}
643617
};
644618
let (m, d) = y.md_from_rd(rd);
@@ -652,13 +626,12 @@ impl<R: Rules> Calendar for LunarChinese<R> {
652626
fn from_iso(&self, iso: IsoDateInner) -> Self::DateInner {
653627
let rd = Iso.to_rata_die(&iso);
654628
let y = {
655-
let actual_iso = iso.0.extended_year();
656-
let candidate = self.0.year_data(actual_iso);
629+
let candidate = self.0.year_data(iso.0.year);
657630

658631
if rd >= candidate.new_year() {
659632
candidate
660633
} else {
661-
self.0.year_data(actual_iso - 1)
634+
self.0.year_data(iso.0.year - 1)
662635
}
663636
};
664637
let (m, d) = y.md_from_rd(rd);
@@ -672,11 +645,11 @@ impl<R: Rules> Calendar for LunarChinese<R> {
672645
// Count the number of months in a given year, specified by providing a date
673646
// from that year
674647
fn days_in_year(&self, date: &Self::DateInner) -> u16 {
675-
date.0.days_in_year()
648+
date.0.year.days_in_year()
676649
}
677650

678651
fn days_in_month(&self, date: &Self::DateInner) -> u8 {
679-
date.0.days_in_month()
652+
Self::days_in_provided_month(date.0.year, date.0.month)
680653
}
681654

682655
fn add(
@@ -711,7 +684,7 @@ impl<R: Rules> Calendar for LunarChinese<R> {
711684
}
712685

713686
fn is_in_leap_year(&self, date: &Self::DateInner) -> bool {
714-
Self::provided_year_is_leap(date.0.year)
687+
date.0.year.leap_month().is_some()
715688
}
716689

717690
/// The calendar-specific month code represented by `date`;
@@ -724,7 +697,7 @@ impl<R: Rules> Calendar for LunarChinese<R> {
724697

725698
/// The calendar-specific day-of-month represented by `date`
726699
fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth {
727-
date.0.day_of_month()
700+
types::DayOfMonth(date.0.day)
728701
}
729702

730703
/// Information of the day of the year
@@ -737,7 +710,7 @@ impl<R: Rules> Calendar for LunarChinese<R> {
737710
}
738711

739712
fn months_in_year(&self, date: &Self::DateInner) -> u8 {
740-
date.0.months_in_year()
713+
Self::months_in_provided_year(date.0.year)
741714
}
742715
}
743716

components/calendar/src/cal/coptic.rs

Lines changed: 18 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
44

55
use crate::cal::iso::{Iso, IsoDateInner};
6-
use crate::calendar_arithmetic::{ArithmeticDate, CalendarArithmetic};
6+
use crate::calendar_arithmetic::ArithmeticDate;
77
use crate::calendar_arithmetic::{ArithmeticDateBuilder, DateFieldsResolver};
88
use crate::error::{
99
DateError, DateFromFieldsError, EcmaReferenceYearError, MonthCodeError, UnknownEraError,
@@ -43,12 +43,14 @@ pub struct Coptic;
4343
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
4444
pub struct CopticDateInner(pub(crate) ArithmeticDate<Coptic>);
4545

46-
impl CalendarArithmetic for Coptic {
46+
impl DateFieldsResolver for Coptic {
47+
type YearInfo = i32;
48+
4749
fn days_in_provided_month(year: i32, month: u8) -> u8 {
4850
if (1..=12).contains(&month) {
4951
30
5052
} else if month == 13 {
51-
if Self::provided_year_is_leap(year) {
53+
if year.rem_euclid(4) == 3 {
5254
6
5355
} else {
5456
5
@@ -61,31 +63,6 @@ impl CalendarArithmetic for Coptic {
6163
fn months_in_provided_year(_: i32) -> u8 {
6264
13
6365
}
64-
65-
fn provided_year_is_leap(year: i32) -> bool {
66-
year.rem_euclid(4) == 3
67-
}
68-
69-
fn last_month_day_in_provided_year(year: i32) -> (u8, u8) {
70-
if Self::provided_year_is_leap(year) {
71-
(13, 6)
72-
} else {
73-
(13, 5)
74-
}
75-
}
76-
77-
fn days_in_provided_year(year: i32) -> u16 {
78-
if Self::provided_year_is_leap(year) {
79-
366
80-
} else {
81-
365
82-
}
83-
}
84-
}
85-
86-
impl DateFieldsResolver for Coptic {
87-
type YearInfo = i32;
88-
8966
#[inline]
9067
fn year_info_from_era(
9168
&self,
@@ -166,8 +143,8 @@ impl Calendar for Coptic {
166143
fn from_rata_die(&self, rd: RataDie) -> Self::DateInner {
167144
CopticDateInner(
168145
match calendrical_calculations::coptic::coptic_from_fixed(rd) {
169-
Err(I32CastError::BelowMin) => ArithmeticDate::min_date(),
170-
Err(I32CastError::AboveMax) => ArithmeticDate::max_date(),
146+
Err(I32CastError::BelowMin) => ArithmeticDate::new_unchecked(i32::MIN, 1, 1),
147+
Err(I32CastError::AboveMax) => ArithmeticDate::new_unchecked(i32::MAX, 13, 6),
171148
Ok((year, month, day)) => ArithmeticDate::new_unchecked(year, month, day),
172149
},
173150
)
@@ -186,15 +163,19 @@ impl Calendar for Coptic {
186163
}
187164

188165
fn months_in_year(&self, date: &Self::DateInner) -> u8 {
189-
date.0.months_in_year()
166+
Self::months_in_provided_year(date.0.year)
190167
}
191168

192169
fn days_in_year(&self, date: &Self::DateInner) -> u16 {
193-
date.0.days_in_year()
170+
if self.is_in_leap_year(date) {
171+
366
172+
} else {
173+
365
174+
}
194175
}
195176

196177
fn days_in_month(&self, date: &Self::DateInner) -> u8 {
197-
date.0.days_in_month()
178+
Self::days_in_provided_month(date.0.year, date.0.month)
198179
}
199180

200181
fn add(
@@ -216,7 +197,7 @@ impl Calendar for Coptic {
216197
}
217198

218199
fn year_info(&self, date: &Self::DateInner) -> Self::Year {
219-
let year = date.0.extended_year();
200+
let year = date.0.year;
220201
types::EraYear {
221202
era: tinystr!(16, "am"),
222203
era_index: Some(0),
@@ -227,19 +208,19 @@ impl Calendar for Coptic {
227208
}
228209

229210
fn is_in_leap_year(&self, date: &Self::DateInner) -> bool {
230-
Self::provided_year_is_leap(date.0.year)
211+
date.0.year.rem_euclid(4) == 3
231212
}
232213

233214
fn month(&self, date: &Self::DateInner) -> types::MonthInfo {
234215
self.month_code_from_ordinal(&date.0.year, date.0.month)
235216
}
236217

237218
fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth {
238-
date.0.day_of_month()
219+
types::DayOfMonth(date.0.day)
239220
}
240221

241222
fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear {
242-
date.0.day_of_year()
223+
types::DayOfYear(30 * (date.0.month as u16 - 1) + date.0.day as u16)
243224
}
244225

245226
fn debug_name(&self) -> &'static str {

components/calendar/src/cal/ethiopian.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,14 @@ impl DateFieldsResolver for Ethiopian {
7676
// Coptic year
7777
type YearInfo = i32;
7878

79+
fn days_in_provided_month(year: Self::YearInfo, month: u8) -> u8 {
80+
Coptic::days_in_provided_month(year, month)
81+
}
82+
83+
fn months_in_provided_year(year: Self::YearInfo) -> u8 {
84+
Coptic::months_in_provided_year(year)
85+
}
86+
7987
#[inline]
8088
fn year_info_from_era(
8189
&self,
@@ -187,7 +195,7 @@ impl Calendar for Ethiopian {
187195
}
188196

189197
fn year_info(&self, date: &Self::DateInner) -> Self::Year {
190-
let coptic_year = date.0 .0.extended_year();
198+
let coptic_year = date.0 .0.year;
191199
let extended_year = if self.0 == EthiopianEraStyle::AmeteAlem {
192200
coptic_year - AMETE_ALEM_OFFSET
193201
} else {

0 commit comments

Comments
 (0)