Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
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
4 changes: 4 additions & 0 deletions components/calendar/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,9 @@ harness = false
name = "convert"
harness = false

[[test]]
name = "arithmetic"
required-features = ["ixdtf"]

[package.metadata.cargo-semver-checks.lints]
workspace = true
25 changes: 17 additions & 8 deletions components/calendar/benches/date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,27 @@ pub struct Test {
use criterion::{
black_box, criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, Criterion,
};
use icu_calendar::{AsCalendar, Calendar, Date, DateDuration};
use icu_calendar::{
options::{DateAddOptions, Overflow},
types, AsCalendar, Calendar, Date,
};

fn bench_date<A: AsCalendar>(date: &mut Date<A>) {
// black_box used to avoid compiler optimization.
// Arithmetic
date.add(DateDuration {
is_negative: false,
years: black_box(1),
months: black_box(2),
weeks: black_box(3),
days: black_box(4),
});
let mut options = DateAddOptions::default();
options.overflow = Some(Overflow::Constrain);
date.try_add_with_options(
types::DateDuration {
is_negative: false,
years: black_box(1),
months: black_box(2),
weeks: black_box(3),
days: black_box(4),
},
options,
)
.unwrap();

// Retrieving vals
let _ = black_box(date.year());
Expand Down
466 changes: 182 additions & 284 deletions components/calendar/src/any_calendar.rs

Large diffs are not rendered by default.

53 changes: 27 additions & 26 deletions components/calendar/src/cal/abstract_gregorian.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ use crate::calendar_arithmetic::{
};
use crate::error::DateError;
use crate::options::DateFromFieldsOptions;
use crate::options::{DateAddOptions, DateDifferenceOptions};
use crate::preferences::CalendarAlgorithm;
use crate::types::EraYear;
use crate::{types, Calendar, DateDuration, DateDurationUnit, RangeError};
use crate::{types, Calendar, RangeError};
use calendrical_calculations::helpers::I32CastError;
use calendrical_calculations::rata_die::RataDie;

Expand Down Expand Up @@ -43,8 +44,6 @@ impl ArithmeticDate<AbstractGregorian<IsoEra>> {
}

impl CalendarArithmetic for AbstractGregorian<IsoEra> {
type YearInfo = i32;

fn days_in_provided_month(year: i32, month: u8) -> u8 {
// https://www.youtube.com/watch?v=J9KijLyP-yg&t=1394s
if month == 2 {
Expand Down Expand Up @@ -113,6 +112,7 @@ impl<Y: GregorianYears> crate::cal::scaffold::UnstableSealed for AbstractGregori
impl<Y: GregorianYears> Calendar for AbstractGregorian<Y> {
type DateInner = ArithmeticDate<AbstractGregorian<IsoEra>>;
type Year = types::EraYear;
type DifferenceError = core::convert::Infallible;

fn from_fields(
&self,
Expand Down Expand Up @@ -156,19 +156,22 @@ impl<Y: GregorianYears> Calendar for AbstractGregorian<Y> {
date.days_in_month()
}

fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration) {
date.offset_date(offset, &());
fn add(
&self,
date: &Self::DateInner,
duration: types::DateDuration,
options: DateAddOptions,
) -> Result<Self::DateInner, DateError> {
date.added(duration, &AbstractGregorian(IsoEra), options)
}

fn until(
&self,
date1: &Self::DateInner,
date2: &Self::DateInner,
_calendar2: &Self,
_largest_unit: DateDurationUnit,
_smallest_unit: DateDurationUnit,
) -> DateDuration {
date1.until(*date2, _largest_unit, _smallest_unit)
options: DateDifferenceOptions,
) -> Result<types::DateDuration, Self::DifferenceError> {
Ok(date1.until(date2, &AbstractGregorian(IsoEra), options))
}

fn year_info(&self, date: &Self::DateInner) -> Self::Year {
Expand All @@ -181,7 +184,7 @@ impl<Y: GregorianYears> Calendar for AbstractGregorian<Y> {
}

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

fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth {
Expand Down Expand Up @@ -214,6 +217,7 @@ macro_rules! impl_with_abstract_gregorian {
impl crate::Calendar for $cal_ty {
type DateInner = $inner_date_ty;
type Year = types::EraYear;
type DifferenceError = core::convert::Infallible;
fn from_fields(
&self,
fields: crate::types::DateFields,
Expand Down Expand Up @@ -265,30 +269,27 @@ macro_rules! impl_with_abstract_gregorian {
crate::cal::abstract_gregorian::AbstractGregorian($eras_expr).days_in_month(&date.0)
}

fn offset_date(&self, date: &mut Self::DateInner, offset: crate::DateDuration) {
fn add(
&self,
date: &Self::DateInner,
duration: crate::types::DateDuration,
options: crate::options::DateAddOptions,
) -> Result<Self::DateInner, DateError> {
let $self_ident = self;
let mut inner = date.0;
crate::cal::abstract_gregorian::AbstractGregorian($eras_expr)
.offset_date(&mut inner, offset);
date.0 = inner;
.add(&date.0, duration, options)
.map($inner_date_ty)
}

fn until(
&self,
date1: &Self::DateInner,
date2: &Self::DateInner,
_calendar2: &Self,
largest_unit: crate::DateDurationUnit,
smallest_unit: crate::DateDurationUnit,
) -> crate::DateDuration {
options: crate::options::DateDifferenceOptions,
) -> Result<crate::types::DateDuration, Self::DifferenceError> {
let $self_ident = self;
crate::cal::abstract_gregorian::AbstractGregorian($eras_expr).until(
&date1.0,
&date2.0,
&crate::cal::abstract_gregorian::AbstractGregorian($eras_expr),
largest_unit,
smallest_unit,
)
crate::cal::abstract_gregorian::AbstractGregorian($eras_expr)
.until(&date1.0, &date2.0, options)
}

fn year_info(&self, date: &Self::DateInner) -> Self::Year {
Expand Down
47 changes: 27 additions & 20 deletions components/calendar/src/cal/chinese.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).

use crate::cal::iso::{Iso, IsoDateInner};
use crate::calendar_arithmetic::{ArithmeticDate, ArithmeticDateBuilder, CalendarArithmetic};
use crate::calendar_arithmetic::{
ArithmeticDate, ArithmeticDateBuilder, CalendarArithmetic, ToExtendedYear,
};
use crate::calendar_arithmetic::{DateFieldsResolver, PrecomputedDataSource};
use crate::error::DateError;
use crate::options::{DateAddOptions, DateDifferenceOptions};
use crate::options::{DateFromFieldsOptions, Overflow};
use crate::provider::chinese_based::PackedChineseBasedYearInfo;
use crate::types::{MonthCode, MonthInfo};
use crate::AsCalendar;
use crate::{types, Calendar, Date, DateDuration, DateDurationUnit};
use crate::{types, Calendar, Date};
use calendrical_calculations::chinese_based::{
self, ChineseBased, YearBounds, WELL_BEHAVED_ASTRONOMICAL_RANGE,
};
Expand Down Expand Up @@ -497,8 +500,6 @@ impl LunarChinese<China> {
}

impl<R: Rules> CalendarArithmetic for LunarChinese<R> {
type YearInfo = LunarChineseYearData;

fn days_in_provided_month(year: LunarChineseYearData, month: u8) -> u8 {
year.days_in_month(month)
}
Expand Down Expand Up @@ -577,12 +578,21 @@ impl<R: Rules> DateFieldsResolver for LunarChinese<R> {
_ => Err(DateError::UnknownMonthCode(month_code)),
}
}

fn month_code_from_ordinal(
&self,
year: &Self::YearInfo,
ordinal_month: u8,
) -> types::MonthInfo {
year.month(ordinal_month)
}
}

impl<R: Rules> crate::cal::scaffold::UnstableSealed for LunarChinese<R> {}
impl<R: Rules> Calendar for LunarChinese<R> {
type DateInner = ChineseDateInner<R>;
type Year = types::CyclicYear;
type DifferenceError = core::convert::Infallible;

fn from_fields(
&self,
Expand Down Expand Up @@ -645,25 +655,22 @@ impl<R: Rules> Calendar for LunarChinese<R> {
date.0.days_in_month()
}

#[doc(hidden)] // unstable
fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration) {
date.0.offset_date(offset, self);
fn add(
&self,
date: &Self::DateInner,
duration: types::DateDuration,
options: DateAddOptions,
) -> Result<Self::DateInner, DateError> {
date.0.added(duration, self, options).map(ChineseDateInner)
}

#[doc(hidden)] // unstable
/// Calculate `date2 - date` as a duration
///
/// `calendar2` is the calendar object associated with `date2`. In case the specific calendar objects
/// differ on date, the date for the first calendar is used, and `date2` may be converted if necessary.
fn until(
&self,
date1: &Self::DateInner,
date2: &Self::DateInner,
_calendar2: &Self,
_largest_unit: DateDurationUnit,
_smallest_unit: DateDurationUnit,
) -> DateDuration {
date1.0.until(date2.0, _largest_unit, _smallest_unit)
options: DateDifferenceOptions,
) -> Result<types::DateDuration, Self::DifferenceError> {
Ok(date1.0.until(&date2.0, self, options))
}

/// Obtain a name for the calendar for debug printing
Expand Down Expand Up @@ -760,9 +767,9 @@ pub struct LunarChineseYearData {
pub(crate) related_iso: i32,
}

impl From<LunarChineseYearData> for i32 {
fn from(value: LunarChineseYearData) -> Self {
value.related_iso
impl ToExtendedYear for LunarChineseYearData {
fn to_extended_year(&self) -> i32 {
self.related_iso
}
}

Expand Down
26 changes: 15 additions & 11 deletions components/calendar/src/cal/coptic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use crate::calendar_arithmetic::{ArithmeticDate, CalendarArithmetic};
use crate::calendar_arithmetic::{ArithmeticDateBuilder, DateFieldsResolver};
use crate::error::DateError;
use crate::options::DateFromFieldsOptions;
use crate::{types, Calendar, Date, DateDuration, DateDurationUnit, RangeError};
use crate::options::{DateAddOptions, DateDifferenceOptions};
use crate::{types, Calendar, Date, RangeError};
use calendrical_calculations::helpers::I32CastError;
use calendrical_calculations::rata_die::RataDie;
use tinystr::tinystr;
Expand Down Expand Up @@ -39,8 +40,6 @@ pub struct Coptic;
pub struct CopticDateInner(pub(crate) ArithmeticDate<Coptic>);

impl CalendarArithmetic for Coptic {
type YearInfo = i32;

fn days_in_provided_month(year: i32, month: u8) -> u8 {
if (1..=12).contains(&month) {
30
Expand Down Expand Up @@ -133,6 +132,8 @@ impl crate::cal::scaffold::UnstableSealed for Coptic {}
impl Calendar for Coptic {
type DateInner = CopticDateInner;
type Year = types::EraYear;
type DifferenceError = core::convert::Infallible;

fn from_fields(
&self,
fields: types::DateFields,
Expand Down Expand Up @@ -178,19 +179,22 @@ impl Calendar for Coptic {
date.0.days_in_month()
}

fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration) {
date.0.offset_date(offset, &());
fn add(
&self,
date: &Self::DateInner,
duration: types::DateDuration,
options: DateAddOptions,
) -> Result<Self::DateInner, DateError> {
date.0.added(duration, self, options).map(CopticDateInner)
}

fn until(
&self,
date1: &Self::DateInner,
date2: &Self::DateInner,
_calendar2: &Self,
_largest_unit: DateDurationUnit,
_smallest_unit: DateDurationUnit,
) -> DateDuration {
date1.0.until(date2.0, _largest_unit, _smallest_unit)
options: DateDifferenceOptions,
) -> Result<types::DateDuration, Self::DifferenceError> {
Ok(date1.0.until(&date2.0, self, options))
}

fn year_info(&self, date: &Self::DateInner) -> Self::Year {
Expand All @@ -209,7 +213,7 @@ impl Calendar for Coptic {
}

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

fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth {
Expand Down
24 changes: 16 additions & 8 deletions components/calendar/src/cal/ethiopian.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ use crate::cal::Coptic;
use crate::calendar_arithmetic::{ArithmeticDate, ArithmeticDateBuilder, DateFieldsResolver};
use crate::error::DateError;
use crate::options::DateFromFieldsOptions;
use crate::options::{DateAddOptions, DateDifferenceOptions};
use crate::types::DateFields;
use crate::{types, Calendar, Date, DateDuration, DateDurationUnit, RangeError};
use crate::{types, Calendar, Date, RangeError};
use calendrical_calculations::rata_die::RataDie;
use tinystr::tinystr;

Expand Down Expand Up @@ -103,6 +104,8 @@ impl crate::cal::scaffold::UnstableSealed for Ethiopian {}
impl Calendar for Ethiopian {
type DateInner = EthiopianDateInner;
type Year = types::EraYear;
type DifferenceError = core::convert::Infallible;

fn from_fields(
&self,
fields: DateFields,
Expand Down Expand Up @@ -143,19 +146,24 @@ impl Calendar for Ethiopian {
Coptic.days_in_month(&date.0)
}

fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration) {
Coptic.offset_date(&mut date.0, offset);
fn add(
&self,
date: &Self::DateInner,
duration: types::DateDuration,
options: DateAddOptions,
) -> Result<Self::DateInner, DateError> {
Coptic
.add(&date.0, duration, options)
.map(EthiopianDateInner)
}

fn until(
&self,
date1: &Self::DateInner,
date2: &Self::DateInner,
_calendar2: &Self,
largest_unit: DateDurationUnit,
smallest_unit: DateDurationUnit,
) -> DateDuration {
Coptic.until(&date1.0, &date2.0, &Coptic, largest_unit, smallest_unit)
options: DateDifferenceOptions,
) -> Result<types::DateDuration, Self::DifferenceError> {
Coptic.until(&date1.0, &date2.0, options)
}

fn year_info(&self, date: &Self::DateInner) -> Self::Year {
Expand Down
Loading