icu_datetime/pattern/names.rs
1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5use super::{
6 DateTimePattern, DateTimePatternFormatter, GetNameForCyclicYearError, GetNameForDayPeriodError,
7 GetNameForEraError, GetNameForMonthError, GetNameForWeekdayError, MonthPlaceholderValue,
8 PatternLoadError, UnsupportedCalendarError,
9};
10use crate::error::ErrorField;
11use crate::fieldsets::enums::{CompositeDateTimeFieldSet, CompositeFieldSet};
12use crate::provider::fields::{self, FieldLength, FieldSymbol};
13use crate::provider::neo::{marker_attrs, *};
14use crate::provider::pattern::PatternItem;
15use crate::provider::time_zones::tz;
16use crate::size_test_macro::size_test;
17use crate::FixedCalendarDateTimeFormatter;
18use crate::{external_loaders::*, DateTimeFormatterPreferences};
19use crate::{scaffold::*, DateTimeFormatter, DateTimeFormatterLoadError};
20use core::fmt;
21use core::marker::PhantomData;
22use icu_calendar::types::EraYear;
23use icu_calendar::AnyCalendar;
24use icu_decimal::options::DecimalFormatterOptions;
25use icu_decimal::options::GroupingStrategy;
26use icu_decimal::provider::{DecimalDigitsV1, DecimalSymbolsV1};
27use icu_decimal::DecimalFormatter;
28use icu_provider::prelude::*;
29
30/// Choices for loading year names.
31#[derive(Debug, Copy, Clone, PartialEq, Eq)]
32#[non_exhaustive]
33pub enum YearNameLength {
34 /// An abbreviated calendar-dependent year or era name.
35 ///
36 /// Examples:
37 ///
38 /// - "AD"
39 /// - "甲子"
40 Abbreviated,
41 /// A wide calendar-dependent year or era name.
42 ///
43 /// Examples:
44 ///
45 /// - "Anno Domini"
46 /// - "甲子"
47 Wide,
48 /// A narrow calendar-dependent year or era name. Not necesarily unique.
49 ///
50 /// Examples:
51 ///
52 /// - "A"
53 /// - "甲子"
54 Narrow,
55}
56
57impl YearNameLength {
58 pub(crate) fn to_attributes(self) -> &'static DataMarkerAttributes {
59 use marker_attrs::Length;
60 let length = match self {
61 YearNameLength::Abbreviated => Length::Abbr,
62 YearNameLength::Wide => Length::Wide,
63 YearNameLength::Narrow => Length::Narrow,
64 };
65 marker_attrs::name_attr_for(marker_attrs::Context::Format, length)
66 }
67
68 pub(crate) fn from_field_length(field_length: FieldLength) -> Option<Self> {
69 // UTS 35 says that "G..GGG" and "U..UUU" are all Abbreviated
70 let field_length = field_length.numeric_to_abbr();
71 match field_length {
72 FieldLength::Three => Some(YearNameLength::Abbreviated),
73 FieldLength::Four => Some(YearNameLength::Wide),
74 FieldLength::Five => Some(YearNameLength::Narrow),
75 _ => None,
76 }
77 }
78
79 /// Returns an [`ErrorField`] sufficient for error reporting.
80 pub(crate) fn to_approximate_error_field(self) -> ErrorField {
81 let field_length = match self {
82 YearNameLength::Abbreviated => FieldLength::Three,
83 YearNameLength::Wide => FieldLength::Four,
84 YearNameLength::Narrow => FieldLength::Five,
85 };
86 ErrorField(fields::Field {
87 symbol: FieldSymbol::Era,
88 length: field_length,
89 })
90 }
91}
92
93/// Choices for loading month names.
94#[derive(Debug, Copy, Clone, PartialEq, Eq)]
95#[non_exhaustive]
96pub enum MonthNameLength {
97 /// An abbreviated calendar-dependent month name for formatting with other fields.
98 ///
99 /// Example: "Sep"
100 Abbreviated,
101 /// A wide calendar-dependent month name for formatting with other fields.
102 ///
103 /// Example: "September"
104 Wide,
105 /// A narrow calendar-dependent month name for formatting with other fields. Not necesarily unique.
106 ///
107 /// Example: "S"
108 Narrow,
109 /// An abbreviated calendar-dependent month name for stand-alone display.
110 ///
111 /// Example: "Sep"
112 StandaloneAbbreviated,
113 /// A wide calendar-dependent month name for stand-alone display.
114 ///
115 /// Example: "September"
116 StandaloneWide,
117 /// A narrow calendar-dependent month name for stand-alone display. Not necesarily unique.
118 ///
119 /// Example: "S"
120 StandaloneNarrow,
121}
122
123impl MonthNameLength {
124 pub(crate) fn to_attributes(self) -> &'static DataMarkerAttributes {
125 use marker_attrs::{Context, Length};
126 let (context, length) = match self {
127 MonthNameLength::Abbreviated => (Context::Format, Length::Abbr),
128 MonthNameLength::Wide => (Context::Format, Length::Wide),
129 MonthNameLength::Narrow => (Context::Format, Length::Narrow),
130 MonthNameLength::StandaloneAbbreviated => (Context::Standalone, Length::Abbr),
131 MonthNameLength::StandaloneWide => (Context::Standalone, Length::Wide),
132 MonthNameLength::StandaloneNarrow => (Context::Standalone, Length::Narrow),
133 };
134 marker_attrs::name_attr_for(context, length)
135 }
136
137 pub(crate) fn from_field(
138 field_symbol: fields::Month,
139 field_length: FieldLength,
140 ) -> Option<Self> {
141 use fields::Month;
142 match (field_symbol, field_length) {
143 (Month::Format, FieldLength::Three) => Some(MonthNameLength::Abbreviated),
144 (Month::Format, FieldLength::Four) => Some(MonthNameLength::Wide),
145 (Month::Format, FieldLength::Five) => Some(MonthNameLength::Narrow),
146 (Month::StandAlone, FieldLength::Three) => Some(MonthNameLength::StandaloneAbbreviated),
147 (Month::StandAlone, FieldLength::Four) => Some(MonthNameLength::StandaloneWide),
148 (Month::StandAlone, FieldLength::Five) => Some(MonthNameLength::StandaloneNarrow),
149 _ => None,
150 }
151 }
152
153 /// Returns an [`ErrorField`] sufficient for error reporting.
154 pub(crate) fn to_approximate_error_field(self) -> ErrorField {
155 use fields::Month;
156 let (field_symbol, field_length) = match self {
157 MonthNameLength::Abbreviated => (Month::Format, FieldLength::Three),
158 MonthNameLength::Wide => (Month::Format, FieldLength::Four),
159 MonthNameLength::Narrow => (Month::Format, FieldLength::Five),
160 MonthNameLength::StandaloneAbbreviated => (Month::StandAlone, FieldLength::Three),
161 MonthNameLength::StandaloneWide => (Month::StandAlone, FieldLength::Four),
162 MonthNameLength::StandaloneNarrow => (Month::StandAlone, FieldLength::Five),
163 };
164 ErrorField(fields::Field {
165 symbol: FieldSymbol::Month(field_symbol),
166 length: field_length,
167 })
168 }
169}
170
171/// Choices for loading weekday names.
172#[derive(Debug, Copy, Clone, PartialEq, Eq)]
173#[non_exhaustive]
174pub enum WeekdayNameLength {
175 /// An abbreviated weekday name for formatting with other fields.
176 ///
177 /// Example: "Tue"
178 Abbreviated,
179 /// A wide weekday name for formatting with other fields.
180 ///
181 /// Example: "Tuesday"
182 Wide,
183 /// A narrow weekday name for formatting with other fields. Not necesarily unique.
184 ///
185 /// Example: "T"
186 Narrow,
187 /// A short weekday name for formatting with other fields.
188 ///
189 /// Example: "Tu"
190 Short,
191 /// An abbreviated weekday name for stand-alone display.
192 ///
193 /// Example: "Tue"
194 StandaloneAbbreviated,
195 /// A wide weekday name for stand-alone display.
196 ///
197 /// Example: "Tuesday"
198 StandaloneWide,
199 /// A narrow weekday name for stand-alone display. Not necesarily unique.
200 ///
201 /// Example: "T"
202 StandaloneNarrow,
203 /// A short weekday name for stand-alone display.
204 ///
205 /// Example: "Tu"
206 StandaloneShort,
207}
208
209impl WeekdayNameLength {
210 pub(crate) fn to_attributes(self) -> &'static DataMarkerAttributes {
211 use marker_attrs::{Context, Length};
212 // UTS 35 says that "e" and "E" have the same non-numeric names
213 let (context, length) = match self {
214 WeekdayNameLength::Abbreviated => (Context::Format, Length::Abbr),
215 WeekdayNameLength::Wide => (Context::Format, Length::Wide),
216 WeekdayNameLength::Narrow => (Context::Format, Length::Narrow),
217 WeekdayNameLength::Short => (Context::Format, Length::Short),
218 WeekdayNameLength::StandaloneAbbreviated => (Context::Standalone, Length::Abbr),
219 WeekdayNameLength::StandaloneWide => (Context::Standalone, Length::Wide),
220 WeekdayNameLength::StandaloneNarrow => (Context::Standalone, Length::Narrow),
221 WeekdayNameLength::StandaloneShort => (Context::Standalone, Length::Short),
222 };
223 marker_attrs::name_attr_for(context, length)
224 }
225
226 pub(crate) fn from_field(
227 field_symbol: fields::Weekday,
228 field_length: FieldLength,
229 ) -> Option<Self> {
230 use fields::Weekday;
231 // UTS 35 says that "e" and "E" have the same non-numeric names
232 let field_symbol = field_symbol.to_format_symbol();
233 // UTS 35 says that "E..EEE" are all Abbreviated
234 // However, this doesn't apply to "e" and "c".
235 let field_length = if matches!(field_symbol, fields::Weekday::Format) {
236 field_length.numeric_to_abbr()
237 } else {
238 field_length
239 };
240 match (field_symbol, field_length) {
241 (Weekday::Format, FieldLength::Three) => Some(WeekdayNameLength::Abbreviated),
242 (Weekday::Format, FieldLength::Four) => Some(WeekdayNameLength::Wide),
243 (Weekday::Format, FieldLength::Five) => Some(WeekdayNameLength::Narrow),
244 (Weekday::Format, FieldLength::Six) => Some(WeekdayNameLength::Short),
245 (Weekday::StandAlone, FieldLength::Three) => {
246 Some(WeekdayNameLength::StandaloneAbbreviated)
247 }
248 (Weekday::StandAlone, FieldLength::Four) => Some(WeekdayNameLength::StandaloneWide),
249 (Weekday::StandAlone, FieldLength::Five) => Some(WeekdayNameLength::StandaloneNarrow),
250 (Weekday::StandAlone, FieldLength::Six) => Some(WeekdayNameLength::StandaloneShort),
251 _ => None,
252 }
253 }
254
255 /// Returns an [`ErrorField`] sufficient for error reporting.
256 pub(crate) fn to_approximate_error_field(self) -> ErrorField {
257 use fields::Weekday;
258 let (field_symbol, field_length) = match self {
259 WeekdayNameLength::Abbreviated => (Weekday::Format, FieldLength::Three),
260 WeekdayNameLength::Wide => (Weekday::Format, FieldLength::Four),
261 WeekdayNameLength::Narrow => (Weekday::Format, FieldLength::Five),
262 WeekdayNameLength::Short => (Weekday::Format, FieldLength::Six),
263 WeekdayNameLength::StandaloneAbbreviated => (Weekday::StandAlone, FieldLength::Three),
264 WeekdayNameLength::StandaloneWide => (Weekday::StandAlone, FieldLength::Four),
265 WeekdayNameLength::StandaloneNarrow => (Weekday::StandAlone, FieldLength::Five),
266 WeekdayNameLength::StandaloneShort => (Weekday::StandAlone, FieldLength::Six),
267 };
268 ErrorField(fields::Field {
269 symbol: FieldSymbol::Weekday(field_symbol),
270 length: field_length,
271 })
272 }
273}
274
275/// Choices for loading day period names.
276#[derive(Debug, Copy, Clone, PartialEq, Eq)]
277#[non_exhaustive]
278pub enum DayPeriodNameLength {
279 /// An abbreviated 12-hour day period name, including display names for 0h and 12h.
280 ///
281 /// Examples:
282 ///
283 /// - "AM"
284 /// - "mid."
285 Abbreviated,
286 /// A wide 12-hour day period name, including display names for 0h and 12h.
287 ///
288 /// The wide form may be the same as the abbreviated form if the "real" long form
289 /// (eg "ante meridiem") is not customarily used.
290 ///
291 /// Examples:
292 ///
293 /// - "AM"
294 /// - "mignight"
295 Wide,
296 /// An abbreviated 12-hour day period name, including display names for 0h and 12h.
297 ///
298 /// The narrow form must be unique, unlike some other fields.
299 ///
300 /// Examples:
301 ///
302 /// - "AM"
303 /// - "md"
304 Narrow,
305}
306
307impl DayPeriodNameLength {
308 pub(crate) fn to_attributes(self) -> &'static DataMarkerAttributes {
309 use marker_attrs::Length;
310 let length = match self {
311 DayPeriodNameLength::Abbreviated => Length::Abbr,
312 DayPeriodNameLength::Wide => Length::Wide,
313 DayPeriodNameLength::Narrow => Length::Narrow,
314 };
315 marker_attrs::name_attr_for(marker_attrs::Context::Format, length)
316 }
317
318 pub(crate) fn from_field(
319 field_symbol: fields::DayPeriod,
320 field_length: FieldLength,
321 ) -> Option<Self> {
322 use fields::DayPeriod;
323 // Names for 'a' and 'b' are stored in the same data marker
324 let field_symbol = match field_symbol {
325 DayPeriod::NoonMidnight => DayPeriod::AmPm,
326 other => other,
327 };
328 // UTS 35 says that "a..aaa" and "b..bbb" are all Abbreviated
329 let field_length = field_length.numeric_to_abbr();
330 match (field_symbol, field_length) {
331 (DayPeriod::AmPm, FieldLength::Three) => Some(DayPeriodNameLength::Abbreviated),
332 (DayPeriod::AmPm, FieldLength::Four) => Some(DayPeriodNameLength::Wide),
333 (DayPeriod::AmPm, FieldLength::Five) => Some(DayPeriodNameLength::Narrow),
334 _ => None,
335 }
336 }
337
338 /// Returns an [`ErrorField`] sufficient for error reporting.
339 pub(crate) fn to_approximate_error_field(self) -> ErrorField {
340 // Names for 'a' and 'b' are stored in the same data marker
341 let field_symbol = fields::DayPeriod::AmPm;
342 let field_length = match self {
343 DayPeriodNameLength::Abbreviated => FieldLength::Three,
344 DayPeriodNameLength::Wide => FieldLength::Four,
345 DayPeriodNameLength::Narrow => FieldLength::Five,
346 };
347 ErrorField(fields::Field {
348 symbol: FieldSymbol::DayPeriod(field_symbol),
349 length: field_length,
350 })
351 }
352}
353
354pub(crate) struct EmptyDataProvider;
355
356impl<M> DataProvider<M> for EmptyDataProvider
357where
358 M: DataMarker,
359{
360 fn load(&self, base_req: DataRequest) -> Result<DataResponse<M>, DataError> {
361 Err(DataErrorKind::MarkerNotFound.with_req(M::INFO, base_req))
362 }
363}
364
365size_test!(
366 FixedCalendarDateTimeNames<icu_calendar::Gregorian>,
367 typed_date_time_names_size,
368 328
369);
370
371/// A low-level type that formats datetime patterns with localized names.
372/// The calendar should be chosen at compile time.
373#[doc = typed_date_time_names_size!()]
374///
375/// Type parameters:
376///
377/// 1. The calendar chosen at compile time for additional type safety
378/// 2. A field set containing the fields that might be formatted
379///
380/// By default, the field set is set to [`CompositeDateTimeFieldSet`],
381/// meaning that dates and times, but not time zones, are supported. A smaller
382/// field set results in smaller stack size.
383///
384/// To support all fields including time zones, use [`CompositeFieldSet`].
385///
386/// [`CompositeFieldSet`]: crate::fieldsets::enums::CompositeFieldSet
387/// [`CompositeDateTimeFieldSet`]: crate::fieldsets::enums::CompositeDateTimeFieldSet
388///
389/// # Examples
390///
391/// ```
392/// use icu::calendar::Gregorian;
393/// use icu::datetime::input::Date;
394/// use icu::datetime::pattern::FixedCalendarDateTimeNames;
395/// use icu::datetime::pattern::DateTimePattern;
396/// use icu::datetime::pattern::MonthNameLength;
397/// use icu::datetime::pattern::WeekdayNameLength;
398/// use icu::datetime::pattern::DayPeriodNameLength;
399/// use icu::locale::locale;
400/// use icu::datetime::input::{DateTime, Time};
401/// use writeable::assert_try_writeable_eq;
402///
403/// // Create an instance that can format abbreviated month, weekday, and day period names:
404/// let mut names: FixedCalendarDateTimeNames<Gregorian> =
405/// FixedCalendarDateTimeNames::try_new(locale!("uk").into()).unwrap();
406/// names
407/// .include_month_names(MonthNameLength::Abbreviated)
408/// .unwrap()
409/// .include_weekday_names(WeekdayNameLength::Abbreviated)
410/// .unwrap()
411/// .include_day_period_names(DayPeriodNameLength::Abbreviated)
412/// .unwrap();
413///
414/// // Create a pattern from a pattern string (note: K is the hour with h11 hour cycle):
415/// let pattern_str = "E MMM d y -- K:mm a";
416/// let pattern: DateTimePattern = pattern_str.parse().unwrap();
417///
418/// // Test it:
419/// let datetime = DateTime { date: Date::try_new_gregorian(2023, 11, 20).unwrap(), time: Time::try_new(12, 35, 3, 0).unwrap() };
420/// assert_try_writeable_eq!(names.with_pattern_unchecked(&pattern).format(&datetime), "пн лист. 20 2023 -- 0:35 пп");
421/// ```
422///
423/// If the correct data is not loaded, an error will occur:
424///
425/// ```
426/// use icu::calendar::Gregorian;
427/// use icu::datetime::input::Date;
428/// use icu::datetime::pattern::FormattedDateTimePatternError;
429/// use icu::datetime::parts;
430/// use icu::datetime::pattern::FixedCalendarDateTimeNames;
431/// use icu::datetime::pattern::{DateTimePattern, PatternLoadError};
432/// use icu::datetime::fieldsets::enums::CompositeFieldSet;
433/// use icu::locale::locale;
434/// use icu::time::zone::IanaParser;
435/// use icu::datetime::input::{Time, TimeZoneInfo, ZonedDateTime};
436/// use icu_provider_adapters::empty::EmptyDataProvider;
437/// use writeable::{Part, assert_try_writeable_parts_eq};
438///
439/// // Unstable API used only for error construction below
440/// use icu::datetime::provider::fields::{Field, FieldLength, FieldSymbol, Weekday};
441///
442/// // Create an instance that can format all fields (CompositeFieldSet):
443/// let mut names: FixedCalendarDateTimeNames<Gregorian, CompositeFieldSet> =
444/// FixedCalendarDateTimeNames::try_new(locale!("en").into()).unwrap();
445///
446/// // Create a pattern from a pattern string:
447/// let pattern_str = "'It is:' E MMM d y G 'at' h:mm:ssSSS a zzzz";
448/// let pattern: DateTimePattern = pattern_str.parse().unwrap();
449///
450/// // The pattern string contains lots of symbols including "E", "MMM", and "a",
451/// // but we did not load any data!
452///
453/// let mut dtz = ZonedDateTime::try_strict_from_str("2023-11-20T11:35:03+00:00[Europe/London]", Gregorian, IanaParser::new()).unwrap();
454///
455/// // Missing data is filled in on a best-effort basis, and an error is signaled.
456/// assert_try_writeable_parts_eq!(
457/// names.with_pattern_unchecked(&pattern).format(&dtz),
458/// "It is: mon M11 20 2023 ce at 11:35:03.000 AM +0000",
459/// Err(FormattedDateTimePatternError::NamesNotLoaded(Field { symbol: FieldSymbol::Weekday(Weekday::Format), length: FieldLength::One }.into())),
460/// [
461/// (7, 10, Part::ERROR), // mon
462/// (7, 10, parts::WEEKDAY), // mon
463/// (11, 14, Part::ERROR), // M11
464/// (11, 14, parts::MONTH), // M11
465/// (15, 17, icu::decimal::parts::INTEGER), // 20
466/// (15, 17, parts::DAY), // 20
467/// (18, 22, icu::decimal::parts::INTEGER), // 2023
468/// (18, 22, parts::YEAR), // 2023
469/// (23, 25, Part::ERROR), // CE
470/// (23, 25, parts::ERA), // CE
471/// (29, 31, icu::decimal::parts::INTEGER), // 11
472/// (29, 31, parts::HOUR), // 11
473/// (32, 34, icu::decimal::parts::INTEGER), // 35
474/// (32, 34, parts::MINUTE), // 35
475/// (35, 41, parts::SECOND), // 03.000
476/// (35, 37, icu::decimal::parts::INTEGER), // 03
477/// (37, 38, icu::decimal::parts::DECIMAL), // .
478/// (38, 41, icu::decimal::parts::FRACTION), // 000
479/// (42, 44, Part::ERROR), // AM
480/// (42, 44, parts::DAY_PERIOD), // AM
481/// (45, 50, Part::ERROR), // +0000
482/// (45, 50, parts::TIME_ZONE_NAME), // +0000
483/// ]
484/// );
485///
486/// // To make the error occur sooner, one can use an EmptyDataProvider:
487/// let empty = EmptyDataProvider::new();
488/// assert!(matches!(
489/// names.load_for_pattern(&empty, &pattern),
490/// Err(PatternLoadError::Data(_, _)),
491/// ));
492/// ```
493///
494/// If the pattern contains fields inconsistent with the receiver, an error will occur:
495///
496/// ```
497/// use icu::calendar::Gregorian;
498/// use icu::datetime::pattern::FormattedDateTimePatternError;
499/// use icu::datetime::parts;
500/// use icu::datetime::pattern::FixedCalendarDateTimeNames;
501/// use icu::datetime::pattern::DateTimePattern;
502/// use icu::datetime::unchecked::MissingInputFieldKind;
503/// use icu::datetime::fieldsets::zone::LocalizedOffsetLong;
504/// use icu::locale::locale;
505/// use icu::datetime::input::{DateTime, TimeZoneInfo};
506/// use writeable::{Part, assert_try_writeable_parts_eq};
507///
508/// // Create an instance that can format abbreviated month, weekday, and day period names:
509/// let mut names: FixedCalendarDateTimeNames<Gregorian, LocalizedOffsetLong> =
510/// FixedCalendarDateTimeNames::try_new(locale!("en").into()).unwrap();
511///
512/// // Create a pattern from a pattern string:
513/// let pattern_str = "'It is:' E MMM d y G 'at' h:mm:ssSSS a zzzz";
514/// let pattern: DateTimePattern = pattern_str.parse().unwrap();
515///
516/// // The pattern string contains lots of symbols including "E", "MMM", and "a",
517/// // but the `FixedCalendarDateTimeNames` is configured to format only time zones!
518/// // Further, the time zone we provide doesn't contain any offset into!
519/// // Missing data is filled in on a best-effort basis, and an error is signaled.
520/// assert_try_writeable_parts_eq!(
521/// names.with_pattern_unchecked(&pattern).format(&TimeZoneInfo::unknown()),
522/// "It is: {E} {M} {d} {y} {G} at {h}:{m}:{s} {a} {z}",
523/// Err(FormattedDateTimePatternError::MissingInputField(MissingInputFieldKind::Weekday)),
524/// [
525/// (7, 10, Part::ERROR), // {E}
526/// (7, 10, parts::WEEKDAY), // {E}
527/// (11, 14, Part::ERROR), // {M}
528/// (11, 14, parts::MONTH), // {M}
529/// (15, 18, Part::ERROR), // {d}
530/// (15, 18, parts::DAY), // {d}
531/// (19, 22, Part::ERROR), // {y}
532/// (19, 22, parts::YEAR), // {y}
533/// (23, 26, Part::ERROR), // {G}
534/// (23, 26, parts::ERA), // {G}
535/// (30, 33, Part::ERROR), // {h}
536/// (30, 33, parts::HOUR), // {h}
537/// (34, 37, Part::ERROR), // {m}
538/// (34, 37, parts::MINUTE), // {m}
539/// (38, 41, Part::ERROR), // {s}
540/// (38, 41, parts::SECOND), // {s}
541/// (42, 45, Part::ERROR), // {a}
542/// (42, 45, parts::DAY_PERIOD), // {a}
543/// (46, 49, Part::ERROR), // {z}
544/// (46, 49, parts::TIME_ZONE_NAME), // {z}
545/// ]
546/// );
547/// ```
548///
549/// Multiple types of time zone data can be loaded into a [`FixedCalendarDateTimeNames`]:
550///
551/// ```
552/// use icu::datetime::pattern::FixedCalendarDateTimeNames;
553/// use icu::datetime::fieldsets::enums::ZoneFieldSet;
554/// use icu::locale::locale;
555/// use icu::datetime::input::{DateTime, Time};
556/// use writeable::assert_try_writeable_eq;
557///
558/// // Create an instance that can format abbreviated month, weekday, and day period names:
559/// let mut names: FixedCalendarDateTimeNames<(), ZoneFieldSet> =
560/// FixedCalendarDateTimeNames::try_new(locale!("uk").into()).unwrap();
561///
562/// // Load the names for generic short:
563/// names.include_time_zone_essentials().unwrap();
564/// names.include_time_zone_generic_short_names().unwrap();
565/// names.include_time_zone_location_names().unwrap();
566///
567/// // The same functions can be called a second time (nothing will happen):
568/// names.include_time_zone_essentials().unwrap();
569/// names.include_time_zone_generic_short_names().unwrap();
570/// names.include_time_zone_location_names().unwrap();
571///
572/// // We can load names for a different zone style:
573/// names.include_time_zone_generic_long_names().unwrap();
574/// ```
575///
576/// However, new time zone names cannot be added into a formatter that already has them. If you
577/// need this functionality, see <https://github.com/unicode-org/icu4x/issues/6063>
578///
579/// ```
580/// use icu::datetime::fieldsets::enums::ZoneFieldSet;
581/// use icu::datetime::fieldsets::zone;
582/// use icu::datetime::pattern::FixedCalendarDateTimeNames;
583/// use icu::datetime::NoCalendarFormatter;
584/// use icu::locale::locale;
585/// use icu_datetime::pattern::PatternLoadError;
586/// use icu_provider::DataError;
587/// use icu_provider::DataErrorKind;
588///
589/// let prefs = locale!("uk").into();
590///
591/// // Create a formatter for generic long time zones:
592/// let formatter =
593/// NoCalendarFormatter::try_new(prefs, zone::GenericLong).unwrap();
594///
595/// // Convert it to a FixedCalendarDateTimeNames:
596/// let mut names =
597/// FixedCalendarDateTimeNames::from_formatter(prefs, formatter)
598/// .cast_into_fset::<ZoneFieldSet>();
599///
600/// // Specific names cannot be added:
601/// assert!(matches!(
602/// names.include_time_zone_specific_long_names(),
603/// Err(PatternLoadError::Data(
604/// DataError {
605/// kind: DataErrorKind::InconsistentData(_),
606/// ..
607/// },
608/// _
609/// ))
610/// ));
611/// ```
612#[derive(Debug, Clone)]
613pub struct FixedCalendarDateTimeNames<C, FSet: DateTimeNamesMarker = CompositeDateTimeFieldSet> {
614 prefs: DateTimeFormatterPreferences,
615 inner: RawDateTimeNames<FSet>,
616 metadata: DateTimeNamesMetadata,
617 _calendar: PhantomData<C>,
618}
619
620/// Extra metadata associated with DateTimeNames but not DateTimeFormatter.
621#[derive(Debug, Clone)]
622pub(crate) struct DateTimeNamesMetadata {
623 zone_checksum: Option<u64>,
624}
625
626impl DateTimeNamesMetadata {
627 /// No impl Default: emphasize when we create a new empty instance
628 #[inline]
629 pub(crate) fn new_empty() -> Self {
630 Self {
631 zone_checksum: None,
632 }
633 }
634 /// If mz_periods is already populated, we can't load anything else because
635 /// we can't verify the checksum. Set a blank checksum in this case.
636 #[inline]
637 pub(crate) fn new_from_previous<M: DateTimeNamesMarker>(names: &RawDateTimeNames<M>) -> Self {
638 if names.mz_periods.get().inner.get_option().is_some() {
639 Self {
640 zone_checksum: Some(0),
641 }
642 } else {
643 Self::new_empty()
644 }
645 }
646}
647
648/// A low-level type that formats datetime patterns with localized names.
649/// The calendar is chosen in the constructor at runtime.
650///
651/// Currently this only supports loading of non-calendar-specific names, but
652/// additional functions may be added in the future. If you need this, see
653/// <https://github.com/unicode-org/icu4x/issues/6107>
654#[derive(Debug, Clone)]
655pub struct DateTimeNames<FSet: DateTimeNamesMarker> {
656 inner: FixedCalendarDateTimeNames<(), FSet>,
657 calendar: FormattableAnyCalendar,
658}
659
660pub(crate) struct RawDateTimeNames<FSet: DateTimeNamesMarker> {
661 year_names: <FSet::YearNames as NamesContainer<YearNamesV1, YearNameLength>>::Container,
662 month_names: <FSet::MonthNames as NamesContainer<MonthNamesV1, MonthNameLength>>::Container,
663 weekday_names:
664 <FSet::WeekdayNames as NamesContainer<WeekdayNamesV1, WeekdayNameLength>>::Container,
665 dayperiod_names:
666 <FSet::DayPeriodNames as NamesContainer<DayPeriodNamesV1, DayPeriodNameLength>>::Container,
667 zone_essentials: <FSet::ZoneEssentials as NamesContainer<tz::EssentialsV1, ()>>::Container,
668 locations_root: <FSet::ZoneLocationsRoot as NamesContainer<tz::LocationsRootV1, ()>>::Container,
669 locations: <FSet::ZoneLocations as NamesContainer<tz::LocationsOverrideV1, ()>>::Container,
670 exemplars_root: <FSet::ZoneExemplarsRoot as NamesContainer<tz::CitiesRootV1, ()>>::Container,
671 exemplars: <FSet::ZoneExemplars as NamesContainer<tz::CitiesOverrideV1, ()>>::Container,
672 mz_generic_long: <FSet::ZoneGenericLong as NamesContainer<tz::MzGenericLongV1, ()>>::Container,
673 mz_generic_short:
674 <FSet::ZoneGenericShort as NamesContainer<tz::MzGenericShortV1, ()>>::Container,
675 mz_standard_long:
676 <FSet::ZoneStandardLong as NamesContainer<tz::MzStandardLongV1, ()>>::Container,
677 mz_specific_long:
678 <FSet::ZoneSpecificLong as NamesContainer<tz::MzSpecificLongV1, ()>>::Container,
679 mz_specific_short:
680 <FSet::ZoneSpecificShort as NamesContainer<tz::MzSpecificShortV1, ()>>::Container,
681 mz_periods: <FSet::MetazoneLookup as NamesContainer<tz::MzPeriodV1, ()>>::Container,
682 // TODO(#4340): Make the DecimalFormatter optional
683 decimal_formatter: Option<DecimalFormatter>,
684 _marker: PhantomData<FSet>,
685}
686
687// Need a custom impl because not all of the associated types impl Debug
688impl<FSet: DateTimeNamesMarker> fmt::Debug for RawDateTimeNames<FSet> {
689 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
690 f.debug_struct("RawDateTimeNames")
691 .field("year_names", &self.year_names)
692 .field("month_names", &self.month_names)
693 .field("weekday_names", &self.weekday_names)
694 .field("dayperiod_names", &self.dayperiod_names)
695 .field("zone_essentials", &self.zone_essentials)
696 .field("locations_root", &self.locations_root)
697 .field("locations", &self.locations)
698 .field("exemplars_root", &self.exemplars_root)
699 .field("exemplars", &self.exemplars)
700 .field("mz_generic_long", &self.mz_generic_long)
701 .field("mz_generic_short", &self.mz_generic_short)
702 .field("mz_standard_long", &self.mz_standard_long)
703 .field("mz_specific_long", &self.mz_specific_long)
704 .field("mz_specific_short", &self.mz_specific_short)
705 .field("mz_periods", &self.mz_periods)
706 .field("decimal_formatter", &self.decimal_formatter)
707 .finish()
708 }
709}
710
711impl<FSet: DateTimeNamesMarker> Clone for RawDateTimeNames<FSet> {
712 fn clone(&self) -> Self {
713 Self {
714 year_names: self.year_names.clone(),
715 month_names: self.month_names.clone(),
716 weekday_names: self.weekday_names.clone(),
717 dayperiod_names: self.dayperiod_names.clone(),
718 zone_essentials: self.zone_essentials.clone(),
719 locations_root: self.locations_root.clone(),
720 locations: self.locations.clone(),
721 exemplars_root: self.exemplars_root.clone(),
722 exemplars: self.exemplars.clone(),
723 mz_generic_long: self.mz_generic_long.clone(),
724 mz_generic_short: self.mz_generic_short.clone(),
725 mz_standard_long: self.mz_standard_long.clone(),
726 mz_specific_long: self.mz_specific_long.clone(),
727 mz_specific_short: self.mz_specific_short.clone(),
728 mz_periods: self.mz_periods.clone(),
729 decimal_formatter: self.decimal_formatter.clone(),
730 _marker: PhantomData,
731 }
732 }
733}
734
735impl<FSet: DateTimeNamesMarker> RawDateTimeNames<FSet> {
736 pub(crate) fn cast_into_fset<FSet2: DateTimeNamesFrom<FSet>>(self) -> RawDateTimeNames<FSet2> {
737 RawDateTimeNames {
738 year_names: FSet2::map_year_names(self.year_names),
739 month_names: FSet2::map_month_names(self.month_names),
740 weekday_names: FSet2::map_weekday_names(self.weekday_names),
741 dayperiod_names: FSet2::map_day_period_names(self.dayperiod_names),
742 zone_essentials: FSet2::map_zone_essentials(self.zone_essentials),
743 locations_root: FSet2::map_zone_locations_root(self.locations_root),
744 locations: FSet2::map_zone_locations(self.locations),
745 exemplars_root: FSet2::map_zone_exemplars_root(self.exemplars_root),
746 exemplars: FSet2::map_zone_exemplars(self.exemplars),
747 mz_generic_long: FSet2::map_zone_generic_long(self.mz_generic_long),
748 mz_generic_short: FSet2::map_zone_generic_short(self.mz_generic_short),
749 mz_standard_long: FSet2::map_zone_standard_long(self.mz_standard_long),
750 mz_specific_long: FSet2::map_zone_specific_long(self.mz_specific_long),
751 mz_specific_short: FSet2::map_zone_specific_short(self.mz_specific_short),
752 mz_periods: FSet2::map_metazone_lookup(self.mz_periods),
753 decimal_formatter: self.decimal_formatter,
754 _marker: PhantomData,
755 }
756 }
757}
758
759#[derive(Debug, Copy, Clone)]
760pub(crate) struct RawDateTimeNamesBorrowed<'l> {
761 year_names: OptionalNames<YearNameLength, &'l YearNames<'l>>,
762 month_names: OptionalNames<MonthNameLength, &'l MonthNames<'l>>,
763 weekday_names: OptionalNames<WeekdayNameLength, &'l LinearNames<'l>>,
764 dayperiod_names: OptionalNames<DayPeriodNameLength, &'l LinearNames<'l>>,
765 zone_essentials: OptionalNames<(), &'l tz::Essentials<'l>>,
766 locations_root: OptionalNames<(), &'l tz::Locations<'l>>,
767 locations: OptionalNames<(), &'l tz::Locations<'l>>,
768 exemplars_root: OptionalNames<(), &'l tz::ExemplarCities<'l>>,
769 exemplars: OptionalNames<(), &'l tz::ExemplarCities<'l>>,
770 mz_generic_long: OptionalNames<(), &'l tz::MzGeneric<'l>>,
771 mz_standard_long: OptionalNames<(), &'l tz::MzGeneric<'l>>,
772 mz_generic_short: OptionalNames<(), &'l tz::MzGeneric<'l>>,
773 mz_specific_long: OptionalNames<(), &'l tz::MzSpecific<'l>>,
774 mz_specific_short: OptionalNames<(), &'l tz::MzSpecific<'l>>,
775 mz_periods: OptionalNames<(), &'l tz::MzPeriod<'l>>,
776 pub(crate) decimal_formatter: Option<&'l DecimalFormatter>,
777}
778
779impl<C, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
780 /// Constructor that takes a selected locale and creates an empty instance.
781 ///
782 /// For an example, see [`FixedCalendarDateTimeNames`].
783 ///
784 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
785 ///
786 /// [📚 Help choosing a constructor](icu_provider::constructors)
787 #[cfg(feature = "compiled_data")]
788 pub fn try_new(prefs: DateTimeFormatterPreferences) -> Result<Self, DataError> {
789 let mut names = Self {
790 prefs,
791 inner: RawDateTimeNames::new_without_number_formatting(),
792 metadata: DateTimeNamesMetadata::new_empty(), // OK: this is a constructor
793 _calendar: PhantomData,
794 };
795 names.include_decimal_formatter()?;
796 Ok(names)
797 }
798
799 #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::try_new)]
800 pub fn try_new_unstable<P>(
801 provider: &P,
802 prefs: DateTimeFormatterPreferences,
803 ) -> Result<Self, DataError>
804 where
805 P: DataProvider<DecimalSymbolsV1> + DataProvider<DecimalDigitsV1> + ?Sized,
806 {
807 let mut names = Self {
808 prefs,
809 inner: RawDateTimeNames::new_without_number_formatting(),
810 metadata: DateTimeNamesMetadata::new_empty(), // OK: this is a constructor
811 _calendar: PhantomData,
812 };
813 names.load_decimal_formatter(provider)?;
814 Ok(names)
815 }
816
817 icu_provider::gen_buffer_data_constructors!(
818 (prefs: DateTimeFormatterPreferences) -> error: DataError,
819 functions: [
820 try_new: skip,
821 try_new_with_buffer_provider,
822 try_new_unstable,
823 Self,
824 ]
825 );
826
827 /// Creates a completely empty instance, not even with number formatting.
828 ///
829 /// # Examples
830 ///
831 /// Errors occur if a number formatter is not loaded but one is required:
832 ///
833 /// ```
834 /// use icu::calendar::Gregorian;
835 /// use icu::datetime::input::Date;
836 /// use icu::datetime::parts;
837 /// use icu::datetime::pattern::FormattedDateTimePatternError;
838 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
839 /// use icu::datetime::pattern::DateTimePattern;
840 /// use icu::datetime::fieldsets::enums::DateFieldSet;
841 /// use icu::locale::locale;
842 /// use writeable::{Part, assert_try_writeable_parts_eq};
843 ///
844 /// // Create an instance that can format only date fields:
845 /// let names: FixedCalendarDateTimeNames<Gregorian, DateFieldSet> =
846 /// FixedCalendarDateTimeNames::new_without_number_formatting(locale!("en").into());
847 ///
848 /// // Create a pattern from a pattern string:
849 /// let pattern_str = "'It is:' y-MM-dd";
850 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
851 ///
852 /// // The pattern string contains lots of numeric symbols,
853 /// // but we did not load any data!
854 ///
855 /// let date = Date::try_new_gregorian(2024, 7, 1).unwrap();
856 ///
857 /// // Missing data is filled in on a best-effort basis, and an error is signaled.
858 /// // (note that the padding is ignored in this fallback mode)
859 /// assert_try_writeable_parts_eq!(
860 /// names.with_pattern_unchecked(&pattern).format(&date),
861 /// "It is: 2024-07-01",
862 /// Err(FormattedDateTimePatternError::DecimalFormatterNotLoaded),
863 /// [
864 /// (7, 11, Part::ERROR), // 2024
865 /// (7, 11, parts::YEAR), // 2024
866 /// (12, 14, Part::ERROR), // 07
867 /// (12, 14, parts::MONTH), // 07
868 /// (15, 17, Part::ERROR), // 01
869 /// (15, 17, parts::DAY), // 01
870 /// ]
871 /// );
872 /// ```
873 pub fn new_without_number_formatting(prefs: DateTimeFormatterPreferences) -> Self {
874 Self {
875 prefs,
876 inner: RawDateTimeNames::new_without_number_formatting(),
877 metadata: DateTimeNamesMetadata::new_empty(), // OK: this is a constructor
878 _calendar: PhantomData,
879 }
880 }
881}
882
883impl<C: CldrCalendar, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
884 /// Creates an instance with the names loaded in a [`FixedCalendarDateTimeFormatter`].
885 ///
886 /// This function requires passing in the [`DateTimeFormatterPreferences`] because it is not
887 /// retained in the formatter. Pass the same value or else unexpected behavior may occur.
888 ///
889 /// # Examples
890 ///
891 /// ```
892 /// use icu::datetime::input::Date;
893 /// use icu::datetime::input::{DateTime, Time};
894 /// use icu::datetime::FixedCalendarDateTimeFormatter;
895 /// use icu::datetime::fieldsets::{YMD, YMDT};
896 /// use icu::datetime::pattern::{FixedCalendarDateTimeNames, DayPeriodNameLength};
897 /// use icu::locale::locale;
898 /// use writeable::assert_writeable_eq;
899 ///
900 /// let prefs = locale!("es-MX").into();
901 ///
902 /// let formatter =
903 /// FixedCalendarDateTimeFormatter::try_new(
904 /// prefs,
905 /// YMD::long(),
906 /// )
907 /// .unwrap();
908 ///
909 /// assert_writeable_eq!(
910 /// formatter.format(&Date::try_new_gregorian(2025, 2, 13).unwrap()),
911 /// "13 de febrero de 2025"
912 /// );
913 ///
914 /// // Change the YMD formatter to a YMDT formatter, after loading day period names.
915 /// // This assumes that the locale uses Abbreviated names for the given semantic skeleton!
916 /// let mut names = FixedCalendarDateTimeNames::from_formatter(prefs, formatter).cast_into_fset::<YMDT>();
917 /// names.include_day_period_names(DayPeriodNameLength::Abbreviated).unwrap();
918 /// let formatter = names.try_into_formatter(YMD::long().with_time_hm()).unwrap();
919 ///
920 /// assert_writeable_eq!(
921 /// formatter.format(&DateTime {
922 /// date: Date::try_new_gregorian(2025, 2, 13).unwrap(),
923 /// time: Time::start_of_day(),
924 /// }),
925 /// "13 de febrero de 2025 a las 12:00 a.m."
926 /// );
927 /// ```
928 pub fn from_formatter(
929 prefs: DateTimeFormatterPreferences,
930 formatter: FixedCalendarDateTimeFormatter<C, FSet>,
931 ) -> Self {
932 let metadata = DateTimeNamesMetadata::new_from_previous(&formatter.names);
933 Self {
934 prefs,
935 inner: formatter.names,
936 metadata,
937 _calendar: PhantomData,
938 }
939 }
940
941 fn from_parts(
942 prefs: DateTimeFormatterPreferences,
943 parts: (RawDateTimeNames<FSet>, DateTimeNamesMetadata),
944 ) -> Self {
945 Self {
946 prefs,
947 inner: parts.0,
948 metadata: parts.1,
949 _calendar: PhantomData,
950 }
951 }
952}
953
954impl<C: CldrCalendar, FSet: DateTimeMarkers> FixedCalendarDateTimeNames<C, FSet>
955where
956 FSet::D: TypedDateDataMarkers<C>,
957 FSet::T: TimeMarkers,
958 FSet::Z: ZoneMarkers,
959 FSet: GetField<CompositeFieldSet>,
960{
961 /// Loads a pattern for the given field set with compiled data and returns a [`FixedCalendarDateTimeFormatter`].
962 ///
963 /// The names in the current [`FixedCalendarDateTimeNames`] _must_ be sufficient for the field set.
964 /// If not, the input object will be returned with an error.
965 ///
966 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
967 ///
968 /// [📚 Help choosing a constructor](icu_provider::constructors)
969 ///
970 /// # Examples
971 ///
972 /// ```
973 /// use icu::datetime::fieldsets::T;
974 /// use icu::datetime::input::Time;
975 /// use icu::datetime::pattern::{
976 /// DayPeriodNameLength, FixedCalendarDateTimeNames,
977 /// };
978 /// use icu::locale::locale;
979 /// use writeable::assert_writeable_eq;
980 ///
981 /// let names =
982 /// FixedCalendarDateTimeNames::<(), _>::new_without_number_formatting(
983 /// locale!("es-MX").into(),
984 /// );
985 ///
986 /// let field_set = T::hm();
987 ///
988 /// // Cannot convert yet: no names are loaded
989 /// let mut names = names.try_into_formatter(field_set).unwrap_err().1;
990 ///
991 /// // Load the data we need:
992 /// names
993 /// .include_day_period_names(DayPeriodNameLength::Abbreviated)
994 /// .unwrap();
995 /// names.include_decimal_formatter().unwrap();
996 ///
997 /// // Now the conversion is successful:
998 /// let formatter = names.try_into_formatter(field_set).unwrap();
999 ///
1000 /// assert_writeable_eq!(formatter.format(&Time::start_of_day()), "12:00 a.m.");
1001 /// ```
1002 #[expect(clippy::result_large_err)] // returning self as the error
1003 #[cfg(feature = "compiled_data")]
1004 pub fn try_into_formatter(
1005 self,
1006 field_set: FSet,
1007 ) -> Result<FixedCalendarDateTimeFormatter<C, FSet>, (DateTimeFormatterLoadError, Self)>
1008 where
1009 crate::provider::Baked: AllFixedCalendarPatternDataMarkers<C, FSet>,
1010 {
1011 FixedCalendarDateTimeFormatter::try_new_internal_with_names(
1012 &crate::provider::Baked,
1013 &EmptyDataProvider,
1014 &ExternalLoaderUnstable(&EmptyDataProvider), // for decimals only
1015 self.prefs,
1016 field_set.get_field(),
1017 self.inner,
1018 self.metadata,
1019 )
1020 .map_err(|e| (e.0, Self::from_parts(self.prefs, e.1)))
1021 }
1022
1023 #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::try_into_formatter)]
1024 #[expect(clippy::result_large_err)] // returning self as the error
1025 pub fn try_into_formatter_unstable<P>(
1026 self,
1027 provider: &P,
1028 field_set: FSet,
1029 ) -> Result<FixedCalendarDateTimeFormatter<C, FSet>, (DateTimeFormatterLoadError, Self)>
1030 where
1031 P: AllFixedCalendarPatternDataMarkers<C, FSet> + ?Sized,
1032 {
1033 FixedCalendarDateTimeFormatter::try_new_internal_with_names(
1034 provider,
1035 &EmptyDataProvider,
1036 &ExternalLoaderUnstable(&EmptyDataProvider), // for decimals only
1037 self.prefs,
1038 field_set.get_field(),
1039 self.inner,
1040 self.metadata,
1041 )
1042 .map_err(|e| (e.0, Self::from_parts(self.prefs, e.1)))
1043 }
1044
1045 #[doc = icu_provider::gen_buffer_unstable_docs!(BUFFER, Self::try_into_formatter)]
1046 #[expect(clippy::result_large_err)] // returning self as the error
1047 #[cfg(feature = "serde")]
1048 pub fn try_into_formatter_with_buffer_provider<P>(
1049 self,
1050 provider: &P,
1051 field_set: FSet,
1052 ) -> Result<FixedCalendarDateTimeFormatter<C, FSet>, (DateTimeFormatterLoadError, Self)>
1053 where
1054 P: BufferProvider + ?Sized,
1055 {
1056 FixedCalendarDateTimeFormatter::try_new_internal_with_names(
1057 &provider.as_deserializing(),
1058 &EmptyDataProvider,
1059 &ExternalLoaderUnstable(&EmptyDataProvider), // for decimals only
1060 self.prefs,
1061 field_set.get_field(),
1062 self.inner,
1063 self.metadata,
1064 )
1065 .map_err(|e| (e.0, Self::from_parts(self.prefs, e.1)))
1066 }
1067}
1068
1069impl<FSet: DateTimeNamesMarker> DateTimeNames<FSet> {
1070 /// Creates a completely empty instance, not even with number formatting,
1071 /// with the specified calendar.
1072 pub fn try_new_with_calendar_without_number_formatting(
1073 prefs: DateTimeFormatterPreferences,
1074 calendar: AnyCalendar,
1075 ) -> Result<Self, UnsupportedCalendarError> {
1076 let kind = calendar.kind();
1077 let calendar = FormattableAnyCalendar::try_from_any_calendar(calendar)
1078 .ok_or(UnsupportedCalendarError { kind })?;
1079 Ok(Self {
1080 inner: FixedCalendarDateTimeNames::new_without_number_formatting(prefs),
1081 calendar,
1082 })
1083 }
1084
1085 /// Creates an instance with the names and calendar loaded in a [`DateTimeFormatter`].
1086 ///
1087 /// This function requires passing in the [`DateTimeFormatterPreferences`] because it is not
1088 /// retained in the formatter. Pass the same value or else unexpected behavior may occur.
1089 ///
1090 /// # Examples
1091 ///
1092 /// ```
1093 /// use icu::datetime::input::Date;
1094 /// use icu::datetime::input::{DateTime, Time};
1095 /// use icu::datetime::DateTimeFormatter;
1096 /// use icu::datetime::fieldsets::{YMD, YMDT};
1097 /// use icu::datetime::pattern::{DateTimeNames, DayPeriodNameLength};
1098 /// use icu::locale::locale;
1099 /// use writeable::assert_writeable_eq;
1100 ///
1101 /// let prefs = locale!("es-MX").into();
1102 ///
1103 /// let formatter =
1104 /// DateTimeFormatter::try_new(
1105 /// prefs,
1106 /// YMD::long(),
1107 /// )
1108 /// .unwrap();
1109 ///
1110 /// assert_writeable_eq!(
1111 /// formatter.format(&Date::try_new_iso(2025, 2, 13).unwrap()),
1112 /// "13 de febrero de 2025"
1113 /// );
1114 ///
1115 /// // Change the YMD formatter to a YMDT formatter, after loading day period names.
1116 /// // This assumes that the locale uses Abbreviated names for the given semantic skeleton!
1117 /// let mut names = DateTimeNames::from_formatter(prefs, formatter).cast_into_fset::<YMDT>();
1118 /// names.as_mut().include_day_period_names(DayPeriodNameLength::Abbreviated).unwrap();
1119 /// let formatter = names.try_into_formatter(YMD::long().with_time_hm()).unwrap();
1120 ///
1121 /// assert_writeable_eq!(
1122 /// formatter.format(&DateTime {
1123 /// date: Date::try_new_iso(2025, 2, 13).unwrap(),
1124 /// time: Time::start_of_day(),
1125 /// }),
1126 /// "13 de febrero de 2025 a las 12:00 a.m."
1127 /// );
1128 /// ```
1129 pub fn from_formatter(
1130 prefs: DateTimeFormatterPreferences,
1131 formatter: DateTimeFormatter<FSet>,
1132 ) -> Self {
1133 let metadata = DateTimeNamesMetadata::new_from_previous(&formatter.names);
1134 Self::from_parts(
1135 prefs,
1136 (formatter.calendar.into_tagged(), formatter.names, metadata),
1137 )
1138 }
1139
1140 fn from_parts(
1141 prefs: DateTimeFormatterPreferences,
1142 parts: (
1143 FormattableAnyCalendar,
1144 RawDateTimeNames<FSet>,
1145 DateTimeNamesMetadata,
1146 ),
1147 ) -> Self {
1148 Self {
1149 inner: FixedCalendarDateTimeNames {
1150 prefs,
1151 inner: parts.1,
1152 metadata: parts.2,
1153 _calendar: PhantomData,
1154 },
1155 calendar: parts.0,
1156 }
1157 }
1158}
1159
1160impl<FSet: DateTimeMarkers> DateTimeNames<FSet>
1161where
1162 FSet::D: DateDataMarkers,
1163 FSet::T: TimeMarkers,
1164 FSet::Z: ZoneMarkers,
1165 FSet: GetField<CompositeFieldSet>,
1166{
1167 /// Loads a pattern for the given field set with compiled data and returns a [`DateTimeFormatter`].
1168 ///
1169 /// The names in the current [`DateTimeNames`] _must_ be sufficient for the field set.
1170 /// If not, the input object will be returned with an error.
1171 ///
1172 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
1173 ///
1174 /// [📚 Help choosing a constructor](icu_provider::constructors)
1175 ///
1176 /// # Examples
1177 ///
1178 /// ```
1179 /// use icu::calendar::{AnyCalendar, AnyCalendarKind};
1180 /// use icu::datetime::fieldsets::T;
1181 /// use icu::datetime::input::Time;
1182 /// use icu::datetime::pattern::{DateTimeNames, DayPeriodNameLength};
1183 /// use icu::locale::locale;
1184 /// use writeable::assert_writeable_eq;
1185 ///
1186 /// let kind = AnyCalendarKind::new(locale!("es-MX").into());
1187 /// let calendar = AnyCalendar::new(kind);
1188 ///
1189 /// let names = DateTimeNames::try_new_with_calendar_without_number_formatting(
1190 /// locale!("es-MX").into(),
1191 /// calendar,
1192 /// )
1193 /// .expect("All locale-default calendars are supported");
1194 ///
1195 /// let field_set = T::hm();
1196 ///
1197 /// // Cannot convert yet: no names are loaded
1198 /// let mut names = names.try_into_formatter(field_set).unwrap_err().1;
1199 ///
1200 /// // Load the data we need:
1201 /// names
1202 /// .as_mut()
1203 /// .include_day_period_names(DayPeriodNameLength::Abbreviated)
1204 /// .unwrap();
1205 /// names.as_mut().include_decimal_formatter().unwrap();
1206 ///
1207 /// // Now the conversion is successful:
1208 /// let formatter = names.try_into_formatter(field_set).unwrap();
1209 ///
1210 /// assert_writeable_eq!(formatter.format(&Time::start_of_day()), "12:00 a.m.");
1211 /// ```
1212 #[expect(clippy::result_large_err)] // returning self as the error
1213 #[cfg(feature = "compiled_data")]
1214 pub fn try_into_formatter(
1215 self,
1216 field_set: FSet,
1217 ) -> Result<DateTimeFormatter<FSet>, (DateTimeFormatterLoadError, Self)>
1218 where
1219 crate::provider::Baked: AllAnyCalendarPatternDataMarkers<FSet>,
1220 {
1221 DateTimeFormatter::try_new_internal_with_calendar_and_names(
1222 &crate::provider::Baked,
1223 &EmptyDataProvider,
1224 &ExternalLoaderUnstable(&EmptyDataProvider), // for decimals only
1225 self.inner.prefs,
1226 field_set.get_field(),
1227 self.calendar,
1228 self.inner.inner,
1229 self.inner.metadata,
1230 )
1231 .map_err(|e| (e.0, Self::from_parts(self.inner.prefs, e.1)))
1232 }
1233
1234 #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::try_into_formatter)]
1235 #[expect(clippy::result_large_err)] // returning self as the error
1236 pub fn try_into_formatter_unstable<P>(
1237 self,
1238 provider: &P,
1239 field_set: FSet,
1240 ) -> Result<DateTimeFormatter<FSet>, (DateTimeFormatterLoadError, Self)>
1241 where
1242 P: AllAnyCalendarPatternDataMarkers<FSet> + ?Sized,
1243 {
1244 DateTimeFormatter::try_new_internal_with_calendar_and_names(
1245 provider,
1246 &EmptyDataProvider,
1247 &ExternalLoaderUnstable(&EmptyDataProvider), // for decimals only
1248 self.inner.prefs,
1249 field_set.get_field(),
1250 self.calendar,
1251 self.inner.inner,
1252 self.inner.metadata,
1253 )
1254 .map_err(|e| (e.0, Self::from_parts(self.inner.prefs, e.1)))
1255 }
1256
1257 #[doc = icu_provider::gen_buffer_unstable_docs!(BUFFER, Self::try_into_formatter)]
1258 #[expect(clippy::result_large_err)] // returning self as the error
1259 #[cfg(feature = "serde")]
1260 pub fn try_into_formatter_with_buffer_provider<P>(
1261 self,
1262 provider: &P,
1263 field_set: FSet,
1264 ) -> Result<DateTimeFormatter<FSet>, (DateTimeFormatterLoadError, Self)>
1265 where
1266 P: BufferProvider + ?Sized,
1267 {
1268 DateTimeFormatter::try_new_internal_with_calendar_and_names(
1269 &provider.as_deserializing(),
1270 &EmptyDataProvider,
1271 &ExternalLoaderUnstable(&EmptyDataProvider), // for decimals only
1272 self.inner.prefs,
1273 field_set.get_field(),
1274 self.calendar,
1275 self.inner.inner,
1276 self.inner.metadata,
1277 )
1278 .map_err(|e| (e.0, Self::from_parts(self.inner.prefs, e.1)))
1279 }
1280}
1281
1282impl<FSet: DateTimeNamesMarker> AsRef<FixedCalendarDateTimeNames<(), FSet>>
1283 for DateTimeNames<FSet>
1284{
1285 fn as_ref(&self) -> &FixedCalendarDateTimeNames<(), FSet> {
1286 &self.inner
1287 }
1288}
1289
1290impl<FSet: DateTimeNamesMarker> AsMut<FixedCalendarDateTimeNames<(), FSet>>
1291 for DateTimeNames<FSet>
1292{
1293 fn as_mut(&mut self) -> &mut FixedCalendarDateTimeNames<(), FSet> {
1294 &mut self.inner
1295 }
1296}
1297
1298impl<C: CldrCalendar, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
1299 /// Loads year (era or cycle) names for the specified length.
1300 ///
1301 /// Does not support multiple field symbols or lengths. See [#4337](https://github.com/unicode-org/icu4x/issues/4337)
1302 pub fn load_year_names<P>(
1303 &mut self,
1304 provider: &P,
1305 length: YearNameLength,
1306 ) -> Result<&mut Self, PatternLoadError>
1307 where
1308 P: DataProvider<C::YearNamesV1> + ?Sized,
1309 {
1310 self.inner.load_year_names(
1311 &C::YearNamesV1::bind(provider),
1312 self.prefs,
1313 length,
1314 length.to_approximate_error_field(),
1315 )?;
1316 Ok(self)
1317 }
1318
1319 /// Includes year (era or cycle) names for the specified length with compiled data.
1320 ///
1321 /// Does not support multiple field symbols or lengths. See [#4337](https://github.com/unicode-org/icu4x/issues/4337)
1322 ///
1323 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
1324 ///
1325 /// # Examples
1326 ///
1327 /// ```
1328 /// use icu::calendar::Gregorian;
1329 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1330 /// use icu::datetime::pattern::PatternLoadError;
1331 /// use icu::datetime::pattern::YearNameLength;
1332 /// use icu::locale::locale;
1333 ///
1334 /// let mut names =
1335 /// FixedCalendarDateTimeNames::<Gregorian>::try_new(locale!("und").into())
1336 /// .unwrap();
1337 ///
1338 /// // First length is successful:
1339 /// names.include_year_names(YearNameLength::Wide).unwrap();
1340 ///
1341 /// // Attempting to load the first length a second time will succeed:
1342 /// names.include_year_names(YearNameLength::Wide).unwrap();
1343 ///
1344 /// // But loading a new length fails:
1345 /// assert!(matches!(
1346 /// names.include_year_names(YearNameLength::Abbreviated),
1347 /// Err(PatternLoadError::ConflictingField { .. })
1348 /// ));
1349 /// ```
1350 #[cfg(feature = "compiled_data")]
1351 pub fn include_year_names(
1352 &mut self,
1353 length: YearNameLength,
1354 ) -> Result<&mut Self, PatternLoadError>
1355 where
1356 crate::provider::Baked: icu_provider::DataProvider<<C as CldrCalendar>::YearNamesV1>,
1357 {
1358 self.load_year_names(&crate::provider::Baked, length)
1359 }
1360
1361 /// Loads month names for the specified symbol and length.
1362 ///
1363 /// Does not support multiple field symbols or lengths. See [#4337](https://github.com/unicode-org/icu4x/issues/4337)
1364 pub fn load_month_names<P>(
1365 &mut self,
1366 provider: &P,
1367 length: MonthNameLength,
1368 ) -> Result<&mut Self, PatternLoadError>
1369 where
1370 P: DataProvider<C::MonthNamesV1> + ?Sized,
1371 {
1372 self.inner.load_month_names(
1373 &C::MonthNamesV1::bind(provider),
1374 self.prefs,
1375 length,
1376 length.to_approximate_error_field(),
1377 )?;
1378 Ok(self)
1379 }
1380
1381 /// Includes month names for the specified symbol and length with compiled data.
1382 ///
1383 /// Does not support multiple field symbols or lengths. See [#4337](https://github.com/unicode-org/icu4x/issues/4337)
1384 ///
1385 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
1386 ///
1387 /// # Examples
1388 ///
1389 /// ```
1390 /// use icu::calendar::Gregorian;
1391 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1392 /// use icu::datetime::pattern::MonthNameLength;
1393 /// use icu::datetime::pattern::PatternLoadError;
1394 /// use icu::locale::locale;
1395 ///
1396 /// let mut names =
1397 /// FixedCalendarDateTimeNames::<Gregorian>::try_new(locale!("und").into())
1398 /// .unwrap();
1399 ///
1400 /// // First length is successful:
1401 /// names.include_month_names(MonthNameLength::Wide).unwrap();
1402 ///
1403 /// // Attempting to load the first length a second time will succeed:
1404 /// names.include_month_names(MonthNameLength::Wide).unwrap();
1405 ///
1406 /// // But loading a new symbol or length fails:
1407 /// assert!(matches!(
1408 /// names.include_month_names(MonthNameLength::StandaloneWide),
1409 /// Err(PatternLoadError::ConflictingField { .. })
1410 /// ));
1411 /// assert!(matches!(
1412 /// names.include_month_names(MonthNameLength::Abbreviated),
1413 /// Err(PatternLoadError::ConflictingField { .. })
1414 /// ));
1415 /// ```
1416 #[cfg(feature = "compiled_data")]
1417 pub fn include_month_names(
1418 &mut self,
1419 length: MonthNameLength,
1420 ) -> Result<&mut Self, PatternLoadError>
1421 where
1422 crate::provider::Baked: icu_provider::DataProvider<<C as CldrCalendar>::MonthNamesV1>,
1423 {
1424 self.load_month_names(&crate::provider::Baked, length)
1425 }
1426}
1427
1428impl<C, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
1429 /// Loads day period names for the specified length.
1430 ///
1431 /// Does not support multiple field symbols or lengths. See [#4337](https://github.com/unicode-org/icu4x/issues/4337)
1432 pub fn load_day_period_names<P>(
1433 &mut self,
1434 provider: &P,
1435 length: DayPeriodNameLength,
1436 ) -> Result<&mut Self, PatternLoadError>
1437 where
1438 P: DataProvider<DayPeriodNamesV1> + ?Sized,
1439 {
1440 let provider = DayPeriodNamesV1::bind(provider);
1441 self.inner.load_day_period_names(
1442 &provider,
1443 self.prefs,
1444 length,
1445 length.to_approximate_error_field(),
1446 )?;
1447 Ok(self)
1448 }
1449
1450 /// Includes day period names for the specified length with compiled data.
1451 ///
1452 /// Does not support multiple field symbols or lengths. See [#4337](https://github.com/unicode-org/icu4x/issues/4337)
1453 ///
1454 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
1455 ///
1456 /// # Examples
1457 ///
1458 /// ```
1459 /// use icu::calendar::Gregorian;
1460 /// use icu::datetime::pattern::DayPeriodNameLength;
1461 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1462 /// use icu::datetime::pattern::PatternLoadError;
1463 /// use icu::locale::locale;
1464 ///
1465 /// let mut names =
1466 /// FixedCalendarDateTimeNames::<Gregorian>::try_new(locale!("und").into())
1467 /// .unwrap();
1468 ///
1469 /// // First length is successful:
1470 /// names
1471 /// .include_day_period_names(DayPeriodNameLength::Wide)
1472 /// .unwrap();
1473 ///
1474 /// // Attempting to load the first length a second time will succeed:
1475 /// names
1476 /// .include_day_period_names(DayPeriodNameLength::Wide)
1477 /// .unwrap();
1478 ///
1479 /// // But loading a new length fails:
1480 /// assert!(matches!(
1481 /// names.include_day_period_names(DayPeriodNameLength::Abbreviated),
1482 /// Err(PatternLoadError::ConflictingField { .. })
1483 /// ));
1484 /// ```
1485 #[cfg(feature = "compiled_data")]
1486 pub fn include_day_period_names(
1487 &mut self,
1488 length: DayPeriodNameLength,
1489 ) -> Result<&mut Self, PatternLoadError> {
1490 self.load_day_period_names(&crate::provider::Baked, length)
1491 }
1492
1493 /// Loads weekday names for the specified symbol and length.
1494 ///
1495 /// Does not support multiple field symbols or lengths. See [#4337](https://github.com/unicode-org/icu4x/issues/4337)
1496 pub fn load_weekday_names<P>(
1497 &mut self,
1498 provider: &P,
1499 length: WeekdayNameLength,
1500 ) -> Result<&mut Self, PatternLoadError>
1501 where
1502 P: DataProvider<WeekdayNamesV1> + ?Sized,
1503 {
1504 self.inner.load_weekday_names(
1505 &WeekdayNamesV1::bind(provider),
1506 self.prefs,
1507 length,
1508 length.to_approximate_error_field(),
1509 )?;
1510 Ok(self)
1511 }
1512
1513 /// Includes weekday names for the specified symbol and length with compiled data.
1514 ///
1515 /// Does not support multiple field symbols or lengths. See [#4337](https://github.com/unicode-org/icu4x/issues/4337)
1516 ///
1517 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
1518 ///
1519 /// # Examples
1520 ///
1521 /// ```
1522 /// use icu::calendar::Gregorian;
1523 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1524 /// use icu::datetime::pattern::PatternLoadError;
1525 /// use icu::datetime::pattern::WeekdayNameLength;
1526 /// use icu::locale::locale;
1527 ///
1528 /// let mut names =
1529 /// FixedCalendarDateTimeNames::<Gregorian>::try_new(locale!("und").into())
1530 /// .unwrap();
1531 ///
1532 /// // First length is successful:
1533 /// names
1534 /// .include_weekday_names(WeekdayNameLength::Wide)
1535 /// .unwrap();
1536 ///
1537 /// // Attempting to load the first length a second time will succeed:
1538 /// names
1539 /// .include_weekday_names(WeekdayNameLength::Wide)
1540 /// .unwrap();
1541 ///
1542 /// // But loading a new symbol or length fails:
1543 /// assert!(matches!(
1544 /// names.include_weekday_names(WeekdayNameLength::StandaloneWide),
1545 /// Err(PatternLoadError::ConflictingField { .. })
1546 /// ));
1547 /// assert!(matches!(
1548 /// names.include_weekday_names(WeekdayNameLength::Abbreviated),
1549 /// Err(PatternLoadError::ConflictingField { .. })
1550 /// ));
1551 /// ```
1552 #[cfg(feature = "compiled_data")]
1553 pub fn include_weekday_names(
1554 &mut self,
1555 length: WeekdayNameLength,
1556 ) -> Result<&mut Self, PatternLoadError> {
1557 self.load_weekday_names(&crate::provider::Baked, length)
1558 }
1559
1560 /// Loads shared essential patterns for time zone formatting.
1561 pub fn load_time_zone_essentials<P>(
1562 &mut self,
1563 provider: &P,
1564 ) -> Result<&mut Self, PatternLoadError>
1565 where
1566 P: DataProvider<tz::EssentialsV1> + ?Sized,
1567 {
1568 self.inner
1569 .load_time_zone_essentials(&tz::EssentialsV1::bind(provider), self.prefs)?;
1570 Ok(self)
1571 }
1572
1573 /// Includes shared essential patterns for time zone formatting with compiled data.
1574 ///
1575 /// This data should always be loaded when performing time zone formatting.
1576 /// By itself, it allows localized offset formats.
1577 ///
1578 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
1579 ///
1580 /// # Examples
1581 ///
1582 /// ```
1583 /// use icu::calendar::Gregorian;
1584 /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
1585 /// use icu::datetime::input::ZonedDateTime;
1586 /// use icu::datetime::pattern::DateTimePattern;
1587 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1588 /// use icu::locale::locale;
1589 /// use icu::time::zone::IanaParser;
1590 /// use writeable::assert_try_writeable_eq;
1591 ///
1592 /// let mut zone_london_winter = ZonedDateTime::try_strict_from_str(
1593 /// "2024-01-01T00:00:00+00:00[Europe/London]",
1594 /// Gregorian,
1595 /// IanaParser::new(),
1596 /// )
1597 /// .unwrap()
1598 /// .zone;
1599 /// let mut zone_london_summer = ZonedDateTime::try_strict_from_str(
1600 /// "2024-07-01T00:00:00+01:00[Europe/London]",
1601 /// Gregorian,
1602 /// IanaParser::new(),
1603 /// )
1604 /// .unwrap()
1605 /// .zone;
1606 ///
1607 /// let mut names =
1608 /// FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
1609 /// locale!("en-GB").into(),
1610 /// )
1611 /// .unwrap();
1612 ///
1613 /// names.include_time_zone_essentials().unwrap();
1614 ///
1615 /// // Create a pattern with symbol `OOOO`:
1616 /// let pattern_str = "'Your time zone is:' OOOO";
1617 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1618 ///
1619 /// assert_try_writeable_eq!(
1620 /// names
1621 /// .with_pattern_unchecked(&pattern)
1622 /// .format(&zone_london_winter),
1623 /// "Your time zone is: GMT+00:00",
1624 /// );
1625 /// assert_try_writeable_eq!(
1626 /// names
1627 /// .with_pattern_unchecked(&pattern)
1628 /// .format(&zone_london_summer),
1629 /// "Your time zone is: GMT+01:00",
1630 /// );
1631 ///
1632 /// // Now try `V`:
1633 /// let pattern_str = "'Your time zone is:' V";
1634 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1635 ///
1636 /// assert_try_writeable_eq!(
1637 /// names
1638 /// .with_pattern_unchecked(&pattern)
1639 /// .format(&zone_london_winter),
1640 /// "Your time zone is: gblon",
1641 /// );
1642 ///
1643 /// // Now try `Z`:
1644 /// let pattern_str = "'Your time zone is:' Z";
1645 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1646 ///
1647 /// assert_try_writeable_eq!(
1648 /// names
1649 /// .with_pattern_unchecked(&pattern)
1650 /// .format(&zone_london_winter),
1651 /// "Your time zone is: +0000",
1652 /// );
1653 ///
1654 /// // Now try `ZZZZZ`:
1655 /// let pattern_str = "'Your time zone is:' ZZZZZ";
1656 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1657 ///
1658 /// assert_try_writeable_eq!(
1659 /// names
1660 /// .with_pattern_unchecked(&pattern)
1661 /// .format(&zone_london_winter),
1662 /// "Your time zone is: Z",
1663 /// );
1664 /// assert_try_writeable_eq!(
1665 /// names
1666 /// .with_pattern_unchecked(&pattern)
1667 /// .format(&zone_london_summer),
1668 /// "Your time zone is: +01:00",
1669 /// );
1670 /// ```
1671 #[cfg(feature = "compiled_data")]
1672 pub fn include_time_zone_essentials(&mut self) -> Result<&mut Self, PatternLoadError> {
1673 self.load_time_zone_essentials(&crate::provider::Baked)
1674 }
1675
1676 /// Loads location names for time zone formatting.
1677 pub fn load_time_zone_location_names<P>(
1678 &mut self,
1679 provider: &P,
1680 ) -> Result<&mut Self, PatternLoadError>
1681 where
1682 P: DataProvider<tz::LocationsOverrideV1> + DataProvider<tz::LocationsRootV1> + ?Sized,
1683 {
1684 self.inner.load_time_zone_location_names(
1685 &tz::LocationsOverrideV1::bind(provider),
1686 &tz::LocationsRootV1::bind(provider),
1687 self.prefs,
1688 )?;
1689 Ok(self)
1690 }
1691
1692 /// Includes location names for time zone formatting with compiled data.
1693 ///
1694 /// Important: When performing manual time zone data loading, in addition to the
1695 /// specific time zone format data, also call either:
1696 ///
1697 /// - [`FixedCalendarDateTimeNames::include_time_zone_essentials`]
1698 /// - [`FixedCalendarDateTimeNames::load_time_zone_essentials`]
1699 ///
1700 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
1701 ///
1702 /// # Examples
1703 ///
1704 /// ```
1705 /// use icu::calendar::Gregorian;
1706 /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
1707 /// use icu::datetime::input::ZonedDateTime;
1708 /// use icu::datetime::pattern::DateTimePattern;
1709 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1710 /// use icu::locale::locale;
1711 /// use icu::time::zone::IanaParser;
1712 /// use writeable::assert_try_writeable_eq;
1713 ///
1714 /// let mut zone_london_winter = ZonedDateTime::try_strict_from_str(
1715 /// "2024-01-01T00:00:00+00:00[Europe/London]",
1716 /// Gregorian,
1717 /// IanaParser::new(),
1718 /// )
1719 /// .unwrap()
1720 /// .zone;
1721 ///
1722 /// let mut names =
1723 /// FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
1724 /// locale!("en-GB").into(),
1725 /// )
1726 /// .unwrap();
1727 ///
1728 /// names.include_time_zone_essentials().unwrap();
1729 /// names.include_time_zone_location_names().unwrap();
1730 ///
1731 /// // Try `VVVV`:
1732 /// let pattern_str = "'Your time zone is:' VVVV";
1733 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1734 ///
1735 /// assert_try_writeable_eq!(
1736 /// names
1737 /// .with_pattern_unchecked(&pattern)
1738 /// .format(&zone_london_winter),
1739 /// "Your time zone is: UK Time",
1740 /// );
1741 /// ```
1742 #[cfg(feature = "compiled_data")]
1743 pub fn include_time_zone_location_names(&mut self) -> Result<&mut Self, PatternLoadError> {
1744 self.load_time_zone_location_names(&crate::provider::Baked)
1745 }
1746
1747 /// Loads exemplar city names for time zone formatting.
1748 pub fn load_time_zone_exemplar_city_names<P>(
1749 &mut self,
1750 provider: &P,
1751 ) -> Result<&mut Self, PatternLoadError>
1752 where
1753 P: DataProvider<tz::CitiesOverrideV1> + DataProvider<tz::CitiesRootV1> + ?Sized,
1754 {
1755 self.inner.load_time_zone_exemplar_city_names(
1756 &tz::CitiesOverrideV1::bind(provider),
1757 &tz::CitiesRootV1::bind(provider),
1758 self.prefs,
1759 )?;
1760 Ok(self)
1761 }
1762
1763 /// Includes exemplar city names for time zone formatting with compiled data.
1764 ///
1765 /// Important: The `VVV` format requires location data in addition to exemplar
1766 /// city data. Also call either:
1767 ///
1768 /// - [`FixedCalendarDateTimeNames::include_time_zone_location_names`]
1769 /// - [`FixedCalendarDateTimeNames::load_time_zone_location_names`]
1770 ///
1771 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
1772 ///
1773 /// # Examples
1774 ///
1775 /// ```
1776 /// use icu::calendar::Gregorian;
1777 /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
1778 /// use icu::datetime::input::ZonedDateTime;
1779 /// use icu::datetime::pattern::DateTimePattern;
1780 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1781 /// use icu::locale::locale;
1782 /// use icu::time::zone::IanaParser;
1783 /// use writeable::assert_try_writeable_eq;
1784 ///
1785 /// let mut zone_london_winter = ZonedDateTime::try_strict_from_str(
1786 /// "2024-01-01T00:00:00+00:00[Europe/London]",
1787 /// Gregorian,
1788 /// IanaParser::new(),
1789 /// )
1790 /// .unwrap()
1791 /// .zone;
1792 ///
1793 /// let mut names =
1794 /// FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
1795 /// locale!("en-GB").into(),
1796 /// )
1797 /// .unwrap();
1798 ///
1799 /// names.include_time_zone_location_names().unwrap();
1800 /// names.include_time_zone_exemplar_city_names().unwrap();
1801 ///
1802 /// // Try `VVVV`:
1803 /// let pattern_str = "'Your time zone is:' VVV";
1804 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1805 ///
1806 /// assert_try_writeable_eq!(
1807 /// names
1808 /// .with_pattern_unchecked(&pattern)
1809 /// .format(&zone_london_winter),
1810 /// "Your time zone is: London",
1811 /// );
1812 /// ```
1813 #[cfg(feature = "compiled_data")]
1814 pub fn include_time_zone_exemplar_city_names(&mut self) -> Result<&mut Self, PatternLoadError> {
1815 self.load_time_zone_exemplar_city_names(&crate::provider::Baked)
1816 }
1817
1818 /// Loads generic non-location long time zone names.
1819 // NOTE: If a buffer version of this fn is added in 2.x, it should use the CompatProvider
1820 pub fn load_time_zone_generic_long_names<P>(
1821 &mut self,
1822 provider: &P,
1823 ) -> Result<&mut Self, PatternLoadError>
1824 where
1825 P: DataProvider<tz::MzGenericLongV1>
1826 + DataProvider<tz::MzStandardLongV1>
1827 + DataProvider<tz::MzPeriodV1>
1828 + ?Sized,
1829 {
1830 self.inner.load_time_zone_generic_long_names(
1831 &tz::MzGenericLongV1::bind(provider),
1832 &tz::MzStandardLongV1::bind(provider),
1833 &tz::MzPeriodV1::bind(provider),
1834 self.prefs,
1835 &mut self.metadata,
1836 )?;
1837 Ok(self)
1838 }
1839
1840 /// Includes generic non-location long time zone names with compiled data.
1841 ///
1842 /// Important: When performing manual time zone data loading, in addition to the
1843 /// specific time zone format data, also call either:
1844 ///
1845 /// - [`FixedCalendarDateTimeNames::include_time_zone_essentials`]
1846 /// - [`FixedCalendarDateTimeNames::load_time_zone_essentials`]
1847 ///
1848 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
1849 ///
1850 /// # Examples
1851 ///
1852 /// ```
1853 /// use icu::calendar::Gregorian;
1854 /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
1855 /// use icu::datetime::input::ZonedDateTime;
1856 /// use icu::datetime::pattern::DateTimePattern;
1857 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1858 /// use icu::locale::locale;
1859 /// use icu::time::zone::IanaParser;
1860 /// use writeable::assert_try_writeable_eq;
1861 ///
1862 /// let mut zone_berlin_winter = ZonedDateTime::try_strict_from_str(
1863 /// "2024-01-01T00:00:00+01:00[Europe/Berlin]",
1864 /// Gregorian,
1865 /// IanaParser::new(),
1866 /// )
1867 /// .unwrap()
1868 /// .zone;
1869 /// let mut zone_berlin_summer = ZonedDateTime::try_strict_from_str(
1870 /// "2024-07-01T00:00:00+02:00[Europe/Berlin]",
1871 /// Gregorian,
1872 /// IanaParser::new(),
1873 /// )
1874 /// .unwrap()
1875 /// .zone;
1876 ///
1877 /// let mut names =
1878 /// FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
1879 /// locale!("en-GB").into(),
1880 /// )
1881 /// .unwrap();
1882 ///
1883 /// names.include_time_zone_essentials().unwrap();
1884 /// names.include_time_zone_generic_long_names().unwrap();
1885 /// names.include_time_zone_location_names().unwrap();
1886 ///
1887 /// // Create a pattern with symbol `vvvv`:
1888 /// let pattern_str = "'Your time zone is:' vvvv";
1889 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1890 ///
1891 /// assert_try_writeable_eq!(
1892 /// names
1893 /// .with_pattern_unchecked(&pattern)
1894 /// .format(&zone_berlin_winter),
1895 /// "Your time zone is: Central European Time",
1896 /// );
1897 /// assert_try_writeable_eq!(
1898 /// names
1899 /// .with_pattern_unchecked(&pattern)
1900 /// .format(&zone_berlin_summer),
1901 /// "Your time zone is: Central European Time",
1902 /// );
1903 /// ```
1904 #[cfg(feature = "compiled_data")]
1905 pub fn include_time_zone_generic_long_names(&mut self) -> Result<&mut Self, PatternLoadError> {
1906 self.load_time_zone_generic_long_names(&crate::provider::Baked)
1907 }
1908
1909 /// Loads generic non-location short time zone names.
1910 // NOTE: If a buffer version of this fn is added in 2.x, it should use the CompatProvider
1911 pub fn load_time_zone_generic_short_names<P>(
1912 &mut self,
1913 provider: &P,
1914 ) -> Result<&mut Self, PatternLoadError>
1915 where
1916 P: DataProvider<tz::MzGenericShortV1> + DataProvider<tz::MzPeriodV1> + ?Sized,
1917 {
1918 self.inner.load_time_zone_generic_short_names(
1919 &tz::MzGenericShortV1::bind(provider),
1920 &tz::MzPeriodV1::bind(provider),
1921 self.prefs,
1922 &mut self.metadata,
1923 )?;
1924 Ok(self)
1925 }
1926
1927 /// Includes generic non-location short time zone names with compiled data.
1928 ///
1929 /// Important: When performing manual time zone data loading, in addition to the
1930 /// specific time zone format data, also call either:
1931 ///
1932 /// - [`FixedCalendarDateTimeNames::include_time_zone_essentials`]
1933 /// - [`FixedCalendarDateTimeNames::load_time_zone_essentials`]
1934 ///
1935 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
1936 ///
1937 /// # Examples
1938 ///
1939 /// ```
1940 /// use icu::calendar::Gregorian;
1941 /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
1942 /// use icu::datetime::input::ZonedDateTime;
1943 /// use icu::datetime::pattern::DateTimePattern;
1944 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1945 /// use icu::locale::locale;
1946 /// use icu::time::zone::IanaParser;
1947 /// use writeable::assert_try_writeable_eq;
1948 ///
1949 /// let mut zone_berlin_winter = ZonedDateTime::try_strict_from_str(
1950 /// "2024-01-01T00:00:00+01:00[Europe/Berlin]",
1951 /// Gregorian,
1952 /// IanaParser::new(),
1953 /// )
1954 /// .unwrap()
1955 /// .zone;
1956 /// let mut zone_berlin_summer = ZonedDateTime::try_strict_from_str(
1957 /// "2024-07-01T00:00:00+02:00[Europe/Berlin]",
1958 /// Gregorian,
1959 /// IanaParser::new(),
1960 /// )
1961 /// .unwrap()
1962 /// .zone;
1963 ///
1964 /// let mut names =
1965 /// FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
1966 /// locale!("en-GB").into(),
1967 /// )
1968 /// .unwrap();
1969 ///
1970 /// names.include_time_zone_essentials().unwrap();
1971 /// names.include_time_zone_generic_short_names().unwrap();
1972 /// names.include_time_zone_location_names().unwrap();
1973 ///
1974 /// // Create a pattern with symbol `v`:
1975 /// let pattern_str = "'Your time zone is:' v";
1976 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1977 ///
1978 /// assert_try_writeable_eq!(
1979 /// names
1980 /// .with_pattern_unchecked(&pattern)
1981 /// .format(&zone_berlin_winter),
1982 /// "Your time zone is: CET",
1983 /// );
1984 /// assert_try_writeable_eq!(
1985 /// names
1986 /// .with_pattern_unchecked(&pattern)
1987 /// .format(&zone_berlin_summer),
1988 /// "Your time zone is: CET",
1989 /// );
1990 /// ```
1991 #[cfg(feature = "compiled_data")]
1992 pub fn include_time_zone_generic_short_names(&mut self) -> Result<&mut Self, PatternLoadError> {
1993 self.load_time_zone_generic_short_names(&crate::provider::Baked)
1994 }
1995
1996 /// Loads specific non-location long time zone names.
1997 // NOTE: If a buffer version of this fn is added in 2.x, it should use the CompatProvider
1998 pub fn load_time_zone_specific_long_names<P>(
1999 &mut self,
2000 provider: &P,
2001 ) -> Result<&mut Self, PatternLoadError>
2002 where
2003 P: DataProvider<tz::MzSpecificLongV1>
2004 + DataProvider<tz::MzStandardLongV1>
2005 + DataProvider<tz::MzPeriodV1>
2006 + ?Sized,
2007 {
2008 self.inner.load_time_zone_specific_long_names(
2009 &tz::MzSpecificLongV1::bind(provider),
2010 &tz::MzStandardLongV1::bind(provider),
2011 &tz::MzPeriodV1::bind(provider),
2012 self.prefs,
2013 &mut self.metadata,
2014 )?;
2015 Ok(self)
2016 }
2017
2018 /// Includes specific non-location long time zone names with compiled data.
2019 ///
2020 /// Important: When performing manual time zone data loading, in addition to the
2021 /// specific time zone format data, also call either:
2022 ///
2023 /// - [`FixedCalendarDateTimeNames::include_time_zone_essentials`]
2024 /// - [`FixedCalendarDateTimeNames::load_time_zone_essentials`]
2025 ///
2026 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2027 ///
2028 /// # Examples
2029 ///
2030 /// ```
2031 /// use icu::calendar::Gregorian;
2032 /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
2033 /// use icu::datetime::input::ZonedDateTime;
2034 /// use icu::datetime::pattern::DateTimePattern;
2035 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
2036 /// use icu::locale::locale;
2037 /// use icu::time::zone::IanaParser;
2038 /// use writeable::assert_try_writeable_eq;
2039 ///
2040 /// let mut zone_london_winter = ZonedDateTime::try_strict_from_str(
2041 /// "2024-01-01T00:00:00+00:00[Europe/London]",
2042 /// Gregorian,
2043 /// IanaParser::new(),
2044 /// )
2045 /// .unwrap()
2046 /// .zone;
2047 /// let mut zone_london_summer = ZonedDateTime::try_strict_from_str(
2048 /// "2024-07-01T00:00:00+01:00[Europe/London]",
2049 /// Gregorian,
2050 /// IanaParser::new(),
2051 /// )
2052 /// .unwrap()
2053 /// .zone;
2054 ///
2055 /// let mut names =
2056 /// FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
2057 /// locale!("en-GB").into(),
2058 /// )
2059 /// .unwrap();
2060 ///
2061 /// names.include_time_zone_essentials().unwrap();
2062 /// names.include_time_zone_specific_long_names().unwrap();
2063 ///
2064 /// // Create a pattern with symbol `zzzz`:
2065 /// let pattern_str = "'Your time zone is:' zzzz";
2066 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
2067 ///
2068 /// assert_try_writeable_eq!(
2069 /// names
2070 /// .with_pattern_unchecked(&pattern)
2071 /// .format(&zone_london_winter),
2072 /// "Your time zone is: Greenwich Mean Time",
2073 /// );
2074 /// assert_try_writeable_eq!(
2075 /// names
2076 /// .with_pattern_unchecked(&pattern)
2077 /// .format(&zone_london_summer),
2078 /// "Your time zone is: British Summer Time",
2079 /// );
2080 /// ```
2081 #[cfg(feature = "compiled_data")]
2082 pub fn include_time_zone_specific_long_names(&mut self) -> Result<&mut Self, PatternLoadError> {
2083 self.load_time_zone_specific_long_names(&crate::provider::Baked)
2084 }
2085
2086 /// Loads specific non-location short time zone names.
2087 // NOTE: If a buffer version of this fn is added in 2.x, it should use the CompatProvider
2088 pub fn load_time_zone_specific_short_names<P>(
2089 &mut self,
2090 provider: &P,
2091 ) -> Result<&mut Self, PatternLoadError>
2092 where
2093 P: DataProvider<tz::MzSpecificShortV1> + DataProvider<tz::MzPeriodV1> + ?Sized,
2094 {
2095 self.inner.load_time_zone_specific_short_names(
2096 &tz::MzSpecificShortV1::bind(provider),
2097 &tz::MzPeriodV1::bind(provider),
2098 self.prefs,
2099 &mut self.metadata,
2100 )?;
2101 Ok(self)
2102 }
2103
2104 /// Includes specific non-location short time zone names with compiled data.
2105 ///
2106 /// Important: When performing manual time zone data loading, in addition to the
2107 /// specific time zone format data, also call either:
2108 ///
2109 /// - [`FixedCalendarDateTimeNames::include_time_zone_essentials`]
2110 /// - [`FixedCalendarDateTimeNames::load_time_zone_essentials`]
2111 ///
2112 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2113 ///
2114 /// # Examples
2115 ///
2116 /// ```
2117 /// use icu::calendar::Gregorian;
2118 /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
2119 /// use icu::datetime::input::ZonedDateTime;
2120 /// use icu::datetime::pattern::DateTimePattern;
2121 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
2122 /// use icu::locale::locale;
2123 /// use icu::time::zone::IanaParser;
2124 /// use writeable::assert_try_writeable_eq;
2125 ///
2126 /// let mut zone_london_winter = ZonedDateTime::try_strict_from_str(
2127 /// "2024-01-01T00:00:00+00:00[Europe/London]",
2128 /// Gregorian,
2129 /// IanaParser::new(),
2130 /// )
2131 /// .unwrap()
2132 /// .zone;
2133 /// let mut zone_london_summer = ZonedDateTime::try_strict_from_str(
2134 /// "2024-07-01T00:00:00+01:00[Europe/London]",
2135 /// Gregorian,
2136 /// IanaParser::new(),
2137 /// )
2138 /// .unwrap()
2139 /// .zone;
2140 ///
2141 /// let mut names =
2142 /// FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
2143 /// locale!("en-GB").into(),
2144 /// )
2145 /// .unwrap();
2146 ///
2147 /// names.include_time_zone_essentials().unwrap();
2148 /// names.include_time_zone_specific_short_names().unwrap();
2149 ///
2150 /// // Create a pattern with symbol `z`:
2151 /// let pattern_str = "'Your time zone is:' z";
2152 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
2153 ///
2154 /// assert_try_writeable_eq!(
2155 /// names
2156 /// .with_pattern_unchecked(&pattern)
2157 /// .format(&zone_london_winter),
2158 /// "Your time zone is: GMT",
2159 /// );
2160 /// assert_try_writeable_eq!(
2161 /// names
2162 /// .with_pattern_unchecked(&pattern)
2163 /// .format(&zone_london_summer),
2164 /// "Your time zone is: BST",
2165 /// );
2166 /// ```
2167 #[cfg(feature = "compiled_data")]
2168 pub fn include_time_zone_specific_short_names(
2169 &mut self,
2170 ) -> Result<&mut Self, PatternLoadError> {
2171 self.load_time_zone_specific_short_names(&crate::provider::Baked)
2172 }
2173
2174 /// Loads generic non-location short time zone names
2175 /// and all data required for its fallback formats.
2176 ///
2177 /// See [`GenericShort`](crate::fieldsets::zone::GenericShort)
2178 // NOTE: If a buffer version of this fn is added in 2.x, it should use the CompatProvider
2179 pub fn load_time_zone_generic_short_names_with_fallback<P>(
2180 &mut self,
2181 provider: &P,
2182 ) -> Result<&mut Self, PatternLoadError>
2183 where
2184 P: DataProvider<DecimalSymbolsV1>
2185 + DataProvider<DecimalDigitsV1>
2186 + DataProvider<tz::EssentialsV1>
2187 + DataProvider<tz::LocationsOverrideV1>
2188 + DataProvider<tz::LocationsRootV1>
2189 + DataProvider<tz::MzGenericShortV1>
2190 + DataProvider<tz::MzPeriodV1>
2191 + ?Sized,
2192 {
2193 let error_field = self.inner.load_time_zone_field_v_except_decimals(
2194 &tz::EssentialsV1::bind(provider),
2195 &tz::LocationsOverrideV1::bind(provider),
2196 &tz::LocationsRootV1::bind(provider),
2197 &tz::MzGenericShortV1::bind(provider),
2198 &tz::MzPeriodV1::bind(provider),
2199 self.prefs,
2200 &mut self.metadata,
2201 )?;
2202 self.load_decimal_formatter(provider)
2203 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2204 Ok(self)
2205 }
2206
2207 /// Includes generic non-location short time zone names
2208 /// and all data required for its fallback formats, with compiled data.
2209 ///
2210 /// See [`GenericShort`](crate::fieldsets::zone::GenericShort)
2211 ///
2212 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2213 #[cfg(feature = "compiled_data")]
2214 pub fn include_time_zone_generic_short_names_with_fallback(
2215 &mut self,
2216 ) -> Result<&mut Self, PatternLoadError> {
2217 let error_field = self.inner.load_time_zone_field_v_except_decimals(
2218 &tz::EssentialsV1::bind(&crate::provider::Baked),
2219 &tz::LocationsOverrideV1::bind(&crate::provider::Baked),
2220 &tz::LocationsRootV1::bind(&crate::provider::Baked),
2221 &tz::MzGenericShortV1::bind(&crate::provider::Baked),
2222 &tz::MzPeriodV1::bind(&crate::provider::Baked),
2223 self.prefs,
2224 &mut self.metadata,
2225 )?;
2226 self.include_decimal_formatter()
2227 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2228 Ok(self)
2229 }
2230
2231 /// Loads generic non-location long time zone names
2232 /// and all data required for its fallback formats.
2233 ///
2234 /// See [`GenericLong`](crate::fieldsets::zone::GenericLong)
2235 // NOTE: If a buffer version of this fn is added in 2.x, it should use the CompatProvider
2236 pub fn load_time_zone_generic_long_names_with_fallback<P>(
2237 &mut self,
2238 provider: &P,
2239 ) -> Result<&mut Self, PatternLoadError>
2240 where
2241 P: DataProvider<DecimalSymbolsV1>
2242 + DataProvider<DecimalDigitsV1>
2243 + DataProvider<tz::EssentialsV1>
2244 + DataProvider<tz::LocationsOverrideV1>
2245 + DataProvider<tz::LocationsRootV1>
2246 + DataProvider<tz::MzGenericLongV1>
2247 + DataProvider<tz::MzStandardLongV1>
2248 + DataProvider<tz::MzPeriodV1>
2249 + ?Sized,
2250 {
2251 let error_field = self.inner.load_time_zone_field_vvvv_except_decimals(
2252 &tz::EssentialsV1::bind(provider),
2253 &tz::LocationsOverrideV1::bind(provider),
2254 &tz::LocationsRootV1::bind(provider),
2255 &tz::MzGenericLongV1::bind(provider),
2256 &tz::MzStandardLongV1::bind(provider),
2257 &tz::MzPeriodV1::bind(provider),
2258 self.prefs,
2259 &mut self.metadata,
2260 )?;
2261 self.load_decimal_formatter(provider)
2262 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2263 Ok(self)
2264 }
2265
2266 /// Includes generic non-location long time zone names
2267 /// and all data required for its fallback formats, with compiled data.
2268 ///
2269 /// See [`GenericLong`](crate::fieldsets::zone::GenericLong)
2270 ///
2271 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2272 #[cfg(feature = "compiled_data")]
2273 pub fn include_time_zone_generic_long_names_with_fallback(
2274 &mut self,
2275 ) -> Result<&mut Self, PatternLoadError> {
2276 let error_field = self.inner.load_time_zone_field_vvvv_except_decimals(
2277 &tz::EssentialsV1::bind(&crate::provider::Baked),
2278 &tz::LocationsOverrideV1::bind(&crate::provider::Baked),
2279 &tz::LocationsRootV1::bind(&crate::provider::Baked),
2280 &tz::MzGenericLongV1::bind(&crate::provider::Baked),
2281 &tz::MzStandardLongV1::bind(&crate::provider::Baked),
2282 &tz::MzPeriodV1::bind(&crate::provider::Baked),
2283 self.prefs,
2284 &mut self.metadata,
2285 )?;
2286 self.include_decimal_formatter()
2287 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2288 Ok(self)
2289 }
2290
2291 /// Loads specific non-location short time zone names
2292 /// and all data required for its fallback formats
2293 /// except for decimal formatting.
2294 ///
2295 /// See [`SpecificShort`](crate::fieldsets::zone::SpecificShort)
2296 // NOTE: If a buffer version of this fn is added in 2.x, it should use the CompatProvider
2297 pub fn load_time_zone_specific_short_names_with_fallback<P>(
2298 &mut self,
2299 provider: &P,
2300 ) -> Result<&mut Self, PatternLoadError>
2301 where
2302 P: DataProvider<DecimalSymbolsV1>
2303 + DataProvider<DecimalDigitsV1>
2304 + DataProvider<tz::EssentialsV1>
2305 + DataProvider<tz::LocationsOverrideV1>
2306 + DataProvider<tz::LocationsRootV1>
2307 + DataProvider<tz::MzSpecificShortV1>
2308 + DataProvider<tz::MzPeriodV1>
2309 + ?Sized,
2310 {
2311 let error_field = self.inner.load_time_zone_field_z_except_decimals(
2312 &tz::EssentialsV1::bind(provider),
2313 &tz::MzSpecificShortV1::bind(provider),
2314 &tz::MzPeriodV1::bind(provider),
2315 self.prefs,
2316 &mut self.metadata,
2317 )?;
2318 self.load_decimal_formatter(provider)
2319 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2320 Ok(self)
2321 }
2322
2323 /// Includes specific non-location short time zone names
2324 /// and all data required for its fallback formats
2325 /// except for decimal formatting, with compiled data.
2326 ///
2327 /// See [`SpecificShort`](crate::fieldsets::zone::SpecificShort)
2328 ///
2329 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2330 #[cfg(feature = "compiled_data")]
2331 pub fn include_time_zone_specific_short_names_with_fallback(
2332 &mut self,
2333 ) -> Result<&mut Self, PatternLoadError> {
2334 let error_field = self.inner.load_time_zone_field_z_except_decimals(
2335 &tz::EssentialsV1::bind(&crate::provider::Baked),
2336 &tz::MzSpecificShortV1::bind(&crate::provider::Baked),
2337 &tz::MzPeriodV1::bind(&crate::provider::Baked),
2338 self.prefs,
2339 &mut self.metadata,
2340 )?;
2341 self.include_decimal_formatter()
2342 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2343 Ok(self)
2344 }
2345
2346 /// Loads specific non-location long time zone names
2347 /// and all data required for its fallback formats
2348 /// except for decimal formatting.
2349 ///
2350 /// See [`SpecificLong`](crate::fieldsets::zone::SpecificLong)
2351 // NOTE: If a buffer version of this fn is added in 2.x, it should use the CompatProvider
2352 pub fn load_time_zone_specific_long_names_with_fallback<P>(
2353 &mut self,
2354 provider: &P,
2355 ) -> Result<&mut Self, PatternLoadError>
2356 where
2357 P: DataProvider<DecimalSymbolsV1>
2358 + DataProvider<DecimalDigitsV1>
2359 + DataProvider<tz::EssentialsV1>
2360 + DataProvider<tz::LocationsOverrideV1>
2361 + DataProvider<tz::LocationsRootV1>
2362 + DataProvider<tz::MzSpecificLongV1>
2363 + DataProvider<tz::MzStandardLongV1>
2364 + DataProvider<tz::MzPeriodV1>
2365 + ?Sized,
2366 {
2367 let error_field = self.inner.load_time_zone_field_zzzz_except_decimals(
2368 &tz::EssentialsV1::bind(provider),
2369 &tz::LocationsOverrideV1::bind(provider),
2370 &tz::LocationsRootV1::bind(provider),
2371 &tz::MzStandardLongV1::bind(provider),
2372 &tz::MzSpecificLongV1::bind(provider),
2373 &tz::MzPeriodV1::bind(provider),
2374 self.prefs,
2375 &mut self.metadata,
2376 )?;
2377 self.load_decimal_formatter(provider)
2378 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2379 Ok(self)
2380 }
2381
2382 /// Includes specific non-location long time zone names
2383 /// and all data required for its fallback formats
2384 /// except for decimal formatting, with compiled data.
2385 ///
2386 /// See [`SpecificLong`](crate::fieldsets::zone::SpecificLong)
2387 ///
2388 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2389 #[cfg(feature = "compiled_data")]
2390 pub fn include_time_zone_specific_long_names_with_fallback(
2391 &mut self,
2392 ) -> Result<&mut Self, PatternLoadError> {
2393 let error_field = self.inner.load_time_zone_field_zzzz_except_decimals(
2394 &tz::EssentialsV1::bind(&crate::provider::Baked),
2395 &tz::LocationsOverrideV1::bind(&crate::provider::Baked),
2396 &tz::LocationsRootV1::bind(&crate::provider::Baked),
2397 &tz::MzStandardLongV1::bind(&crate::provider::Baked),
2398 &tz::MzSpecificLongV1::bind(&crate::provider::Baked),
2399 &tz::MzPeriodV1::bind(&crate::provider::Baked),
2400 self.prefs,
2401 &mut self.metadata,
2402 )?;
2403 self.include_decimal_formatter()
2404 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2405 Ok(self)
2406 }
2407
2408 /// Loads all data for short and long localized offset time zone formatting
2409 /// except for decimal formatting.
2410 ///
2411 /// See:
2412 ///
2413 /// - [`LocalizedOffsetShort`](crate::fieldsets::zone::LocalizedOffsetShort)
2414 /// - [`LocalizedOffsetLong`](crate::fieldsets::zone::LocalizedOffsetLong)
2415 pub fn load_time_zone_localized_offset_names_with_fallback<P>(
2416 &mut self,
2417 provider: &P,
2418 ) -> Result<&mut Self, PatternLoadError>
2419 where
2420 P: DataProvider<DecimalSymbolsV1>
2421 + DataProvider<DecimalDigitsV1>
2422 + DataProvider<tz::EssentialsV1>
2423 + ?Sized,
2424 {
2425 let error_field = self.inner.load_time_zone_field_O_except_decimals(
2426 &tz::EssentialsV1::bind(provider),
2427 self.prefs,
2428 )?;
2429 self.load_decimal_formatter(provider)
2430 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2431 Ok(self)
2432 }
2433
2434 /// Includes all data for short and long localized offset time zone formatting
2435 /// except for decimal formatting, with compiled data.
2436 ///
2437 /// See:
2438 ///
2439 /// - [`LocalizedOffsetShort`](crate::fieldsets::zone::LocalizedOffsetShort)
2440 /// - [`LocalizedOffsetLong`](crate::fieldsets::zone::LocalizedOffsetLong)
2441 ///
2442 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2443 #[cfg(feature = "compiled_data")]
2444 pub fn include_time_zone_localized_offset_names_with_fallback(
2445 &mut self,
2446 ) -> Result<&mut Self, PatternLoadError> {
2447 let error_field = self.inner.load_time_zone_field_O_except_decimals(
2448 &tz::EssentialsV1::bind(&crate::provider::Baked),
2449 self.prefs,
2450 )?;
2451 self.include_decimal_formatter()
2452 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2453 Ok(self)
2454 }
2455
2456 /// Loads a [`DecimalFormatter`] from a data provider.
2457 #[inline]
2458 pub fn load_decimal_formatter<P>(&mut self, provider: &P) -> Result<&mut Self, DataError>
2459 where
2460 P: DataProvider<DecimalSymbolsV1> + DataProvider<DecimalDigitsV1> + ?Sized,
2461 {
2462 self.inner
2463 .load_decimal_formatter(&ExternalLoaderUnstable(provider), self.prefs)?;
2464 Ok(self)
2465 }
2466
2467 /// Loads a [`DecimalFormatter`] with compiled data.
2468 ///
2469 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2470 ///
2471 /// # Examples
2472 ///
2473 /// ```
2474 /// use icu::datetime::fieldsets::enums::TimeFieldSet;
2475 /// use icu::datetime::input::Time;
2476 /// use icu::datetime::pattern::DateTimePattern;
2477 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
2478 /// use icu::locale::locale;
2479 /// use writeable::assert_try_writeable_eq;
2480 ///
2481 /// let mut names = FixedCalendarDateTimeNames::<(), TimeFieldSet>::try_new(
2482 /// locale!("bn").into(),
2483 /// )
2484 /// .unwrap();
2485 /// names.include_decimal_formatter();
2486 ///
2487 /// // Create a pattern for the time, which is all numbers
2488 /// let pattern_str = "'The current 24-hour time is:' HH:mm";
2489 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
2490 ///
2491 /// let time = Time::try_new(6, 40, 33, 0).unwrap();
2492 ///
2493 /// assert_try_writeable_eq!(
2494 /// names.with_pattern_unchecked(&pattern).format(&time),
2495 /// "The current 24-hour time is: ০৬:৪০",
2496 /// );
2497 /// ```
2498 #[cfg(feature = "compiled_data")]
2499 #[inline]
2500 pub fn include_decimal_formatter(&mut self) -> Result<&mut Self, DataError> {
2501 self.inner
2502 .load_decimal_formatter(&ExternalLoaderCompiledData, self.prefs)?;
2503 Ok(self)
2504 }
2505}
2506
2507impl<C: CldrCalendar, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
2508 /// Associates this [`FixedCalendarDateTimeNames`] with a pattern
2509 /// without checking that all necessary data is loaded.
2510 ///
2511 /// Use this function if you know at compile time what fields your pattern contains.
2512 #[inline]
2513 pub fn with_pattern_unchecked<'l>(
2514 &'l self,
2515 pattern: &'l DateTimePattern,
2516 ) -> DateTimePatternFormatter<'l, C, FSet> {
2517 DateTimePatternFormatter::new(pattern.as_borrowed(), self.inner.as_borrowed())
2518 }
2519
2520 /// Associates this [`FixedCalendarDateTimeNames`] with a datetime pattern
2521 /// and loads all data required for that pattern.
2522 ///
2523 /// Does not duplicate textual field symbols. See [#4337](https://github.com/unicode-org/icu4x/issues/4337)
2524 // NOTE: If a buffer version of this fn is added in 2.x, it should use the CompatProvider
2525 pub fn load_for_pattern<'l, P>(
2526 &'l mut self,
2527 provider: &P,
2528 pattern: &'l DateTimePattern,
2529 ) -> Result<DateTimePatternFormatter<'l, C, FSet>, PatternLoadError>
2530 where
2531 P: DataProvider<C::YearNamesV1>
2532 + DataProvider<C::MonthNamesV1>
2533 + DataProvider<WeekdayNamesV1>
2534 + DataProvider<DayPeriodNamesV1>
2535 + DataProvider<tz::EssentialsV1>
2536 + DataProvider<tz::LocationsOverrideV1>
2537 + DataProvider<tz::LocationsRootV1>
2538 + DataProvider<tz::CitiesOverrideV1>
2539 + DataProvider<tz::CitiesRootV1>
2540 + DataProvider<tz::MzGenericLongV1>
2541 + DataProvider<tz::MzGenericShortV1>
2542 + DataProvider<tz::MzStandardLongV1>
2543 + DataProvider<tz::MzSpecificLongV1>
2544 + DataProvider<tz::MzSpecificShortV1>
2545 + DataProvider<tz::MzPeriodV1>
2546 + DataProvider<DecimalSymbolsV1>
2547 + DataProvider<DecimalDigitsV1>
2548 + ?Sized,
2549 {
2550 let locale = self.prefs;
2551 self.inner.load_for_pattern(
2552 &C::YearNamesV1::bind(provider),
2553 &C::MonthNamesV1::bind(provider),
2554 &WeekdayNamesV1::bind(provider),
2555 &DayPeriodNamesV1::bind(provider),
2556 &tz::EssentialsV1::bind(provider),
2557 &tz::LocationsRootV1::bind(provider),
2558 &tz::LocationsOverrideV1::bind(provider),
2559 &tz::CitiesRootV1::bind(provider),
2560 &tz::CitiesOverrideV1::bind(provider),
2561 &tz::MzGenericLongV1::bind(provider),
2562 &tz::MzGenericShortV1::bind(provider),
2563 &tz::MzStandardLongV1::bind(provider),
2564 &tz::MzSpecificLongV1::bind(provider),
2565 &tz::MzSpecificShortV1::bind(provider),
2566 &tz::MzPeriodV1::bind(provider),
2567 &ExternalLoaderUnstable(provider),
2568 locale,
2569 pattern.iter_items(),
2570 &mut self.metadata,
2571 )?;
2572 Ok(DateTimePatternFormatter::new(
2573 pattern.as_borrowed(),
2574 self.inner.as_borrowed(),
2575 ))
2576 }
2577
2578 /// Associates this [`FixedCalendarDateTimeNames`] with a pattern
2579 /// and includes all data required for that pattern, from compiled data.
2580 ///
2581 /// Does not support duplicate textual field symbols. See [#4337](https://github.com/unicode-org/icu4x/issues/4337)
2582 ///
2583 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2584 ///
2585 /// # Examples
2586 ///
2587 /// ```
2588 /// use icu::calendar::Gregorian;
2589 /// use icu::datetime::input::Date;
2590 /// use icu::datetime::input::{DateTime, Time};
2591 /// use icu::datetime::pattern::DateTimePattern;
2592 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
2593 /// use icu::locale::locale;
2594 /// use writeable::assert_try_writeable_eq;
2595 ///
2596 /// let mut names =
2597 /// FixedCalendarDateTimeNames::<Gregorian>::try_new(locale!("en").into())
2598 /// .unwrap();
2599 ///
2600 /// // Create a pattern from a pattern string:
2601 /// let pattern_str = "MMM d (EEEE) 'of year' y G 'at' h:mm a";
2602 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
2603 ///
2604 /// // Load data for the pattern and format:
2605 /// let datetime = DateTime {
2606 /// date: Date::try_new_gregorian(2023, 12, 5).unwrap(),
2607 /// time: Time::try_new(17, 43, 12, 0).unwrap(),
2608 /// };
2609 /// assert_try_writeable_eq!(
2610 /// names
2611 /// .include_for_pattern(&pattern)
2612 /// .unwrap()
2613 /// .format(&datetime),
2614 /// "Dec 5 (Tuesday) of year 2023 AD at 5:43 PM"
2615 /// );
2616 /// ```
2617 #[cfg(feature = "compiled_data")]
2618 pub fn include_for_pattern<'l>(
2619 &'l mut self,
2620 pattern: &'l DateTimePattern,
2621 ) -> Result<DateTimePatternFormatter<'l, C, FSet>, PatternLoadError>
2622 where
2623 crate::provider::Baked: DataProvider<C::YearNamesV1> + DataProvider<C::MonthNamesV1>,
2624 crate::provider::Baked: DataProvider<C::YearNamesV1> + DataProvider<C::MonthNamesV1>,
2625 {
2626 let locale = self.prefs;
2627 self.inner.load_for_pattern(
2628 &C::YearNamesV1::bind(&crate::provider::Baked),
2629 &C::MonthNamesV1::bind(&crate::provider::Baked),
2630 &WeekdayNamesV1::bind(&crate::provider::Baked),
2631 &DayPeriodNamesV1::bind(&crate::provider::Baked),
2632 &tz::EssentialsV1::bind(&crate::provider::Baked),
2633 &tz::LocationsOverrideV1::bind(&crate::provider::Baked),
2634 &tz::LocationsRootV1::bind(&crate::provider::Baked),
2635 &tz::CitiesOverrideV1::bind(&crate::provider::Baked),
2636 &tz::CitiesRootV1::bind(&crate::provider::Baked),
2637 &tz::MzGenericLongV1::bind(&crate::provider::Baked),
2638 &tz::MzGenericShortV1::bind(&crate::provider::Baked),
2639 &tz::MzStandardLongV1::bind(&crate::provider::Baked),
2640 &tz::MzSpecificLongV1::bind(&crate::provider::Baked),
2641 &tz::MzSpecificShortV1::bind(&crate::provider::Baked),
2642 &tz::MzPeriodV1::bind(&crate::provider::Baked),
2643 &ExternalLoaderCompiledData,
2644 locale,
2645 pattern.iter_items(),
2646 &mut self.metadata,
2647 )?;
2648 Ok(DateTimePatternFormatter::new(
2649 pattern.as_borrowed(),
2650 self.inner.as_borrowed(),
2651 ))
2652 }
2653}
2654
2655impl<C, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
2656 /// Maps a [`FixedCalendarDateTimeNames`] of a specific `FSet` to a more general `FSet`.
2657 ///
2658 /// For example, this can transform a formatter for [`DateFieldSet`] to one for
2659 /// [`CompositeDateTimeFieldSet`].
2660 ///
2661 /// [`DateFieldSet`]: crate::fieldsets::enums::DateFieldSet
2662 /// [`CompositeDateTimeFieldSet`]: crate::fieldsets::enums::CompositeDateTimeFieldSet
2663 ///
2664 /// # Examples
2665 ///
2666 /// ```
2667 /// use icu::calendar::Gregorian;
2668 /// use icu::datetime::fieldsets::enums::{
2669 /// CompositeDateTimeFieldSet, DateFieldSet,
2670 /// };
2671 /// use icu::datetime::input::Date;
2672 /// use icu::datetime::input::{DateTime, Time};
2673 /// use icu::datetime::pattern::DateTimePattern;
2674 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
2675 /// use icu::datetime::pattern::MonthNameLength;
2676 /// use icu::locale::locale;
2677 /// use writeable::assert_try_writeable_eq;
2678 ///
2679 /// // Create an instance that can format abbreviated month names:
2680 /// let mut names: FixedCalendarDateTimeNames<Gregorian, DateFieldSet> =
2681 /// FixedCalendarDateTimeNames::try_new(locale!("uk").into()).unwrap();
2682 /// names
2683 /// .include_month_names(MonthNameLength::Abbreviated)
2684 /// .unwrap();
2685 ///
2686 /// // Test it with a pattern:
2687 /// let pattern_str = "MMM d y";
2688 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
2689 /// let datetime = DateTime {
2690 /// date: Date::try_new_gregorian(2023, 11, 20).unwrap(),
2691 /// time: Time::start_of_day(),
2692 /// };
2693 /// assert_try_writeable_eq!(
2694 /// names.with_pattern_unchecked(&pattern).format(&datetime),
2695 /// "лист. 20 2023"
2696 /// );
2697 ///
2698 /// // Convert the field set to `CompositeDateTimeFieldSet`:
2699 /// let composite_names = names.cast_into_fset::<CompositeDateTimeFieldSet>();
2700 ///
2701 /// // It should still work:
2702 /// assert_try_writeable_eq!(
2703 /// composite_names
2704 /// .with_pattern_unchecked(&pattern)
2705 /// .format(&datetime),
2706 /// "лист. 20 2023"
2707 /// );
2708 /// ```
2709 ///
2710 /// Converting into a narrower type is not supported:
2711 ///
2712 /// ```compile_fail,E0277
2713 /// use icu::calendar::Gregorian;
2714 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
2715 /// use icu::datetime::fieldsets::enums::{DateFieldSet, CompositeDateTimeFieldSet};
2716 ///
2717 /// let composite_names: FixedCalendarDateTimeNames<Gregorian, CompositeDateTimeFieldSet> = todo!();
2718 ///
2719 /// // error[E0277]: the trait bound `(): From<DataPayloadWithVariables<DayPeriodNamesV1, FieldLength>>` is not satisfied
2720 /// let narrow_names = composite_names.cast_into_fset::<DateFieldSet>();
2721 /// ```
2722 pub fn cast_into_fset<FSet2: DateTimeNamesFrom<FSet>>(
2723 self,
2724 ) -> FixedCalendarDateTimeNames<C, FSet2> {
2725 FixedCalendarDateTimeNames {
2726 prefs: self.prefs,
2727 inner: self.inner.cast_into_fset(),
2728 metadata: self.metadata,
2729 _calendar: PhantomData,
2730 }
2731 }
2732}
2733
2734impl<FSet: DateTimeNamesMarker> DateTimeNames<FSet> {
2735 /// Maps a [`FixedCalendarDateTimeNames`] of a specific `FSet` to a more general `FSet`.
2736 ///
2737 /// For example, this can transform a formatter for [`DateFieldSet`] to one for
2738 /// [`CompositeDateTimeFieldSet`].
2739 ///
2740 /// [`DateFieldSet`]: crate::fieldsets::enums::DateFieldSet
2741 /// [`CompositeDateTimeFieldSet`]: crate::fieldsets::enums::CompositeDateTimeFieldSet
2742 pub fn cast_into_fset<FSet2: DateTimeNamesFrom<FSet>>(self) -> DateTimeNames<FSet2> {
2743 DateTimeNames {
2744 inner: self.inner.cast_into_fset(),
2745 calendar: self.calendar,
2746 }
2747 }
2748}
2749
2750impl<FSet: DateTimeNamesMarker> RawDateTimeNames<FSet> {
2751 pub(crate) fn new_without_number_formatting() -> Self {
2752 Self {
2753 year_names: <FSet::YearNames as NamesContainer<
2754 YearNamesV1,
2755 YearNameLength,
2756 >>::Container::new_empty(),
2757 month_names: <FSet::MonthNames as NamesContainer<
2758 MonthNamesV1,
2759 MonthNameLength,
2760 >>::Container::new_empty(),
2761 weekday_names: <FSet::WeekdayNames as NamesContainer<
2762 WeekdayNamesV1,
2763 WeekdayNameLength,
2764 >>::Container::new_empty(),
2765 dayperiod_names: <FSet::DayPeriodNames as NamesContainer<
2766 DayPeriodNamesV1,
2767 DayPeriodNameLength,
2768 >>::Container::new_empty(),
2769 zone_essentials: <FSet::ZoneEssentials as NamesContainer<
2770 tz::EssentialsV1,
2771 (),
2772 >>::Container::new_empty(),
2773 locations_root: <FSet::ZoneLocationsRoot as NamesContainer<
2774 tz::LocationsRootV1,
2775 (),
2776 >>::Container::new_empty(),
2777 locations: <FSet::ZoneLocations as NamesContainer<
2778 tz::LocationsOverrideV1,
2779 (),
2780 >>::Container::new_empty(),
2781 exemplars: <FSet::ZoneExemplars as NamesContainer<
2782 tz::CitiesOverrideV1,
2783 (),
2784 >>::Container::new_empty(),
2785 exemplars_root: <FSet::ZoneExemplarsRoot as NamesContainer<
2786 tz::CitiesRootV1,
2787 (),
2788 >>::Container::new_empty(),
2789 mz_generic_long: <FSet::ZoneGenericLong as NamesContainer<
2790 tz::MzGenericLongV1,
2791 (),
2792 >>::Container::new_empty(),
2793 mz_generic_short: <FSet::ZoneGenericShort as NamesContainer<
2794 tz::MzGenericShortV1,
2795 (),
2796 >>::Container::new_empty(),
2797 mz_standard_long: <FSet::ZoneStandardLong as NamesContainer<
2798 tz::MzStandardLongV1,
2799 (),
2800 >>::Container::new_empty(),
2801 mz_specific_long: <FSet::ZoneSpecificLong as NamesContainer<
2802 tz::MzSpecificLongV1,
2803 (),
2804 >>::Container::new_empty(),
2805 mz_specific_short: <FSet::ZoneSpecificShort as NamesContainer<
2806 tz::MzSpecificShortV1,
2807 (),
2808 >>::Container::new_empty(),
2809 mz_periods: <FSet::MetazoneLookup as NamesContainer<
2810 tz::MzPeriodV1,
2811 (),
2812 >>::Container::new_empty(),
2813 decimal_formatter: None,
2814 _marker: PhantomData,
2815 }
2816 }
2817
2818 pub(crate) fn as_borrowed(&self) -> RawDateTimeNamesBorrowed<'_> {
2819 RawDateTimeNamesBorrowed {
2820 year_names: self.year_names.get().inner,
2821 month_names: self.month_names.get().inner,
2822 weekday_names: self.weekday_names.get().inner,
2823 dayperiod_names: self.dayperiod_names.get().inner,
2824 zone_essentials: self.zone_essentials.get().inner,
2825 locations_root: self.locations_root.get().inner,
2826 locations: self.locations.get().inner,
2827 exemplars_root: self.exemplars_root.get().inner,
2828 exemplars: self.exemplars.get().inner,
2829 mz_generic_long: self.mz_generic_long.get().inner,
2830 mz_generic_short: self.mz_generic_short.get().inner,
2831 mz_standard_long: self.mz_standard_long.get().inner,
2832 mz_specific_long: self.mz_specific_long.get().inner,
2833 mz_specific_short: self.mz_specific_short.get().inner,
2834 mz_periods: self.mz_periods.get().inner,
2835 decimal_formatter: self.decimal_formatter.as_ref(),
2836 }
2837 }
2838
2839 pub(crate) fn load_year_names<P>(
2840 &mut self,
2841 provider: &P,
2842 prefs: DateTimeFormatterPreferences,
2843 length: YearNameLength,
2844 error_field: ErrorField,
2845 ) -> Result<(), PatternLoadError>
2846 where
2847 P: BoundDataProvider<YearNamesV1> + ?Sized,
2848 {
2849 let attributes = length.to_attributes();
2850 let locale = provider
2851 .bound_marker()
2852 .make_locale(prefs.locale_preferences);
2853 let req = DataRequest {
2854 id: DataIdentifierBorrowed::for_marker_attributes_and_locale(attributes, &locale),
2855 ..Default::default()
2856 };
2857 self.year_names
2858 .load_put(provider, req, length)
2859 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
2860 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2861 Ok(())
2862 }
2863
2864 pub(crate) fn load_month_names<P>(
2865 &mut self,
2866 provider: &P,
2867 prefs: DateTimeFormatterPreferences,
2868 length: MonthNameLength,
2869 error_field: ErrorField,
2870 ) -> Result<(), PatternLoadError>
2871 where
2872 P: BoundDataProvider<MonthNamesV1> + ?Sized,
2873 {
2874 let attributes = length.to_attributes();
2875 let locale = provider
2876 .bound_marker()
2877 .make_locale(prefs.locale_preferences);
2878 let req = DataRequest {
2879 id: DataIdentifierBorrowed::for_marker_attributes_and_locale(attributes, &locale),
2880 ..Default::default()
2881 };
2882 self.month_names
2883 .load_put(provider, req, length)
2884 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
2885 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2886 Ok(())
2887 }
2888
2889 pub(crate) fn load_day_period_names<P>(
2890 &mut self,
2891 provider: &P,
2892 prefs: DateTimeFormatterPreferences,
2893 length: DayPeriodNameLength,
2894 error_field: ErrorField,
2895 ) -> Result<(), PatternLoadError>
2896 where
2897 P: BoundDataProvider<DayPeriodNamesV1> + ?Sized,
2898 {
2899 let attributes = length.to_attributes();
2900 let locale = provider
2901 .bound_marker()
2902 .make_locale(prefs.locale_preferences);
2903 let req = DataRequest {
2904 id: DataIdentifierBorrowed::for_marker_attributes_and_locale(attributes, &locale),
2905 ..Default::default()
2906 };
2907 self.dayperiod_names
2908 .load_put(provider, req, length)
2909 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
2910 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2911 Ok(())
2912 }
2913
2914 pub(crate) fn load_weekday_names<P>(
2915 &mut self,
2916 provider: &P,
2917 prefs: DateTimeFormatterPreferences,
2918 length: WeekdayNameLength,
2919 error_field: ErrorField,
2920 ) -> Result<(), PatternLoadError>
2921 where
2922 P: BoundDataProvider<WeekdayNamesV1> + ?Sized,
2923 {
2924 let attributes = length.to_attributes();
2925 let locale = provider
2926 .bound_marker()
2927 .make_locale(prefs.locale_preferences);
2928 let req = DataRequest {
2929 id: DataIdentifierBorrowed::for_marker_attributes_and_locale(attributes, &locale),
2930 ..Default::default()
2931 };
2932 self.weekday_names
2933 .load_put(provider, req, length)
2934 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
2935 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2936 Ok(())
2937 }
2938
2939 pub(crate) fn load_time_zone_essentials<P>(
2940 &mut self,
2941 provider: &P,
2942 prefs: DateTimeFormatterPreferences,
2943 ) -> Result<ErrorField, PatternLoadError>
2944 where
2945 P: BoundDataProvider<tz::EssentialsV1> + ?Sized,
2946 {
2947 let locale = provider
2948 .bound_marker()
2949 .make_locale(prefs.locale_preferences);
2950 let error_field = ErrorField(fields::Field {
2951 symbol: FieldSymbol::TimeZone(fields::TimeZone::LocalizedOffset),
2952 length: FieldLength::Four,
2953 });
2954 let variables = ();
2955 let req = DataRequest {
2956 id: DataIdentifierBorrowed::for_locale(&locale),
2957 ..Default::default()
2958 };
2959 self.zone_essentials
2960 .load_put(provider, req, variables)
2961 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
2962 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2963 Ok(error_field)
2964 }
2965
2966 pub(crate) fn load_time_zone_location_names<P, P2>(
2967 &mut self,
2968 provider: &P,
2969 root_provider: &P2,
2970 prefs: DateTimeFormatterPreferences,
2971 ) -> Result<ErrorField, PatternLoadError>
2972 where
2973 P: BoundDataProvider<tz::LocationsOverrideV1> + ?Sized,
2974 P2: BoundDataProvider<tz::LocationsRootV1> + ?Sized,
2975 {
2976 let locale = provider
2977 .bound_marker()
2978 .make_locale(prefs.locale_preferences);
2979 let error_field = ErrorField(fields::Field {
2980 symbol: FieldSymbol::TimeZone(fields::TimeZone::Location),
2981 length: FieldLength::Four,
2982 });
2983 let variables = ();
2984 let req = DataRequest {
2985 id: DataIdentifierBorrowed::for_locale(&locale),
2986 ..Default::default()
2987 };
2988 self.locations_root
2989 .load_put(root_provider, req, variables)
2990 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
2991 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2992 self.locations
2993 .load_put(provider, req, variables)
2994 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
2995 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2996 Ok(error_field)
2997 }
2998
2999 pub(crate) fn load_time_zone_exemplar_city_names<P, P2>(
3000 &mut self,
3001 provider: &P,
3002 root_provider: &P2,
3003 prefs: DateTimeFormatterPreferences,
3004 ) -> Result<ErrorField, PatternLoadError>
3005 where
3006 P: BoundDataProvider<tz::CitiesOverrideV1> + ?Sized,
3007 P2: BoundDataProvider<tz::CitiesRootV1> + ?Sized,
3008 {
3009 let locale = provider
3010 .bound_marker()
3011 .make_locale(prefs.locale_preferences);
3012 let error_field = ErrorField(fields::Field {
3013 symbol: FieldSymbol::TimeZone(fields::TimeZone::Location),
3014 length: FieldLength::Three,
3015 });
3016 let variables = ();
3017 let req = DataRequest {
3018 id: DataIdentifierBorrowed::for_locale(&locale),
3019 ..Default::default()
3020 };
3021 self.exemplars_root
3022 .load_put(root_provider, req, variables)
3023 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3024 .map_err(|e| PatternLoadError::Data(e, error_field))?;
3025 self.exemplars
3026 .load_put(provider, req, variables)
3027 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3028 .map_err(|e| PatternLoadError::Data(e, error_field))?;
3029 Ok(error_field)
3030 }
3031
3032 pub(crate) fn load_time_zone_generic_long_names(
3033 &mut self,
3034 mz_generic_provider: &(impl BoundDataProvider<tz::MzGenericLongV1> + ?Sized),
3035 mz_standard_provider: &(impl BoundDataProvider<tz::MzStandardLongV1> + ?Sized),
3036 mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3037 prefs: DateTimeFormatterPreferences,
3038 names_metadata: &mut DateTimeNamesMetadata,
3039 ) -> Result<ErrorField, PatternLoadError> {
3040 let locale = mz_generic_provider
3041 .bound_marker()
3042 .make_locale(prefs.locale_preferences);
3043 let error_field = ErrorField(fields::Field {
3044 symbol: FieldSymbol::TimeZone(fields::TimeZone::GenericNonLocation),
3045 length: FieldLength::Four,
3046 });
3047 let variables = ();
3048 let req = DataRequest {
3049 id: DataIdentifierBorrowed::for_locale(&locale),
3050 ..Default::default()
3051 };
3052 let mut save_checksum = |cs: &u64| {
3053 // get_or_insert saves the value only if the Option is None.
3054 names_metadata.zone_checksum.get_or_insert(*cs);
3055 };
3056 let cs1 = self
3057 .mz_generic_long
3058 .load_put(mz_generic_provider, req, variables)
3059 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3060 .map_err(|e| PatternLoadError::Data(e, error_field))?
3061 .checksum
3062 .inspect(&mut save_checksum);
3063 let cs2 = self
3064 .mz_standard_long
3065 .load_put(mz_standard_provider, req, variables)
3066 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3067 .map_err(|e| PatternLoadError::Data(e, error_field))?
3068 .checksum
3069 .inspect(&mut save_checksum);
3070 let cs3 = self
3071 .mz_periods
3072 .load_put(mz_period_provider, Default::default(), ())
3073 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3074 .map_err(|e| PatternLoadError::Data(e, error_field))?
3075 .checksum
3076 .inspect(&mut save_checksum);
3077 // Error if any two of the checksum Options are Some and not equal.
3078 let cs = names_metadata.zone_checksum;
3079 if cs1.or(cs) != cs || cs2.or(cs) != cs || cs3.or(cs) != cs {
3080 return Err(PatternLoadError::Data(
3081 DataErrorKind::InconsistentData(tz::MzPeriodV1::INFO)
3082 .with_req(tz::MzGenericLongV1::INFO, req),
3083 error_field,
3084 ));
3085 }
3086 Ok(error_field)
3087 }
3088
3089 pub(crate) fn load_time_zone_generic_short_names(
3090 &mut self,
3091 provider: &(impl BoundDataProvider<tz::MzGenericShortV1> + ?Sized),
3092 mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3093 prefs: DateTimeFormatterPreferences,
3094 names_metadata: &mut DateTimeNamesMetadata,
3095 ) -> Result<ErrorField, PatternLoadError> {
3096 let locale = provider
3097 .bound_marker()
3098 .make_locale(prefs.locale_preferences);
3099 let error_field = ErrorField(fields::Field {
3100 symbol: FieldSymbol::TimeZone(fields::TimeZone::GenericNonLocation),
3101 length: FieldLength::One,
3102 });
3103 let variables = ();
3104 let req = DataRequest {
3105 id: DataIdentifierBorrowed::for_locale(&locale),
3106 ..Default::default()
3107 };
3108 let mut save_checksum = |cs: &u64| {
3109 // get_or_insert saves the value only if the Option is None.
3110 names_metadata.zone_checksum.get_or_insert(*cs);
3111 };
3112 let cs1 = self
3113 .mz_generic_short
3114 .load_put(provider, req, variables)
3115 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3116 .map_err(|e| PatternLoadError::Data(e, error_field))?
3117 .checksum
3118 .inspect(&mut save_checksum);
3119 let cs2 = self
3120 .mz_periods
3121 .load_put(mz_period_provider, Default::default(), ())
3122 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3123 .map_err(|e| PatternLoadError::Data(e, error_field))?
3124 .checksum
3125 .inspect(&mut save_checksum);
3126 // Error if any two of the checksum Options are Some and not equal.
3127 let cs = names_metadata.zone_checksum;
3128 if cs1.or(cs) != cs || cs2.or(cs) != cs {
3129 return Err(PatternLoadError::Data(
3130 DataErrorKind::InconsistentData(tz::MzPeriodV1::INFO)
3131 .with_req(tz::MzGenericLongV1::INFO, req),
3132 error_field,
3133 ));
3134 }
3135 Ok(error_field)
3136 }
3137
3138 pub(crate) fn load_time_zone_specific_long_names(
3139 &mut self,
3140 mz_specific_provider: &(impl BoundDataProvider<tz::MzSpecificLongV1> + ?Sized),
3141 mz_standard_provider: &(impl BoundDataProvider<tz::MzStandardLongV1> + ?Sized),
3142 mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3143 prefs: DateTimeFormatterPreferences,
3144 names_metadata: &mut DateTimeNamesMetadata,
3145 ) -> Result<ErrorField, PatternLoadError> {
3146 let locale = mz_specific_provider
3147 .bound_marker()
3148 .make_locale(prefs.locale_preferences);
3149 let error_field = ErrorField(fields::Field {
3150 symbol: FieldSymbol::TimeZone(fields::TimeZone::SpecificNonLocation),
3151 length: FieldLength::Four,
3152 });
3153 let variables = ();
3154 let req = DataRequest {
3155 id: DataIdentifierBorrowed::for_locale(&locale),
3156 ..Default::default()
3157 };
3158 let mut save_checksum = |cs: &u64| {
3159 // get_or_insert saves the value only if the Option is None.
3160 names_metadata.zone_checksum.get_or_insert(*cs);
3161 };
3162 let cs1 = self
3163 .mz_specific_long
3164 .load_put(mz_specific_provider, req, variables)
3165 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3166 .map_err(|e| PatternLoadError::Data(e, error_field))?
3167 .checksum
3168 .inspect(&mut save_checksum);
3169 let cs2 = self
3170 .mz_standard_long
3171 .load_put(mz_standard_provider, req, variables)
3172 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3173 .map_err(|e| PatternLoadError::Data(e, error_field))?
3174 .checksum
3175 .inspect(&mut save_checksum);
3176 let cs3 = self
3177 .mz_periods
3178 .load_put(mz_period_provider, Default::default(), ())
3179 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3180 .map_err(|e| PatternLoadError::Data(e, error_field))?
3181 .checksum
3182 .inspect(&mut save_checksum);
3183 // Error if any two of the checksum Options are Some and not equal.
3184 let cs = names_metadata.zone_checksum;
3185 if cs1.or(cs) != cs || cs2.or(cs) != cs || cs3.or(cs) != cs {
3186 return Err(PatternLoadError::Data(
3187 DataErrorKind::InconsistentData(tz::MzPeriodV1::INFO)
3188 .with_req(tz::MzSpecificLongV1::INFO, req),
3189 error_field,
3190 ));
3191 }
3192 Ok(error_field)
3193 }
3194
3195 pub(crate) fn load_time_zone_specific_short_names(
3196 &mut self,
3197 provider: &(impl BoundDataProvider<tz::MzSpecificShortV1> + ?Sized),
3198 mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3199 prefs: DateTimeFormatterPreferences,
3200 names_metadata: &mut DateTimeNamesMetadata,
3201 ) -> Result<ErrorField, PatternLoadError> {
3202 let locale = provider
3203 .bound_marker()
3204 .make_locale(prefs.locale_preferences);
3205 let error_field = ErrorField(fields::Field {
3206 symbol: FieldSymbol::TimeZone(fields::TimeZone::SpecificNonLocation),
3207 length: FieldLength::One,
3208 });
3209 let variables = ();
3210 let req = DataRequest {
3211 id: DataIdentifierBorrowed::for_locale(&locale),
3212 ..Default::default()
3213 };
3214 let mut save_checksum = |cs: &u64| {
3215 // get_or_insert saves the value only if the Option is None.
3216 names_metadata.zone_checksum.get_or_insert(*cs);
3217 };
3218 let cs1 = self
3219 .mz_specific_short
3220 .load_put(provider, req, variables)
3221 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3222 .map_err(|e| PatternLoadError::Data(e, error_field))?
3223 .checksum
3224 .inspect(&mut save_checksum);
3225 let cs2 = self
3226 .mz_periods
3227 .load_put(mz_period_provider, Default::default(), ())
3228 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3229 .map_err(|e| PatternLoadError::Data(e, error_field))?
3230 .checksum
3231 .inspect(&mut save_checksum);
3232 // Error if any two of the checksum Options are Some and not equal.
3233 let cs = names_metadata.zone_checksum;
3234 if cs1.or(cs) != cs || cs2.or(cs) != cs {
3235 return Err(PatternLoadError::Data(
3236 DataErrorKind::InconsistentData(tz::MzPeriodV1::INFO)
3237 .with_req(tz::MzSpecificShortV1::INFO, req),
3238 error_field,
3239 ));
3240 }
3241 Ok(error_field)
3242 }
3243
3244 pub(crate) fn load_time_zone_field_z_except_decimals(
3245 &mut self,
3246 zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3247 mz_specific_short_provider: &(impl BoundDataProvider<tz::MzSpecificShortV1> + ?Sized),
3248 mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3249 prefs: DateTimeFormatterPreferences,
3250 names_metadata: &mut DateTimeNamesMetadata,
3251 ) -> Result<ErrorField, PatternLoadError> {
3252 self.load_time_zone_essentials(zone_essentials_provider, prefs)?;
3253 self.load_time_zone_specific_short_names(
3254 mz_specific_short_provider,
3255 mz_period_provider,
3256 prefs,
3257 names_metadata,
3258 )
3259 }
3260
3261 #[expect(clippy::too_many_arguments)]
3262 pub(crate) fn load_time_zone_field_zzzz_except_decimals(
3263 &mut self,
3264 zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3265 locations_provider: &(impl BoundDataProvider<tz::LocationsOverrideV1> + ?Sized),
3266 locations_root_provider: &(impl BoundDataProvider<tz::LocationsRootV1> + ?Sized),
3267 mz_standard_long_provider: &(impl BoundDataProvider<tz::MzStandardLongV1> + ?Sized),
3268 mz_specific_long_provider: &(impl BoundDataProvider<tz::MzSpecificLongV1> + ?Sized),
3269 mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3270 prefs: DateTimeFormatterPreferences,
3271 names_metadata: &mut DateTimeNamesMetadata,
3272 ) -> Result<ErrorField, PatternLoadError> {
3273 self.load_time_zone_essentials(zone_essentials_provider, prefs)?;
3274 self.load_time_zone_location_names(locations_provider, locations_root_provider, prefs)?;
3275 self.load_time_zone_specific_long_names(
3276 mz_specific_long_provider,
3277 mz_standard_long_provider,
3278 mz_period_provider,
3279 prefs,
3280 names_metadata,
3281 )
3282 }
3283
3284 #[expect(clippy::too_many_arguments)] // internal function with lots of generics
3285 pub(crate) fn load_time_zone_field_v_except_decimals(
3286 &mut self,
3287 zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3288 locations_provider: &(impl BoundDataProvider<tz::LocationsOverrideV1> + ?Sized),
3289 locations_root_provider: &(impl BoundDataProvider<tz::LocationsRootV1> + ?Sized),
3290 mz_generic_short_provider: &(impl BoundDataProvider<tz::MzGenericShortV1> + ?Sized),
3291 mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3292 prefs: DateTimeFormatterPreferences,
3293 names_metadata: &mut DateTimeNamesMetadata,
3294 ) -> Result<ErrorField, PatternLoadError> {
3295 self.load_time_zone_essentials(zone_essentials_provider, prefs)?;
3296 // For fallback:
3297 self.load_time_zone_location_names(locations_provider, locations_root_provider, prefs)?;
3298 self.load_time_zone_generic_short_names(
3299 mz_generic_short_provider,
3300 mz_period_provider,
3301 prefs,
3302 names_metadata,
3303 )
3304 }
3305
3306 #[expect(clippy::too_many_arguments)]
3307 pub(crate) fn load_time_zone_field_vvvv_except_decimals(
3308 &mut self,
3309 zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3310 locations_provider: &(impl BoundDataProvider<tz::LocationsOverrideV1> + ?Sized),
3311 locations_root_provider: &(impl BoundDataProvider<tz::LocationsRootV1> + ?Sized),
3312 mz_generic_long_provider: &(impl BoundDataProvider<tz::MzGenericLongV1> + ?Sized),
3313 mz_standard_long_provider: &(impl BoundDataProvider<tz::MzStandardLongV1> + ?Sized),
3314 mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3315 prefs: DateTimeFormatterPreferences,
3316 names_metadata: &mut DateTimeNamesMetadata,
3317 ) -> Result<ErrorField, PatternLoadError> {
3318 self.load_time_zone_essentials(zone_essentials_provider, prefs)?;
3319 // For fallback:
3320 self.load_time_zone_location_names(locations_provider, locations_root_provider, prefs)?;
3321 self.load_time_zone_generic_long_names(
3322 mz_generic_long_provider,
3323 mz_standard_long_provider,
3324 mz_period_provider,
3325 prefs,
3326 names_metadata,
3327 )
3328 }
3329
3330 #[allow(non_snake_case)] // this is a private function named after the case-sensitive CLDR field
3331 pub(crate) fn load_time_zone_field_V(
3332 &mut self,
3333 _prefs: DateTimeFormatterPreferences,
3334 ) -> Result<(), PatternLoadError> {
3335 // no data required
3336 Ok(())
3337 }
3338
3339 #[allow(non_snake_case)] // this is a private function named after the case-sensitive CLDR field
3340 pub(crate) fn load_time_zone_field_VVV(
3341 &mut self,
3342 locations_provider: &(impl BoundDataProvider<tz::LocationsOverrideV1> + ?Sized),
3343 locations_root_provider: &(impl BoundDataProvider<tz::LocationsRootV1> + ?Sized),
3344 exemplar_cities_provider: &(impl BoundDataProvider<tz::CitiesOverrideV1> + ?Sized),
3345 exemplar_cities_root_provider: &(impl BoundDataProvider<tz::CitiesRootV1> + ?Sized),
3346 prefs: DateTimeFormatterPreferences,
3347 ) -> Result<ErrorField, PatternLoadError> {
3348 self.load_time_zone_location_names(locations_provider, locations_root_provider, prefs)?;
3349 self.load_time_zone_exemplar_city_names(
3350 exemplar_cities_provider,
3351 exemplar_cities_root_provider,
3352 prefs,
3353 )
3354 }
3355
3356 #[allow(non_snake_case)] // this is a private function named after the case-sensitive CLDR field
3357 pub(crate) fn load_time_zone_field_VVVV_except_decimals(
3358 &mut self,
3359 zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3360 locations_provider: &(impl BoundDataProvider<tz::LocationsOverrideV1> + ?Sized),
3361 locations_root_provider: &(impl BoundDataProvider<tz::LocationsRootV1> + ?Sized),
3362 prefs: DateTimeFormatterPreferences,
3363 ) -> Result<ErrorField, PatternLoadError> {
3364 self.load_time_zone_essentials(zone_essentials_provider, prefs)?;
3365 self.load_time_zone_location_names(locations_provider, locations_root_provider, prefs)
3366 }
3367
3368 #[allow(non_snake_case)] // this is a private function named after the case-sensitive CLDR field
3369 pub(crate) fn load_time_zone_field_O_except_decimals(
3370 &mut self,
3371 zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3372 prefs: DateTimeFormatterPreferences,
3373 ) -> Result<ErrorField, PatternLoadError> {
3374 self.load_time_zone_essentials(zone_essentials_provider, prefs)
3375 }
3376
3377 #[allow(non_snake_case)] // this is a private function named after the case-sensitive CLDR field
3378 pub(crate) fn load_time_zone_field_X(
3379 &mut self,
3380 _prefs: DateTimeFormatterPreferences,
3381 ) -> Result<(), PatternLoadError> {
3382 // no data required
3383 Ok(())
3384 }
3385
3386 pub(crate) fn load_decimal_formatter(
3387 &mut self,
3388 loader: &impl DecimalFormatterLoader,
3389 prefs: DateTimeFormatterPreferences,
3390 ) -> Result<(), DataError> {
3391 if self.decimal_formatter.is_some() {
3392 return Ok(());
3393 }
3394 let mut options = DecimalFormatterOptions::default();
3395 options.grouping_strategy = Some(GroupingStrategy::Never);
3396 self.decimal_formatter = Some(DecimalFormatterLoader::load(
3397 loader,
3398 (&prefs).into(),
3399 options,
3400 )?);
3401 Ok(())
3402 }
3403
3404 /// Loads all data required for formatting the given [`PatternItem`]s.
3405 ///
3406 /// This function has a lot of arguments because many of the arguments are generic,
3407 /// and pulling them out to an options struct would be cumbersome.
3408 #[expect(clippy::too_many_arguments)]
3409 pub(crate) fn load_for_pattern(
3410 &mut self,
3411 year_provider: &(impl BoundDataProvider<YearNamesV1> + ?Sized),
3412 month_provider: &(impl BoundDataProvider<MonthNamesV1> + ?Sized),
3413 weekday_provider: &(impl BoundDataProvider<WeekdayNamesV1> + ?Sized),
3414 dayperiod_provider: &(impl BoundDataProvider<DayPeriodNamesV1> + ?Sized),
3415 zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3416 locations_provider: &(impl BoundDataProvider<tz::LocationsOverrideV1> + ?Sized),
3417 locations_root_provider: &(impl BoundDataProvider<tz::LocationsRootV1> + ?Sized),
3418 exemplar_cities_provider: &(impl BoundDataProvider<tz::CitiesOverrideV1> + ?Sized),
3419 exemplar_cities_root_provider: &(impl BoundDataProvider<tz::CitiesRootV1> + ?Sized),
3420 mz_generic_long_provider: &(impl BoundDataProvider<tz::MzGenericLongV1> + ?Sized),
3421 mz_generic_short_provider: &(impl BoundDataProvider<tz::MzGenericShortV1> + ?Sized),
3422 mz_standard_long_provider: &(impl BoundDataProvider<tz::MzStandardLongV1> + ?Sized),
3423 mz_specific_long_provider: &(impl BoundDataProvider<tz::MzSpecificLongV1> + ?Sized),
3424 mz_specific_short_provider: &(impl BoundDataProvider<tz::MzSpecificShortV1> + ?Sized),
3425 mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3426 decimal_formatter_loader: &impl DecimalFormatterLoader,
3427 prefs: DateTimeFormatterPreferences,
3428 pattern_items: impl Iterator<Item = PatternItem>,
3429 names_metadata: &mut DateTimeNamesMetadata,
3430 ) -> Result<(), PatternLoadError> {
3431 let mut numeric_field = None;
3432
3433 for item in pattern_items {
3434 let PatternItem::Field(field) = item else {
3435 continue;
3436 };
3437 let error_field = ErrorField(field);
3438
3439 use crate::provider::fields::*;
3440 use FieldLength::*;
3441 use FieldSymbol as FS;
3442
3443 match (field.symbol, field.length) {
3444 ///// Textual symbols /////
3445
3446 // G..GGGGG
3447 (FS::Era, One | Two | Three | Four | Five) => {
3448 self.load_year_names(
3449 year_provider,
3450 prefs,
3451 YearNameLength::from_field_length(field.length)
3452 .ok_or(PatternLoadError::UnsupportedLength(error_field))?,
3453 error_field,
3454 )?;
3455 }
3456
3457 // U..UUUUU
3458 (FS::Year(Year::Cyclic), One | Two | Three | Four | Five) => {
3459 numeric_field = Some(field);
3460 self.load_year_names(
3461 year_provider,
3462 prefs,
3463 YearNameLength::from_field_length(field.length)
3464 .ok_or(PatternLoadError::UnsupportedLength(error_field))?,
3465 error_field,
3466 )?;
3467 }
3468
3469 // MMM..MMMMM, LLL..LLLLL
3470 (
3471 FS::Month(field_symbol @ Month::Format | field_symbol @ Month::StandAlone),
3472 Three | Four | Five,
3473 ) => {
3474 self.load_month_names(
3475 month_provider,
3476 prefs,
3477 MonthNameLength::from_field(field_symbol, field.length)
3478 .ok_or(PatternLoadError::UnsupportedLength(error_field))?,
3479 error_field,
3480 )?;
3481 }
3482
3483 // e..ee, c..cc
3484 (FS::Weekday(Weekday::Local | Weekday::StandAlone), One | Two) => {
3485 // TODO(#5643): Requires locale-aware day-of-week calculation
3486 return Err(PatternLoadError::UnsupportedLength(ErrorField(field)));
3487 }
3488
3489 // E..EEEEEE, eee..eeeeee, ccc..cccccc
3490 (FS::Weekday(field_symbol), One | Two | Three | Four | Five | Six) => {
3491 self.load_weekday_names(
3492 weekday_provider,
3493 prefs,
3494 WeekdayNameLength::from_field(field_symbol, field.length)
3495 .ok_or(PatternLoadError::UnsupportedLength(error_field))?,
3496 error_field,
3497 )?;
3498 }
3499
3500 // a..aaaaa, b..bbbbb
3501 (FS::DayPeriod(field_symbol), One | Two | Three | Four | Five) => {
3502 self.load_day_period_names(
3503 dayperiod_provider,
3504 prefs,
3505 DayPeriodNameLength::from_field(field_symbol, field.length)
3506 .ok_or(PatternLoadError::UnsupportedLength(error_field))?,
3507 error_field,
3508 )?;
3509 }
3510
3511 ///// Time zone symbols /////
3512
3513 // z..zzz
3514 (FS::TimeZone(TimeZone::SpecificNonLocation), One | Two | Three) => {
3515 self.load_time_zone_field_z_except_decimals(
3516 zone_essentials_provider,
3517 mz_specific_short_provider,
3518 mz_period_provider,
3519 prefs,
3520 names_metadata,
3521 )?;
3522 numeric_field = Some(field);
3523 }
3524 // zzzz
3525 (FS::TimeZone(TimeZone::SpecificNonLocation), Four) => {
3526 self.load_time_zone_field_zzzz_except_decimals(
3527 zone_essentials_provider,
3528 locations_provider,
3529 locations_root_provider,
3530 mz_standard_long_provider,
3531 mz_specific_long_provider,
3532 mz_period_provider,
3533 prefs,
3534 names_metadata,
3535 )?;
3536 numeric_field = Some(field);
3537 }
3538 // v
3539 (FS::TimeZone(TimeZone::GenericNonLocation), One) => {
3540 self.load_time_zone_field_v_except_decimals(
3541 zone_essentials_provider,
3542 locations_provider,
3543 locations_root_provider,
3544 mz_generic_short_provider,
3545 mz_period_provider,
3546 prefs,
3547 names_metadata,
3548 )?;
3549 numeric_field = Some(field);
3550 }
3551 // vvvv
3552 (FS::TimeZone(TimeZone::GenericNonLocation), Four) => {
3553 self.load_time_zone_field_vvvv_except_decimals(
3554 zone_essentials_provider,
3555 locations_provider,
3556 locations_root_provider,
3557 mz_generic_long_provider,
3558 mz_standard_long_provider,
3559 mz_period_provider,
3560 prefs,
3561 names_metadata,
3562 )?;
3563 numeric_field = Some(field);
3564 }
3565
3566 // V
3567 (FS::TimeZone(TimeZone::Location), One) => {
3568 self.load_time_zone_field_V(prefs)?;
3569 }
3570 // VVV
3571 (FS::TimeZone(TimeZone::Location), Three) => {
3572 self.load_time_zone_field_VVV(
3573 locations_provider,
3574 locations_root_provider,
3575 exemplar_cities_provider,
3576 exemplar_cities_root_provider,
3577 prefs,
3578 )?;
3579 }
3580 // VVVV
3581 (FS::TimeZone(TimeZone::Location), Four) => {
3582 self.load_time_zone_field_VVVV_except_decimals(
3583 zone_essentials_provider,
3584 locations_provider,
3585 locations_root_provider,
3586 prefs,
3587 )?;
3588 numeric_field = Some(field);
3589 }
3590 // O, OOOO
3591 (FS::TimeZone(TimeZone::LocalizedOffset), One | Four) => {
3592 self.load_time_zone_field_O_except_decimals(zone_essentials_provider, prefs)?;
3593 numeric_field = Some(field);
3594 }
3595 // X..XXXXX, x..xxxxx
3596 (
3597 FS::TimeZone(TimeZone::IsoWithZ | TimeZone::Iso),
3598 One | Two | Three | Four | Five,
3599 ) => {
3600 self.load_time_zone_field_X(prefs)?;
3601 }
3602
3603 ///// Numeric symbols /////
3604
3605 // y+
3606 (FS::Year(Year::Calendar), _) => numeric_field = Some(field),
3607 // u+
3608 (FS::Year(Year::Extended), _) => numeric_field = Some(field),
3609 // r+
3610 (FS::Year(Year::RelatedIso), _) => {
3611 // always formats as ASCII
3612 }
3613
3614 // M..MM, L..LL
3615 (FS::Month(_), One | Two) => numeric_field = Some(field),
3616
3617 // d..dd
3618 (FS::Day(Day::DayOfMonth), One | Two) => numeric_field = Some(field),
3619 // D..DDD
3620 (FS::Day(Day::DayOfYear), One | Two | Three) => numeric_field = Some(field),
3621 // F
3622 (FS::Day(Day::DayOfWeekInMonth), One) => numeric_field = Some(field),
3623 // g
3624 (FS::Day(Day::ModifiedJulianDay), One) => numeric_field = Some(field),
3625
3626 // K..KK, h..hh, H..HH, k..kk
3627 (FS::Hour(_), One | Two) => numeric_field = Some(field),
3628
3629 // m..mm
3630 (FS::Minute, One | Two) => numeric_field = Some(field),
3631
3632 // s..ss
3633 (FS::Second(Second::Second), One | Two) => numeric_field = Some(field),
3634
3635 // A+
3636 (FS::Second(Second::MillisInDay), _) => numeric_field = Some(field),
3637
3638 // s.S+, ss.S+ (s is modelled by length, S+ by symbol)
3639 (FS::DecimalSecond(_), One | Two) => numeric_field = Some(field),
3640
3641 ///// Unsupported symbols /////
3642 _ => {
3643 return Err(PatternLoadError::UnsupportedLength(ErrorField(field)));
3644 }
3645 }
3646 }
3647
3648 if let Some(field) = numeric_field {
3649 self.load_decimal_formatter(decimal_formatter_loader, prefs)
3650 .map_err(|e| PatternLoadError::Data(e, ErrorField(field)))?;
3651 }
3652
3653 Ok(())
3654 }
3655}
3656
3657impl RawDateTimeNamesBorrowed<'_> {
3658 pub(crate) fn get_name_for_month(
3659 &self,
3660 field_symbol: fields::Month,
3661 field_length: FieldLength,
3662 ordinal_index: u8,
3663 is_leap: bool,
3664 ) -> Result<MonthPlaceholderValue<'_>, GetNameForMonthError> {
3665 let month_name_length = MonthNameLength::from_field(field_symbol, field_length)
3666 .ok_or(GetNameForMonthError::InvalidFieldLength)?;
3667 let month_names = self
3668 .month_names
3669 .get_with_variables(month_name_length)
3670 .ok_or(GetNameForMonthError::NotLoaded)?;
3671 let month_index = usize::from(ordinal_index);
3672 let name = match month_names {
3673 MonthNames::Linear(linear) => {
3674 if is_leap {
3675 None
3676 } else {
3677 linear.get(month_index)
3678 }
3679 }
3680 MonthNames::LeapLinear(leap_linear) => {
3681 let num_months = leap_linear.len() / 2;
3682 if is_leap {
3683 leap_linear.get(month_index + num_months)
3684 } else if month_index < num_months {
3685 leap_linear.get(month_index)
3686 } else {
3687 None
3688 }
3689 }
3690 MonthNames::LeapNumeric(leap_numeric) => {
3691 if is_leap {
3692 return Ok(MonthPlaceholderValue::NumericPattern(leap_numeric));
3693 } else {
3694 return Ok(MonthPlaceholderValue::Numeric);
3695 }
3696 }
3697 };
3698 // Note: Always return `false` for the second argument since neo MonthNames
3699 // knows how to handle leap months and we don't need the fallback logic
3700 name.map(MonthPlaceholderValue::PlainString)
3701 .ok_or(GetNameForMonthError::InvalidMonthCode)
3702 }
3703
3704 pub(crate) fn get_name_for_weekday(
3705 &self,
3706 field_symbol: fields::Weekday,
3707 field_length: FieldLength,
3708 day: icu_calendar::types::Weekday,
3709 ) -> Result<&str, GetNameForWeekdayError> {
3710 let weekday_name_length = WeekdayNameLength::from_field(field_symbol, field_length)
3711 .ok_or(GetNameForWeekdayError::InvalidFieldLength)?;
3712 let weekday_names = self
3713 .weekday_names
3714 .get_with_variables(weekday_name_length)
3715 .ok_or(GetNameForWeekdayError::NotLoaded)?;
3716 weekday_names
3717 .names
3718 .get((day as usize) % 7)
3719 // Note: LinearNames does not guarantee a length of 7.
3720 .ok_or(GetNameForWeekdayError::NotLoaded)
3721 }
3722
3723 /// Gets the era symbol, or `None` if data is loaded but symbol isn't found.
3724 ///
3725 /// `None` should fall back to the era code directly, if, for example,
3726 /// a japanext datetime is formatted with a `DateTimeFormat<Japanese>`
3727 pub(crate) fn get_name_for_era(
3728 &self,
3729 field_length: FieldLength,
3730 era_year: EraYear,
3731 ) -> Result<&str, GetNameForEraError> {
3732 let year_name_length = YearNameLength::from_field_length(field_length)
3733 .ok_or(GetNameForEraError::InvalidFieldLength)?;
3734 let year_names = self
3735 .year_names
3736 .get_with_variables(year_name_length)
3737 .ok_or(GetNameForEraError::NotLoaded)?;
3738
3739 match (year_names, era_year.era_index) {
3740 (YearNames::VariableEras(era_names), None) => {
3741 crate::provider::neo::get_year_name_from_map(
3742 era_names,
3743 era_year.era.as_str().into(),
3744 )
3745 .ok_or(GetNameForEraError::InvalidEraCode)
3746 }
3747 (YearNames::FixedEras(era_names), Some(index)) => era_names
3748 .get(index as usize)
3749 .ok_or(GetNameForEraError::InvalidEraCode),
3750 _ => Err(GetNameForEraError::InvalidEraCode),
3751 }
3752 }
3753
3754 pub(crate) fn get_name_for_cyclic(
3755 &self,
3756 field_length: FieldLength,
3757 cyclic: u8,
3758 ) -> Result<&str, GetNameForCyclicYearError> {
3759 let year_name_length = YearNameLength::from_field_length(field_length)
3760 .ok_or(GetNameForCyclicYearError::InvalidFieldLength)?;
3761 let year_names = self
3762 .year_names
3763 .get_with_variables(year_name_length)
3764 .ok_or(GetNameForCyclicYearError::NotLoaded)?;
3765
3766 let YearNames::Cyclic(cyclics) = year_names else {
3767 return Err(GetNameForCyclicYearError::InvalidYearNumber { max: 0 });
3768 };
3769
3770 cyclics
3771 .get(cyclic as usize - 1)
3772 .ok_or(GetNameForCyclicYearError::InvalidYearNumber {
3773 max: cyclics.len() as u8 + 1,
3774 })
3775 }
3776
3777 pub(crate) fn get_name_for_day_period(
3778 &self,
3779 field_symbol: fields::DayPeriod,
3780 field_length: FieldLength,
3781 hour: icu_time::Hour,
3782 is_top_of_hour: bool,
3783 ) -> Result<&str, GetNameForDayPeriodError> {
3784 use fields::DayPeriod::NoonMidnight;
3785 let day_period_name_length = DayPeriodNameLength::from_field(field_symbol, field_length)
3786 .ok_or(GetNameForDayPeriodError::InvalidFieldLength)?;
3787 let dayperiod_names = self
3788 .dayperiod_names
3789 .get_with_variables(day_period_name_length)
3790 .ok_or(GetNameForDayPeriodError::NotLoaded)?;
3791 let option_value: Option<&str> = match (field_symbol, u8::from(hour), is_top_of_hour) {
3792 (NoonMidnight, 00, true) => dayperiod_names.midnight().or_else(|| dayperiod_names.am()),
3793 (NoonMidnight, 12, true) => dayperiod_names.noon().or_else(|| dayperiod_names.pm()),
3794 (_, hour, _) if hour < 12 => dayperiod_names.am(),
3795 _ => dayperiod_names.pm(),
3796 };
3797 option_value.ok_or(GetNameForDayPeriodError::NotLoaded)
3798 }
3799}
3800
3801/// A container contains all data payloads for time zone formatting (borrowed version).
3802#[derive(Debug, Copy, Clone, Default)]
3803pub(crate) struct TimeZoneDataPayloadsBorrowed<'a> {
3804 /// The data that contains meta information about how to display content.
3805 pub(crate) essentials: Option<&'a tz::Essentials<'a>>,
3806 /// The root location names, e.g. Italy
3807 pub(crate) locations_root: Option<&'a tz::Locations<'a>>,
3808 /// The language specific location names, e.g. Italia
3809 pub(crate) locations: Option<&'a tz::Locations<'a>>,
3810 /// The root exemplar city names, e.g. Rome
3811 pub(crate) exemplars_root: Option<&'a tz::ExemplarCities<'a>>,
3812 /// The language specific exemplar names, e.g. Roma
3813 pub(crate) exemplars: Option<&'a tz::ExemplarCities<'a>>,
3814 /// The generic long metazone names, e.g. Pacific Time
3815 pub(crate) mz_generic_long: Option<&'a tz::MzGeneric<'a>>,
3816 /// The long metazone names shared between generic and standard, e.g. Gulf Standard Time
3817 pub(crate) mz_standard_long: Option<&'a tz::MzGeneric<'a>>,
3818 /// The generic short metazone names, e.g. PT
3819 pub(crate) mz_generic_short: Option<&'a tz::MzGeneric<'a>>,
3820 /// The specific long metazone names, e.g. Pacific Daylight Time
3821 pub(crate) mz_specific_long: Option<&'a tz::MzSpecific<'a>>,
3822 /// The specific short metazone names, e.g. Pacific Daylight Time
3823 pub(crate) mz_specific_short: Option<&'a tz::MzSpecific<'a>>,
3824 /// The metazone lookup
3825 pub(crate) mz_periods: Option<&'a tz::MzPeriod<'a>>,
3826}
3827
3828impl<'data> RawDateTimeNamesBorrowed<'data> {
3829 pub(crate) fn get_payloads(&self) -> TimeZoneDataPayloadsBorrowed<'data> {
3830 TimeZoneDataPayloadsBorrowed {
3831 essentials: self.zone_essentials.get_option(),
3832 locations_root: self.locations_root.get_option(),
3833 locations: self.locations.get_option(),
3834 exemplars: self.exemplars.get_option(),
3835 exemplars_root: self.exemplars_root.get_option(),
3836 mz_generic_long: self.mz_generic_long.get_option(),
3837 mz_standard_long: self.mz_standard_long.get_option(),
3838 mz_generic_short: self.mz_generic_short.get_option(),
3839 mz_specific_long: self.mz_specific_long.get_option(),
3840 mz_specific_short: self.mz_specific_short.get_option(),
3841 mz_periods: self.mz_periods.get_option(),
3842 }
3843 }
3844}