diff --git a/src/components/calendar.rs b/src/components/calendar.rs index 4d6b9b32..76d9c18b 100644 --- a/src/components/calendar.rs +++ b/src/components/calendar.rs @@ -10,7 +10,7 @@ use crate::{ duration::{DateDuration, TimeDuration}, Date, DateTime, Duration, MonthDay, YearMonth, }, - fields::{TemporalFieldKey, TemporalFields}, + fields::{FieldMap, TemporalFields}, iso::{IsoDate, IsoDateSlots}, options::{ArithmeticOverflow, TemporalUnit}, TemporalError, TemporalResult, @@ -634,19 +634,16 @@ impl Calendar { } /// Provides field keys to be ignored depending on the calendar. - pub fn field_keys_to_ignore( - &self, - keys: &[TemporalFieldKey], - ) -> TemporalResult> { - let mut ignored_keys = Vec::with_capacity(5); + pub fn field_keys_to_ignore(&self, keys: FieldMap) -> TemporalResult { + let mut ignored_keys = FieldMap::empty(); if self.is_iso() { // NOTE: It is okay for ignored keys to have duplicates? - for key in keys { - ignored_keys.push(*key); - if key == &TemporalFieldKey::Month { - ignored_keys.push(TemporalFieldKey::MonthCode) - } else if key == &TemporalFieldKey::MonthCode { - ignored_keys.push(TemporalFieldKey::Month) + for key in keys.iter() { + ignored_keys.set(key, true); + if key == FieldMap::MONTH { + ignored_keys.set(FieldMap::MONTH_CODE, true); + } else if key == FieldMap::MONTH_CODE { + ignored_keys.set(FieldMap::MONTH, true); } } @@ -698,9 +695,11 @@ impl From for Calendar { } } -#[cfg(all(test, feature = "compiled_data"))] +#[cfg(test)] mod tests { - use super::*; + use crate::{components::Date, iso::IsoDate, options::TemporalUnit}; + + use super::Calendar; #[test] fn date_until_largest_year() { @@ -947,7 +946,7 @@ mod tests { ), ]; - let calendar = Calendar::from_str("iso8601").unwrap(); + let calendar = Calendar::default(); for test in tests { let first = Date::new_unchecked( @@ -962,22 +961,22 @@ mod tests { .date_until(&first, &second, TemporalUnit::Year) .unwrap(); assert_eq!( - result.years() as i32, + result.years().as_inner() as i32, test.2 .0, "year failed for test \"{test:?}\"" ); assert_eq!( - result.months() as i32, + result.months().as_inner() as i32, test.2 .1, "months failed for test \"{test:?}\"" ); assert_eq!( - result.weeks() as i32, + result.weeks().as_inner() as i32, test.2 .2, "weeks failed for test \"{test:?}\"" ); assert_eq!( - result.days() as i32, + result.days().as_inner() as i32, test.2 .3, "days failed for test \"{test:?}\"" ); diff --git a/src/components/date.rs b/src/components/date.rs index 284770ed..296dddd2 100644 --- a/src/components/date.rs +++ b/src/components/date.rs @@ -32,6 +32,8 @@ pub struct PartialDate { pub(crate) month: Option, pub(crate) month_code: Option, pub(crate) day: Option, + pub(crate) era: Option>, + pub(crate) era_year: Option, } impl PartialDate { @@ -41,8 +43,13 @@ impl PartialDate { month: Option, month_code: Option, day: Option, + era: Option>, + era_year: Option, ) -> TemporalResult { - if year.is_none() && month.is_none() && month_code.is_none() && day.is_none() { + if !(day.is_some() + && (month.is_some() || month_code.is_some()) + && (year.is_some() || (era.is_some() && era_year.is_some()))) + { return Err(TemporalError::r#type() .with_message("A partial date must have at least one defined field.")); } @@ -51,6 +58,8 @@ impl PartialDate { month, month_code, day, + era, + era_year, }) } } diff --git a/src/components/mod.rs b/src/components/mod.rs index a95f700e..3e43207e 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -50,6 +50,7 @@ pub use zoneddatetime::ZonedDateTime; use crate::TemporalError; +// TODO: Update to account for https://tc39.es/proposal-intl-era-monthcode/ #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[repr(u8)] pub enum MonthCode { diff --git a/src/fields.rs b/src/fields.rs index c7e255f8..fc3442ed 100644 --- a/src/fields.rs +++ b/src/fields.rs @@ -456,16 +456,15 @@ impl TemporalFields { /// Merges two `TemporalFields` depending on the calendar. #[inline] pub fn merge_fields(&self, other: &Self, calendar: &Calendar) -> TemporalResult { - let add_keys = other.keys().collect::>(); - let overridden_keys = calendar.field_keys_to_ignore(&add_keys)?; + let overridden_keys = calendar.field_keys_to_ignore(other.bit_map)?; let mut result = Self::default(); - for key in self.keys() { - let value = if overridden_keys.contains(&key) { - other.get(key) + for key in self.bit_map.iter() { + let value = if overridden_keys.contains(key) { + other.get(key.try_into()?) } else { - self.get(key) + self.get(key.try_into()?) }; let Some(value) = value else { @@ -474,7 +473,7 @@ impl TemporalFields { )); }; - result.insert(key, value)?; + result.insert(key.try_into()?, value)?; } Ok(result) @@ -511,6 +510,12 @@ impl From for TemporalFields { if value.day.is_some() { bit_map.set(FieldMap::DAY, true) }; + if value.era.is_some() { + bit_map.set(FieldMap::ERA, true) + } + if value.era_year.is_some() { + bit_map.set(FieldMap::ERA_YEAR, true) + } Self { bit_map, @@ -518,6 +523,8 @@ impl From for TemporalFields { month: value.month, month_code: value.month_code, day: value.day, + era: value.era, + era_year: value.era_year, ..Default::default() } }