Skip to content

Commit e5ca66d

Browse files
authored
DateTimeFormatterPreferences (#5842)
#1317
1 parent 9dd49be commit e5ca66d

33 files changed

+464
-402
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ use icu::datetime::{DateTimeFormatter, NeoSkeletonLength, fieldsets::YMDT};
4141
use icu::locale::locale;
4242

4343
let dtf = DateTimeFormatter::try_new(
44-
&locale!("es").into(),
44+
locale!("es").into(),
4545
YMDT::long()
4646
)
4747
.expect("locale should be present in compiled data");

components/calendar/src/any_calendar.rs

+62-13
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,26 @@ use crate::roc::Roc;
2121
use crate::{types, AsCalendar, Calendar, Date, DateDuration, DateDurationUnit, DateTime, Ref};
2222

2323
use icu_locale_core::extensions::unicode::{key, value, Value};
24+
use icu_locale_core::preferences::define_preferences;
25+
use icu_locale_core::preferences::extensions::unicode::keywords::{
26+
CalendarAlgorithm, IslamicCalendarAlgorithm,
27+
};
2428
use icu_locale_core::subtags::language;
2529
use icu_locale_core::Locale;
2630
use icu_provider::prelude::*;
2731

2832
use core::fmt;
2933

34+
define_preferences!(
35+
/// The prefs for datetime formatting.
36+
[Copy]
37+
AnyCalendarPreferences,
38+
{
39+
/// The user's preferred calendar system.
40+
calendar_algorithm: CalendarAlgorithm
41+
}
42+
);
43+
3044
/// This is a calendar that encompasses all formattable calendars supported by this crate
3145
///
3246
/// This allows for the construction of [`Date`] objects that have their calendar known at runtime.
@@ -46,7 +60,7 @@ use core::fmt;
4660
///
4761
/// let locale = locale!("en-u-ca-japanese"); // English with the Japanese calendar
4862
///
49-
/// let calendar = AnyCalendar::new_for_locale(&locale.into());
63+
/// let calendar = AnyCalendar::new_for_locale(locale.into());
5064
/// let calendar = Rc::new(calendar); // Avoid cloning it each time
5165
/// // If everything is a local reference, you may use icu::calendar::Ref instead.
5266
///
@@ -748,13 +762,13 @@ impl AnyCalendar {
748762
///
749763
/// [📚 Help choosing a constructor](icu_provider::constructors)
750764
#[cfg(feature = "compiled_data")]
751-
pub fn new_for_locale(locale: &DataLocale) -> Self {
752-
let kind = AnyCalendarKind::from_data_locale_with_fallback(locale);
765+
pub fn new_for_locale(prefs: AnyCalendarPreferences) -> Self {
766+
let kind = AnyCalendarKind::from_prefs_with_fallback(prefs);
753767
Self::new(kind)
754768
}
755769

756770
icu_provider::gen_any_buffer_data_constructors!(
757-
(locale) -> error: DataError,
771+
(prefs: AnyCalendarPreferences) -> error: DataError,
758772
functions: [
759773
new_for_locale: skip,
760774
try_new_for_locale_with_any_provider,
@@ -767,7 +781,7 @@ impl AnyCalendar {
767781
#[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::new_for_locale)]
768782
pub fn try_new_for_locale_unstable<P>(
769783
provider: &P,
770-
locale: &DataLocale,
784+
prefs: AnyCalendarPreferences,
771785
) -> Result<Self, DataError>
772786
where
773787
P: DataProvider<crate::provider::JapaneseErasV1Marker>
@@ -778,7 +792,7 @@ impl AnyCalendar {
778792
+ DataProvider<crate::provider::IslamicUmmAlQuraCacheV1Marker>
779793
+ ?Sized,
780794
{
781-
let kind = AnyCalendarKind::from_data_locale_with_fallback(locale);
795+
let kind = AnyCalendarKind::from_prefs_with_fallback(prefs);
782796
Self::try_new_unstable(provider, kind)
783797
}
784798

@@ -1028,6 +1042,40 @@ impl AnyCalendarKind {
10281042
}
10291043
}
10301044

1045+
fn get_for_preferences_calendar(pcal: CalendarAlgorithm) -> Option<Self> {
1046+
match pcal {
1047+
CalendarAlgorithm::Buddhist => Some(Self::Buddhist),
1048+
CalendarAlgorithm::Chinese => Some(Self::Chinese),
1049+
CalendarAlgorithm::Coptic => Some(Self::Coptic),
1050+
CalendarAlgorithm::Dangi => Some(Self::Dangi),
1051+
CalendarAlgorithm::Ethioaa => Some(Self::EthiopianAmeteAlem),
1052+
CalendarAlgorithm::Ethiopic => Some(Self::Ethiopian),
1053+
CalendarAlgorithm::Gregory => Some(Self::Gregorian),
1054+
CalendarAlgorithm::Hebrew => Some(Self::Hebrew),
1055+
CalendarAlgorithm::Indian => Some(Self::Indian),
1056+
CalendarAlgorithm::Islamic(None) => Some(Self::IslamicObservational),
1057+
CalendarAlgorithm::Islamic(Some(islamic)) => match islamic {
1058+
IslamicCalendarAlgorithm::Umalqura => Some(Self::IslamicUmmAlQura),
1059+
IslamicCalendarAlgorithm::Tbla => Some(Self::IslamicTabular),
1060+
IslamicCalendarAlgorithm::Civil => Some(Self::IslamicCivil),
1061+
// Rgsa is not supported
1062+
IslamicCalendarAlgorithm::Rgsa => None,
1063+
_ => {
1064+
debug_assert!(false, "unknown calendar algorithm {pcal:?}");
1065+
None
1066+
}
1067+
},
1068+
CalendarAlgorithm::Iso8601 => Some(Self::Iso),
1069+
CalendarAlgorithm::Japanese => Some(Self::Japanese),
1070+
CalendarAlgorithm::Persian => Some(Self::Persian),
1071+
CalendarAlgorithm::Roc => Some(Self::Roc),
1072+
_ => {
1073+
debug_assert!(false, "unknown calendar algorithm {pcal:?}");
1074+
None
1075+
}
1076+
}
1077+
}
1078+
10311079
fn debug_name(self) -> &'static str {
10321080
match self {
10331081
AnyCalendarKind::Buddhist => Buddhist.debug_name(),
@@ -1062,21 +1110,22 @@ impl AnyCalendarKind {
10621110
.and_then(Self::get_for_bcp47_value)
10631111
}
10641112

1065-
/// Extract the calendar component from a [`DataLocale`]
1113+
/// Extract the calendar component from a [`AnyCalendarPreferences`]
10661114
///
10671115
/// Returns `None` if the calendar is not specified or unknown.
1068-
fn get_for_data_locale(l: &DataLocale) -> Option<Self> {
1069-
l.get_unicode_ext(&key!("ca"))
1070-
.and_then(|v| Self::get_for_bcp47_value(&v))
1116+
fn get_for_prefs(prefs: AnyCalendarPreferences) -> Option<Self> {
1117+
prefs
1118+
.calendar_algorithm
1119+
.and_then(Self::get_for_preferences_calendar)
10711120
}
10721121

10731122
// Do not make public, this will eventually need fallback
10741123
// data from the provider
1075-
fn from_data_locale_with_fallback(l: &DataLocale) -> Self {
1076-
if let Some(kind) = Self::get_for_data_locale(l) {
1124+
fn from_prefs_with_fallback(prefs: AnyCalendarPreferences) -> Self {
1125+
if let Some(kind) = Self::get_for_prefs(prefs) {
10771126
kind
10781127
} else {
1079-
let lang = l.language;
1128+
let lang = prefs.locale_prefs.language;
10801129
if lang == language!("th") {
10811130
Self::Buddhist
10821131
} else if lang == language!("sa") {

components/calendar/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ pub mod week {
200200
#[cfg(feature = "ixdtf")]
201201
pub use crate::ixdtf::ParseError;
202202
#[doc(no_inline)]
203-
pub use any_calendar::{AnyCalendar, AnyCalendarKind};
203+
pub use any_calendar::{AnyCalendar, AnyCalendarKind, AnyCalendarPreferences};
204204
pub use calendar::Calendar;
205205
pub use date::{AsCalendar, Date, Ref};
206206
pub use datetime::DateTime;

components/datetime/README.md

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/datetime/benches/datetime.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ fn datetime_benches(c: &mut Criterion) {
5252

5353
let dtf = {
5454
FixedCalendarDateTimeFormatter::<Gregorian, _>::try_new(
55-
&locale.into(),
55+
locale.into(),
5656
skeleton,
5757
)
5858
.expect("Failed to create FixedCalendarDateTimeFormatter.")

components/datetime/examples/work_log.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const DATES_ISO: &[(i32, u8, u8, u8, u8, u8)] = &[
2727
];
2828

2929
fn main() {
30-
let dtf = FixedCalendarDateTimeFormatter::try_new(&locale!("en").into(), YMDT::medium())
30+
let dtf = FixedCalendarDateTimeFormatter::try_new(locale!("en").into(), YMDT::medium())
3131
.expect("Failed to create FixedCalendarDateTimeFormatter instance.");
3232

3333
println!("\n====== Work Log (en) example ============");

components/datetime/src/combo.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use crate::{provider::neo::*, scaffold::*};
3434
///
3535
/// // Note: Combo type can be elided, but it is shown here for demonstration
3636
/// let formatter = DateTimeFormatter::<Combo<ET, L>>::try_new(
37-
/// &locale!("en-US").into(),
37+
/// locale!("en-US").into(),
3838
/// ET::short().hm().zone_l(),
3939
/// )
4040
/// .unwrap();
@@ -62,7 +62,7 @@ use crate::{provider::neo::*, scaffold::*};
6262
///
6363
/// // Note: Combo type can be elided, but it is shown here for demonstration
6464
/// let formatter = FixedCalendarDateTimeFormatter::<_, Combo<ET, L>>::try_new(
65-
/// &locale!("en-US").into(),
65+
/// locale!("en-US").into(),
6666
/// ET::short().hm().zone_l(),
6767
/// )
6868
/// .unwrap();
@@ -91,7 +91,7 @@ use crate::{provider::neo::*, scaffold::*};
9191
///
9292
/// // Note: Combo type can be elided, but it is shown here for demonstration
9393
/// let formatter = DateTimeFormatter::<Combo<DateFieldSet, Vs>>::try_new(
94-
/// &locale!("en-US").into(),
94+
/// locale!("en-US").into(),
9595
/// DateFieldSet::YMD(YMD::long()).zone_v(),
9696
/// )
9797
/// .unwrap();

components/datetime/src/dynamic.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,10 @@
4545
//! }
4646
//! }
4747
//!
48-
//! let locale = locale!("en-US").into();
4948
//! let datetime = DateTime::try_new_iso(2025, 1, 15, 16, 0, 0).unwrap();
5049
//!
5150
//! let results = [true, false].map(get_field_set).map(|field_set| {
52-
//! DateTimeFormatter::try_new(&locale, field_set).unwrap()
51+
//! DateTimeFormatter::try_new(locale!("en-US").into(), field_set).unwrap()
5352
//! }).map(|formatter| {
5453
//! formatter.convert_and_format(&datetime).try_write_to_string().unwrap().into_owned()
5554
//! });

components/datetime/src/external_loaders.rs

+20-24
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
//! Internal traits and structs for loading data from other crates.
66
7-
use icu_calendar::AnyCalendar;
7+
use icu_calendar::{AnyCalendar, AnyCalendarPreferences};
88
use icu_decimal::options::FixedDecimalFormatterOptions;
9-
use icu_decimal::FixedDecimalFormatter;
9+
use icu_decimal::{FixedDecimalFormatter, FixedDecimalFormatterPreferences};
1010
use icu_provider::prelude::*;
1111

1212
/// Trait for loading a FixedDecimalFormatter.
@@ -15,7 +15,7 @@ use icu_provider::prelude::*;
1515
pub(crate) trait FixedDecimalFormatterLoader {
1616
fn load(
1717
&self,
18-
locale: &DataLocale,
18+
prefs: FixedDecimalFormatterPreferences,
1919
options: FixedDecimalFormatterOptions,
2020
) -> Result<FixedDecimalFormatter, DataError>;
2121
}
@@ -24,7 +24,7 @@ pub(crate) trait FixedDecimalFormatterLoader {
2424
///
2525
/// Implemented on the provider-specific loader types in this module.
2626
pub(crate) trait AnyCalendarLoader {
27-
fn load(&self, locale: &DataLocale) -> Result<AnyCalendar, DataError>;
27+
fn load(&self, prefs: AnyCalendarPreferences) -> Result<AnyCalendar, DataError>;
2828
}
2929

3030
/// Loader for types from other crates using compiled data.
@@ -36,19 +36,18 @@ impl FixedDecimalFormatterLoader for ExternalLoaderCompiledData {
3636
#[inline]
3737
fn load(
3838
&self,
39-
locale: &DataLocale,
39+
prefs: FixedDecimalFormatterPreferences,
4040
options: FixedDecimalFormatterOptions,
4141
) -> Result<FixedDecimalFormatter, DataError> {
42-
let temp_loc = locale.clone().into_locale();
43-
FixedDecimalFormatter::try_new(temp_loc.into(), options)
42+
FixedDecimalFormatter::try_new(prefs, options)
4443
}
4544
}
4645

4746
#[cfg(feature = "compiled_data")]
4847
impl AnyCalendarLoader for ExternalLoaderCompiledData {
4948
#[inline]
50-
fn load(&self, locale: &DataLocale) -> Result<AnyCalendar, DataError> {
51-
Ok(AnyCalendar::new_for_locale(locale))
49+
fn load(&self, prefs: AnyCalendarPreferences) -> Result<AnyCalendar, DataError> {
50+
Ok(AnyCalendar::new_for_locale(prefs))
5251
}
5352
}
5453

@@ -62,11 +61,10 @@ where
6261
#[inline]
6362
fn load(
6463
&self,
65-
locale: &DataLocale,
64+
prefs: FixedDecimalFormatterPreferences,
6665
options: FixedDecimalFormatterOptions,
6766
) -> Result<FixedDecimalFormatter, DataError> {
68-
let temp_loc = locale.clone().into_locale();
69-
FixedDecimalFormatter::try_new_with_any_provider(self.0, temp_loc.into(), options)
67+
FixedDecimalFormatter::try_new_with_any_provider(self.0, prefs, options)
7068
}
7169
}
7270

@@ -75,8 +73,8 @@ where
7573
P: ?Sized + AnyProvider,
7674
{
7775
#[inline]
78-
fn load(&self, locale: &DataLocale) -> Result<AnyCalendar, DataError> {
79-
AnyCalendar::try_new_for_locale_with_any_provider(self.0, locale)
76+
fn load(&self, prefs: AnyCalendarPreferences) -> Result<AnyCalendar, DataError> {
77+
AnyCalendar::try_new_for_locale_with_any_provider(self.0, prefs)
8078
}
8179
}
8280

@@ -92,11 +90,10 @@ where
9290
#[inline]
9391
fn load(
9492
&self,
95-
locale: &DataLocale,
93+
prefs: FixedDecimalFormatterPreferences,
9694
options: FixedDecimalFormatterOptions,
9795
) -> Result<FixedDecimalFormatter, DataError> {
98-
let temp_loc = locale.clone().into_locale();
99-
FixedDecimalFormatter::try_new_with_buffer_provider(self.0, temp_loc.into(), options)
96+
FixedDecimalFormatter::try_new_with_buffer_provider(self.0, prefs, options)
10097
}
10198
}
10299

@@ -106,8 +103,8 @@ where
106103
P: ?Sized + BufferProvider,
107104
{
108105
#[inline]
109-
fn load(&self, locale: &DataLocale) -> Result<AnyCalendar, DataError> {
110-
AnyCalendar::try_new_for_locale_with_buffer_provider(self.0, locale)
106+
fn load(&self, prefs: AnyCalendarPreferences) -> Result<AnyCalendar, DataError> {
107+
AnyCalendar::try_new_for_locale_with_buffer_provider(self.0, prefs)
111108
}
112109
}
113110

@@ -123,11 +120,10 @@ where
123120
#[inline]
124121
fn load(
125122
&self,
126-
locale: &DataLocale,
123+
prefs: FixedDecimalFormatterPreferences,
127124
options: FixedDecimalFormatterOptions,
128125
) -> Result<FixedDecimalFormatter, DataError> {
129-
let temp_loc = locale.clone().into_locale();
130-
FixedDecimalFormatter::try_new_unstable(self.0, temp_loc.into(), options)
126+
FixedDecimalFormatter::try_new_unstable(self.0, prefs, options)
131127
}
132128
}
133129

@@ -142,7 +138,7 @@ where
142138
+ ?Sized,
143139
{
144140
#[inline]
145-
fn load(&self, locale: &DataLocale) -> Result<AnyCalendar, DataError> {
146-
AnyCalendar::try_new_for_locale_unstable(self.0, locale)
141+
fn load(&self, prefs: AnyCalendarPreferences) -> Result<AnyCalendar, DataError> {
142+
AnyCalendar::try_new_for_locale_unstable(self.0, prefs)
147143
}
148144
}

0 commit comments

Comments
 (0)