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, MonthCode};
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, VariantOffsetsCalculator};
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_full_from_str("2023-11-20T11:35:03+00:00[Europe/London]", Gregorian, IanaParser::new(), VariantOffsetsCalculator::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, 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 #[allow(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 #[allow(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 #[allow(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, 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 #[allow(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 #[allow(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 #[allow(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, VariantOffsetsCalculator};
1590 /// use writeable::assert_try_writeable_eq;
1591 ///
1592 /// let mut zone_london_winter = ZonedDateTime::try_full_from_str(
1593 /// "2024-01-01T00:00:00+00:00[Europe/London]",
1594 /// Gregorian,
1595 /// IanaParser::new(),
1596 /// VariantOffsetsCalculator::new(),
1597 /// )
1598 /// .unwrap()
1599 /// .zone;
1600 /// let mut zone_london_summer = ZonedDateTime::try_full_from_str(
1601 /// "2024-07-01T00:00:00+01:00[Europe/London]",
1602 /// Gregorian,
1603 /// IanaParser::new(),
1604 /// VariantOffsetsCalculator::new(),
1605 /// )
1606 /// .unwrap()
1607 /// .zone;
1608 ///
1609 /// let mut names =
1610 /// FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
1611 /// locale!("en-GB").into(),
1612 /// )
1613 /// .unwrap();
1614 ///
1615 /// names.include_time_zone_essentials().unwrap();
1616 ///
1617 /// // Create a pattern with symbol `OOOO`:
1618 /// let pattern_str = "'Your time zone is:' OOOO";
1619 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1620 ///
1621 /// assert_try_writeable_eq!(
1622 /// names
1623 /// .with_pattern_unchecked(&pattern)
1624 /// .format(&zone_london_winter),
1625 /// "Your time zone is: GMT+00:00",
1626 /// );
1627 /// assert_try_writeable_eq!(
1628 /// names
1629 /// .with_pattern_unchecked(&pattern)
1630 /// .format(&zone_london_summer),
1631 /// "Your time zone is: GMT+01:00",
1632 /// );
1633 ///
1634 /// // Now try `V`:
1635 /// let pattern_str = "'Your time zone is:' V";
1636 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1637 ///
1638 /// assert_try_writeable_eq!(
1639 /// names
1640 /// .with_pattern_unchecked(&pattern)
1641 /// .format(&zone_london_winter),
1642 /// "Your time zone is: gblon",
1643 /// );
1644 ///
1645 /// // Now try `Z`:
1646 /// let pattern_str = "'Your time zone is:' Z";
1647 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1648 ///
1649 /// assert_try_writeable_eq!(
1650 /// names
1651 /// .with_pattern_unchecked(&pattern)
1652 /// .format(&zone_london_winter),
1653 /// "Your time zone is: +0000",
1654 /// );
1655 ///
1656 /// // Now try `ZZZZZ`:
1657 /// let pattern_str = "'Your time zone is:' ZZZZZ";
1658 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1659 ///
1660 /// assert_try_writeable_eq!(
1661 /// names
1662 /// .with_pattern_unchecked(&pattern)
1663 /// .format(&zone_london_winter),
1664 /// "Your time zone is: Z",
1665 /// );
1666 /// assert_try_writeable_eq!(
1667 /// names
1668 /// .with_pattern_unchecked(&pattern)
1669 /// .format(&zone_london_summer),
1670 /// "Your time zone is: +01:00",
1671 /// );
1672 /// ```
1673 #[cfg(feature = "compiled_data")]
1674 pub fn include_time_zone_essentials(&mut self) -> Result<&mut Self, PatternLoadError> {
1675 self.load_time_zone_essentials(&crate::provider::Baked)
1676 }
1677
1678 /// Loads location names for time zone formatting.
1679 pub fn load_time_zone_location_names<P>(
1680 &mut self,
1681 provider: &P,
1682 ) -> Result<&mut Self, PatternLoadError>
1683 where
1684 P: DataProvider<tz::LocationsOverrideV1> + DataProvider<tz::LocationsRootV1> + ?Sized,
1685 {
1686 self.inner.load_time_zone_location_names(
1687 &tz::LocationsOverrideV1::bind(provider),
1688 &tz::LocationsRootV1::bind(provider),
1689 self.prefs,
1690 )?;
1691 Ok(self)
1692 }
1693
1694 /// Includes location names for time zone formatting with compiled data.
1695 ///
1696 /// Important: When performing manual time zone data loading, in addition to the
1697 /// specific time zone format data, also call either:
1698 ///
1699 /// - [`FixedCalendarDateTimeNames::include_time_zone_essentials`]
1700 /// - [`FixedCalendarDateTimeNames::load_time_zone_essentials`]
1701 ///
1702 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
1703 ///
1704 /// # Examples
1705 ///
1706 /// ```
1707 /// use icu::calendar::Gregorian;
1708 /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
1709 /// use icu::datetime::input::ZonedDateTime;
1710 /// use icu::datetime::pattern::DateTimePattern;
1711 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1712 /// use icu::locale::locale;
1713 /// use icu::time::zone::{IanaParser, VariantOffsetsCalculator};
1714 /// use writeable::assert_try_writeable_eq;
1715 ///
1716 /// let mut zone_london_winter = ZonedDateTime::try_full_from_str(
1717 /// "2024-01-01T00:00:00+00:00[Europe/London]",
1718 /// Gregorian,
1719 /// IanaParser::new(),
1720 /// VariantOffsetsCalculator::new(),
1721 /// )
1722 /// .unwrap()
1723 /// .zone;
1724 ///
1725 /// let mut names =
1726 /// FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
1727 /// locale!("en-GB").into(),
1728 /// )
1729 /// .unwrap();
1730 ///
1731 /// names.include_time_zone_essentials().unwrap();
1732 /// names.include_time_zone_location_names().unwrap();
1733 ///
1734 /// // Try `VVVV`:
1735 /// let pattern_str = "'Your time zone is:' VVVV";
1736 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1737 ///
1738 /// assert_try_writeable_eq!(
1739 /// names
1740 /// .with_pattern_unchecked(&pattern)
1741 /// .format(&zone_london_winter),
1742 /// "Your time zone is: UK Time",
1743 /// );
1744 /// ```
1745 #[cfg(feature = "compiled_data")]
1746 pub fn include_time_zone_location_names(&mut self) -> Result<&mut Self, PatternLoadError> {
1747 self.load_time_zone_location_names(&crate::provider::Baked)
1748 }
1749
1750 /// Loads exemplar city names for time zone formatting.
1751 pub fn load_time_zone_exemplar_city_names<P>(
1752 &mut self,
1753 provider: &P,
1754 ) -> Result<&mut Self, PatternLoadError>
1755 where
1756 P: DataProvider<tz::CitiesOverrideV1> + DataProvider<tz::CitiesRootV1> + ?Sized,
1757 {
1758 self.inner.load_time_zone_exemplar_city_names(
1759 &tz::CitiesOverrideV1::bind(provider),
1760 &tz::CitiesRootV1::bind(provider),
1761 self.prefs,
1762 )?;
1763 Ok(self)
1764 }
1765
1766 /// Includes exemplar city names for time zone formatting with compiled data.
1767 ///
1768 /// Important: The `VVV` format requires location data in addition to exemplar
1769 /// city data. Also call either:
1770 ///
1771 /// - [`FixedCalendarDateTimeNames::include_time_zone_location_names`]
1772 /// - [`FixedCalendarDateTimeNames::load_time_zone_location_names`]
1773 ///
1774 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
1775 ///
1776 /// # Examples
1777 ///
1778 /// ```
1779 /// use icu::calendar::Gregorian;
1780 /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
1781 /// use icu::datetime::input::ZonedDateTime;
1782 /// use icu::datetime::pattern::DateTimePattern;
1783 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1784 /// use icu::locale::locale;
1785 /// use icu::time::zone::{IanaParser, VariantOffsetsCalculator};
1786 /// use writeable::assert_try_writeable_eq;
1787 ///
1788 /// let mut zone_london_winter = ZonedDateTime::try_full_from_str(
1789 /// "2024-01-01T00:00:00+00:00[Europe/London]",
1790 /// Gregorian,
1791 /// IanaParser::new(),
1792 /// VariantOffsetsCalculator::new(),
1793 /// )
1794 /// .unwrap()
1795 /// .zone;
1796 ///
1797 /// let mut names =
1798 /// FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
1799 /// locale!("en-GB").into(),
1800 /// )
1801 /// .unwrap();
1802 ///
1803 /// names.include_time_zone_location_names().unwrap();
1804 /// names.include_time_zone_exemplar_city_names().unwrap();
1805 ///
1806 /// // Try `VVVV`:
1807 /// let pattern_str = "'Your time zone is:' VVV";
1808 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1809 ///
1810 /// assert_try_writeable_eq!(
1811 /// names
1812 /// .with_pattern_unchecked(&pattern)
1813 /// .format(&zone_london_winter),
1814 /// "Your time zone is: London",
1815 /// );
1816 /// ```
1817 #[cfg(feature = "compiled_data")]
1818 pub fn include_time_zone_exemplar_city_names(&mut self) -> Result<&mut Self, PatternLoadError> {
1819 self.load_time_zone_exemplar_city_names(&crate::provider::Baked)
1820 }
1821
1822 /// Loads generic non-location long time zone names.
1823 pub fn load_time_zone_generic_long_names<P>(
1824 &mut self,
1825 provider: &P,
1826 ) -> Result<&mut Self, PatternLoadError>
1827 where
1828 P: DataProvider<tz::MzGenericLongV1>
1829 + DataProvider<tz::MzStandardLongV1>
1830 + DataProvider<tz::MzPeriodV1>
1831 + ?Sized,
1832 {
1833 self.inner.load_time_zone_generic_long_names(
1834 &tz::MzGenericLongV1::bind(provider),
1835 &tz::MzStandardLongV1::bind(provider),
1836 &tz::MzPeriodV1::bind(provider),
1837 self.prefs,
1838 &mut self.metadata,
1839 )?;
1840 Ok(self)
1841 }
1842
1843 /// Includes generic non-location long time zone names with compiled data.
1844 ///
1845 /// Important: When performing manual time zone data loading, in addition to the
1846 /// specific time zone format data, also call either:
1847 ///
1848 /// - [`FixedCalendarDateTimeNames::include_time_zone_essentials`]
1849 /// - [`FixedCalendarDateTimeNames::load_time_zone_essentials`]
1850 ///
1851 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
1852 ///
1853 /// # Examples
1854 ///
1855 /// ```
1856 /// use icu::calendar::Gregorian;
1857 /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
1858 /// use icu::datetime::input::ZonedDateTime;
1859 /// use icu::datetime::pattern::DateTimePattern;
1860 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1861 /// use icu::locale::locale;
1862 /// use icu::time::zone::{IanaParser, VariantOffsetsCalculator};
1863 /// use writeable::assert_try_writeable_eq;
1864 ///
1865 /// let mut zone_london_winter = ZonedDateTime::try_full_from_str(
1866 /// "2024-01-01T00:00:00+00:00[Europe/London]",
1867 /// Gregorian,
1868 /// IanaParser::new(),
1869 /// VariantOffsetsCalculator::new(),
1870 /// )
1871 /// .unwrap()
1872 /// .zone;
1873 /// let mut zone_london_summer = ZonedDateTime::try_full_from_str(
1874 /// "2024-07-01T00:00:00+01:00[Europe/London]",
1875 /// Gregorian,
1876 /// IanaParser::new(),
1877 /// VariantOffsetsCalculator::new(),
1878 /// )
1879 /// .unwrap()
1880 /// .zone;
1881 ///
1882 /// let mut names =
1883 /// FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
1884 /// locale!("en-GB").into(),
1885 /// )
1886 /// .unwrap();
1887 ///
1888 /// names.include_time_zone_essentials().unwrap();
1889 /// names.include_time_zone_generic_long_names().unwrap();
1890 ///
1891 /// // Create a pattern with symbol `vvvv`:
1892 /// let pattern_str = "'Your time zone is:' vvvv";
1893 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1894 ///
1895 /// assert_try_writeable_eq!(
1896 /// names
1897 /// .with_pattern_unchecked(&pattern)
1898 /// .format(&zone_london_winter),
1899 /// "Your time zone is: Greenwich Mean Time",
1900 /// );
1901 /// assert_try_writeable_eq!(
1902 /// names
1903 /// .with_pattern_unchecked(&pattern)
1904 /// .format(&zone_london_summer),
1905 /// // Note: The year-round generic name of this zone is Greenwich
1906 /// // Mean Time, which may be confusing since the zone observes
1907 /// // daylight savings time. See:
1908 /// // <https://unicode-org.atlassian.net/issues/CLDR-18378>
1909 /// "Your time zone is: Greenwich Mean Time",
1910 /// );
1911 /// ```
1912 #[cfg(feature = "compiled_data")]
1913 pub fn include_time_zone_generic_long_names(&mut self) -> Result<&mut Self, PatternLoadError> {
1914 self.load_time_zone_generic_long_names(&crate::provider::Baked)
1915 }
1916
1917 /// Loads generic non-location short time zone names.
1918 pub fn load_time_zone_generic_short_names<P>(
1919 &mut self,
1920 provider: &P,
1921 ) -> Result<&mut Self, PatternLoadError>
1922 where
1923 P: DataProvider<tz::MzGenericShortV1> + DataProvider<tz::MzPeriodV1> + ?Sized,
1924 {
1925 self.inner.load_time_zone_generic_short_names(
1926 &tz::MzGenericShortV1::bind(provider),
1927 &tz::MzPeriodV1::bind(provider),
1928 self.prefs,
1929 &mut self.metadata,
1930 )?;
1931 Ok(self)
1932 }
1933
1934 /// Includes generic non-location short time zone names with compiled data.
1935 ///
1936 /// Important: When performing manual time zone data loading, in addition to the
1937 /// specific time zone format data, also call either:
1938 ///
1939 /// - [`FixedCalendarDateTimeNames::include_time_zone_essentials`]
1940 /// - [`FixedCalendarDateTimeNames::load_time_zone_essentials`]
1941 ///
1942 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
1943 ///
1944 /// # Examples
1945 ///
1946 /// ```
1947 /// use icu::calendar::Gregorian;
1948 /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
1949 /// use icu::datetime::input::ZonedDateTime;
1950 /// use icu::datetime::pattern::DateTimePattern;
1951 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1952 /// use icu::locale::locale;
1953 /// use icu::time::zone::{IanaParser, VariantOffsetsCalculator};
1954 /// use writeable::assert_try_writeable_eq;
1955 ///
1956 /// let mut zone_london_winter = ZonedDateTime::try_full_from_str(
1957 /// "2024-01-01T00:00:00+00:00[Europe/London]",
1958 /// Gregorian,
1959 /// IanaParser::new(),
1960 /// VariantOffsetsCalculator::new(),
1961 /// )
1962 /// .unwrap()
1963 /// .zone;
1964 /// let mut zone_london_summer = ZonedDateTime::try_full_from_str(
1965 /// "2024-07-01T00:00:00+01:00[Europe/London]",
1966 /// Gregorian,
1967 /// IanaParser::new(),
1968 /// VariantOffsetsCalculator::new(),
1969 /// )
1970 /// .unwrap()
1971 /// .zone;
1972 ///
1973 /// let mut names =
1974 /// FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
1975 /// locale!("en-GB").into(),
1976 /// )
1977 /// .unwrap();
1978 ///
1979 /// names.include_time_zone_essentials().unwrap();
1980 /// names.include_time_zone_generic_short_names().unwrap();
1981 ///
1982 /// // Create a pattern with symbol `v`:
1983 /// let pattern_str = "'Your time zone is:' v";
1984 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1985 ///
1986 /// assert_try_writeable_eq!(
1987 /// names
1988 /// .with_pattern_unchecked(&pattern)
1989 /// .format(&zone_london_winter),
1990 /// "Your time zone is: GMT",
1991 /// );
1992 /// assert_try_writeable_eq!(
1993 /// names
1994 /// .with_pattern_unchecked(&pattern)
1995 /// .format(&zone_london_summer),
1996 /// // Note: The year-round generic name of this zone is Greenwich
1997 /// // Mean Time, which may be confusing since the zone observes
1998 /// // daylight savings time. See:
1999 /// // <https://unicode-org.atlassian.net/issues/CLDR-18378>
2000 /// "Your time zone is: GMT",
2001 /// );
2002 /// ```
2003 #[cfg(feature = "compiled_data")]
2004 pub fn include_time_zone_generic_short_names(&mut self) -> Result<&mut Self, PatternLoadError> {
2005 self.load_time_zone_generic_short_names(&crate::provider::Baked)
2006 }
2007
2008 /// Loads specific non-location long time zone names.
2009 pub fn load_time_zone_specific_long_names<P>(
2010 &mut self,
2011 provider: &P,
2012 ) -> Result<&mut Self, PatternLoadError>
2013 where
2014 P: DataProvider<tz::MzSpecificLongV1>
2015 + DataProvider<tz::MzStandardLongV1>
2016 + DataProvider<tz::MzPeriodV1>
2017 + ?Sized,
2018 {
2019 self.inner.load_time_zone_specific_long_names(
2020 &tz::MzSpecificLongV1::bind(provider),
2021 &tz::MzStandardLongV1::bind(provider),
2022 &tz::MzPeriodV1::bind(provider),
2023 self.prefs,
2024 &mut self.metadata,
2025 )?;
2026 Ok(self)
2027 }
2028
2029 /// Includes specific non-location long time zone names with compiled data.
2030 ///
2031 /// Important: When performing manual time zone data loading, in addition to the
2032 /// specific time zone format data, also call either:
2033 ///
2034 /// - [`FixedCalendarDateTimeNames::include_time_zone_essentials`]
2035 /// - [`FixedCalendarDateTimeNames::load_time_zone_essentials`]
2036 ///
2037 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2038 ///
2039 /// # Examples
2040 ///
2041 /// ```
2042 /// use icu::calendar::Gregorian;
2043 /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
2044 /// use icu::datetime::input::ZonedDateTime;
2045 /// use icu::datetime::pattern::DateTimePattern;
2046 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
2047 /// use icu::locale::locale;
2048 /// use icu::time::zone::{IanaParser, VariantOffsetsCalculator};
2049 /// use writeable::assert_try_writeable_eq;
2050 ///
2051 /// let mut zone_london_winter = ZonedDateTime::try_full_from_str(
2052 /// "2024-01-01T00:00:00+00:00[Europe/London]",
2053 /// Gregorian,
2054 /// IanaParser::new(),
2055 /// VariantOffsetsCalculator::new(),
2056 /// )
2057 /// .unwrap()
2058 /// .zone;
2059 /// let mut zone_london_summer = ZonedDateTime::try_full_from_str(
2060 /// "2024-07-01T00:00:00+01:00[Europe/London]",
2061 /// Gregorian,
2062 /// IanaParser::new(),
2063 /// VariantOffsetsCalculator::new(),
2064 /// )
2065 /// .unwrap()
2066 /// .zone;
2067 ///
2068 /// let mut names =
2069 /// FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
2070 /// locale!("en-GB").into(),
2071 /// )
2072 /// .unwrap();
2073 ///
2074 /// names.include_time_zone_essentials().unwrap();
2075 /// names.include_time_zone_specific_long_names().unwrap();
2076 ///
2077 /// // Create a pattern with symbol `zzzz`:
2078 /// let pattern_str = "'Your time zone is:' zzzz";
2079 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
2080 ///
2081 /// assert_try_writeable_eq!(
2082 /// names
2083 /// .with_pattern_unchecked(&pattern)
2084 /// .format(&zone_london_winter),
2085 /// "Your time zone is: Greenwich Mean Time",
2086 /// );
2087 /// assert_try_writeable_eq!(
2088 /// names
2089 /// .with_pattern_unchecked(&pattern)
2090 /// .format(&zone_london_summer),
2091 /// "Your time zone is: British Summer Time",
2092 /// );
2093 /// ```
2094 #[cfg(feature = "compiled_data")]
2095 pub fn include_time_zone_specific_long_names(&mut self) -> Result<&mut Self, PatternLoadError> {
2096 self.load_time_zone_specific_long_names(&crate::provider::Baked)
2097 }
2098
2099 /// Loads specific non-location short time zone names.
2100 pub fn load_time_zone_specific_short_names<P>(
2101 &mut self,
2102 provider: &P,
2103 ) -> Result<&mut Self, PatternLoadError>
2104 where
2105 P: DataProvider<tz::MzSpecificShortV1> + DataProvider<tz::MzPeriodV1> + ?Sized,
2106 {
2107 self.inner.load_time_zone_specific_short_names(
2108 &tz::MzSpecificShortV1::bind(provider),
2109 &tz::MzPeriodV1::bind(provider),
2110 self.prefs,
2111 &mut self.metadata,
2112 )?;
2113 Ok(self)
2114 }
2115
2116 /// Includes specific non-location short time zone names with compiled data.
2117 ///
2118 /// Important: When performing manual time zone data loading, in addition to the
2119 /// specific time zone format data, also call either:
2120 ///
2121 /// - [`FixedCalendarDateTimeNames::include_time_zone_essentials`]
2122 /// - [`FixedCalendarDateTimeNames::load_time_zone_essentials`]
2123 ///
2124 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2125 ///
2126 /// # Examples
2127 ///
2128 /// ```
2129 /// use icu::calendar::Gregorian;
2130 /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
2131 /// use icu::datetime::input::ZonedDateTime;
2132 /// use icu::datetime::pattern::DateTimePattern;
2133 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
2134 /// use icu::locale::locale;
2135 /// use icu::time::zone::{IanaParser, VariantOffsetsCalculator};
2136 /// use writeable::assert_try_writeable_eq;
2137 ///
2138 /// let mut zone_london_winter = ZonedDateTime::try_full_from_str(
2139 /// "2024-01-01T00:00:00+00:00[Europe/London]",
2140 /// Gregorian,
2141 /// IanaParser::new(),
2142 /// VariantOffsetsCalculator::new(),
2143 /// )
2144 /// .unwrap()
2145 /// .zone;
2146 /// let mut zone_london_summer = ZonedDateTime::try_full_from_str(
2147 /// "2024-07-01T00:00:00+01:00[Europe/London]",
2148 /// Gregorian,
2149 /// IanaParser::new(),
2150 /// VariantOffsetsCalculator::new(),
2151 /// )
2152 /// .unwrap()
2153 /// .zone;
2154 ///
2155 /// let mut names =
2156 /// FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
2157 /// locale!("en-GB").into(),
2158 /// )
2159 /// .unwrap();
2160 ///
2161 /// names.include_time_zone_essentials().unwrap();
2162 /// names.include_time_zone_specific_short_names().unwrap();
2163 ///
2164 /// // Create a pattern with symbol `z`:
2165 /// let pattern_str = "'Your time zone is:' z";
2166 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
2167 ///
2168 /// assert_try_writeable_eq!(
2169 /// names
2170 /// .with_pattern_unchecked(&pattern)
2171 /// .format(&zone_london_winter),
2172 /// "Your time zone is: GMT",
2173 /// );
2174 /// assert_try_writeable_eq!(
2175 /// names
2176 /// .with_pattern_unchecked(&pattern)
2177 /// .format(&zone_london_summer),
2178 /// "Your time zone is: BST",
2179 /// );
2180 /// ```
2181 #[cfg(feature = "compiled_data")]
2182 pub fn include_time_zone_specific_short_names(
2183 &mut self,
2184 ) -> Result<&mut Self, PatternLoadError> {
2185 self.load_time_zone_specific_short_names(&crate::provider::Baked)
2186 }
2187
2188 /// Loads generic non-location short time zone names
2189 /// and all data required for its fallback formats.
2190 ///
2191 /// See [`GenericShort`](crate::fieldsets::zone::GenericShort)
2192 pub fn load_time_zone_generic_short_names_with_fallback<P>(
2193 &mut self,
2194 provider: &P,
2195 ) -> Result<&mut Self, PatternLoadError>
2196 where
2197 P: DataProvider<DecimalSymbolsV1>
2198 + DataProvider<DecimalDigitsV1>
2199 + DataProvider<tz::EssentialsV1>
2200 + DataProvider<tz::LocationsOverrideV1>
2201 + DataProvider<tz::LocationsRootV1>
2202 + DataProvider<tz::MzGenericShortV1>
2203 + DataProvider<tz::MzPeriodV1>
2204 + ?Sized,
2205 {
2206 let error_field = self.inner.load_time_zone_field_v_except_decimals(
2207 &tz::EssentialsV1::bind(provider),
2208 &tz::LocationsOverrideV1::bind(provider),
2209 &tz::LocationsRootV1::bind(provider),
2210 &tz::MzGenericShortV1::bind(provider),
2211 &tz::MzPeriodV1::bind(provider),
2212 self.prefs,
2213 &mut self.metadata,
2214 )?;
2215 self.load_decimal_formatter(provider)
2216 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2217 Ok(self)
2218 }
2219
2220 /// Includes generic non-location short time zone names
2221 /// and all data required for its fallback formats, with compiled data.
2222 ///
2223 /// See [`GenericShort`](crate::fieldsets::zone::GenericShort)
2224 ///
2225 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2226 #[cfg(feature = "compiled_data")]
2227 pub fn include_time_zone_generic_short_names_with_fallback(
2228 &mut self,
2229 ) -> Result<&mut Self, PatternLoadError> {
2230 let error_field = self.inner.load_time_zone_field_v_except_decimals(
2231 &tz::EssentialsV1::bind(&crate::provider::Baked),
2232 &tz::LocationsOverrideV1::bind(&crate::provider::Baked),
2233 &tz::LocationsRootV1::bind(&crate::provider::Baked),
2234 &tz::MzGenericShortV1::bind(&crate::provider::Baked),
2235 &tz::MzPeriodV1::bind(&crate::provider::Baked),
2236 self.prefs,
2237 &mut self.metadata,
2238 )?;
2239 self.include_decimal_formatter()
2240 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2241 Ok(self)
2242 }
2243
2244 /// Loads generic non-location long time zone names
2245 /// and all data required for its fallback formats.
2246 ///
2247 /// See [`GenericLong`](crate::fieldsets::zone::GenericLong)
2248 pub fn load_time_zone_generic_long_names_with_fallback<P>(
2249 &mut self,
2250 provider: &P,
2251 ) -> Result<&mut Self, PatternLoadError>
2252 where
2253 P: DataProvider<DecimalSymbolsV1>
2254 + DataProvider<DecimalDigitsV1>
2255 + DataProvider<tz::EssentialsV1>
2256 + DataProvider<tz::LocationsOverrideV1>
2257 + DataProvider<tz::LocationsRootV1>
2258 + DataProvider<tz::MzGenericLongV1>
2259 + DataProvider<tz::MzStandardLongV1>
2260 + DataProvider<tz::MzPeriodV1>
2261 + ?Sized,
2262 {
2263 let error_field = self.inner.load_time_zone_field_vvvv_except_decimals(
2264 &tz::EssentialsV1::bind(provider),
2265 &tz::LocationsOverrideV1::bind(provider),
2266 &tz::LocationsRootV1::bind(provider),
2267 &tz::MzGenericLongV1::bind(provider),
2268 &tz::MzStandardLongV1::bind(provider),
2269 &tz::MzPeriodV1::bind(provider),
2270 self.prefs,
2271 &mut self.metadata,
2272 )?;
2273 self.load_decimal_formatter(provider)
2274 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2275 Ok(self)
2276 }
2277
2278 /// Includes generic non-location long time zone names
2279 /// and all data required for its fallback formats, with compiled data.
2280 ///
2281 /// See [`GenericLong`](crate::fieldsets::zone::GenericLong)
2282 ///
2283 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2284 #[cfg(feature = "compiled_data")]
2285 pub fn include_time_zone_generic_long_names_with_fallback(
2286 &mut self,
2287 ) -> Result<&mut Self, PatternLoadError> {
2288 let error_field = self.inner.load_time_zone_field_vvvv_except_decimals(
2289 &tz::EssentialsV1::bind(&crate::provider::Baked),
2290 &tz::LocationsOverrideV1::bind(&crate::provider::Baked),
2291 &tz::LocationsRootV1::bind(&crate::provider::Baked),
2292 &tz::MzGenericLongV1::bind(&crate::provider::Baked),
2293 &tz::MzStandardLongV1::bind(&crate::provider::Baked),
2294 &tz::MzPeriodV1::bind(&crate::provider::Baked),
2295 self.prefs,
2296 &mut self.metadata,
2297 )?;
2298 self.include_decimal_formatter()
2299 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2300 Ok(self)
2301 }
2302
2303 /// Loads specific non-location short time zone names
2304 /// and all data required for its fallback formats
2305 /// except for decimal formatting.
2306 ///
2307 /// See [`SpecificShort`](crate::fieldsets::zone::SpecificShort)
2308 pub fn load_time_zone_specific_short_names_with_fallback<P>(
2309 &mut self,
2310 provider: &P,
2311 ) -> Result<&mut Self, PatternLoadError>
2312 where
2313 P: DataProvider<DecimalSymbolsV1>
2314 + DataProvider<DecimalDigitsV1>
2315 + DataProvider<tz::EssentialsV1>
2316 + DataProvider<tz::LocationsOverrideV1>
2317 + DataProvider<tz::LocationsRootV1>
2318 + DataProvider<tz::MzSpecificShortV1>
2319 + DataProvider<tz::MzPeriodV1>
2320 + ?Sized,
2321 {
2322 let error_field = self.inner.load_time_zone_field_z_except_decimals(
2323 &tz::EssentialsV1::bind(provider),
2324 &tz::MzSpecificShortV1::bind(provider),
2325 &tz::MzPeriodV1::bind(provider),
2326 self.prefs,
2327 &mut self.metadata,
2328 )?;
2329 self.load_decimal_formatter(provider)
2330 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2331 Ok(self)
2332 }
2333
2334 /// Includes specific non-location short time zone names
2335 /// and all data required for its fallback formats
2336 /// except for decimal formatting, with compiled data.
2337 ///
2338 /// See [`SpecificShort`](crate::fieldsets::zone::SpecificShort)
2339 ///
2340 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2341 #[cfg(feature = "compiled_data")]
2342 pub fn include_time_zone_specific_short_names_with_fallback(
2343 &mut self,
2344 ) -> Result<&mut Self, PatternLoadError> {
2345 let error_field = self.inner.load_time_zone_field_z_except_decimals(
2346 &tz::EssentialsV1::bind(&crate::provider::Baked),
2347 &tz::MzSpecificShortV1::bind(&crate::provider::Baked),
2348 &tz::MzPeriodV1::bind(&crate::provider::Baked),
2349 self.prefs,
2350 &mut self.metadata,
2351 )?;
2352 self.include_decimal_formatter()
2353 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2354 Ok(self)
2355 }
2356
2357 /// Loads specific non-location long time zone names
2358 /// and all data required for its fallback formats
2359 /// except for decimal formatting.
2360 ///
2361 /// See [`SpecificLong`](crate::fieldsets::zone::SpecificLong)
2362 pub fn load_time_zone_specific_long_names_with_fallback<P>(
2363 &mut self,
2364 provider: &P,
2365 ) -> Result<&mut Self, PatternLoadError>
2366 where
2367 P: DataProvider<DecimalSymbolsV1>
2368 + DataProvider<DecimalDigitsV1>
2369 + DataProvider<tz::EssentialsV1>
2370 + DataProvider<tz::LocationsOverrideV1>
2371 + DataProvider<tz::LocationsRootV1>
2372 + DataProvider<tz::MzSpecificLongV1>
2373 + DataProvider<tz::MzStandardLongV1>
2374 + DataProvider<tz::MzPeriodV1>
2375 + ?Sized,
2376 {
2377 let error_field = self.inner.load_time_zone_field_zzzz_except_decimals(
2378 &tz::EssentialsV1::bind(provider),
2379 &tz::LocationsOverrideV1::bind(provider),
2380 &tz::LocationsRootV1::bind(provider),
2381 &tz::MzStandardLongV1::bind(provider),
2382 &tz::MzSpecificLongV1::bind(provider),
2383 &tz::MzPeriodV1::bind(provider),
2384 self.prefs,
2385 &mut self.metadata,
2386 )?;
2387 self.load_decimal_formatter(provider)
2388 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2389 Ok(self)
2390 }
2391
2392 /// Includes specific non-location long time zone names
2393 /// and all data required for its fallback formats
2394 /// except for decimal formatting, with compiled data.
2395 ///
2396 /// See [`SpecificLong`](crate::fieldsets::zone::SpecificLong)
2397 ///
2398 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2399 #[cfg(feature = "compiled_data")]
2400 pub fn include_time_zone_specific_long_names_with_fallback(
2401 &mut self,
2402 ) -> Result<&mut Self, PatternLoadError> {
2403 let error_field = self.inner.load_time_zone_field_zzzz_except_decimals(
2404 &tz::EssentialsV1::bind(&crate::provider::Baked),
2405 &tz::LocationsOverrideV1::bind(&crate::provider::Baked),
2406 &tz::LocationsRootV1::bind(&crate::provider::Baked),
2407 &tz::MzStandardLongV1::bind(&crate::provider::Baked),
2408 &tz::MzSpecificLongV1::bind(&crate::provider::Baked),
2409 &tz::MzPeriodV1::bind(&crate::provider::Baked),
2410 self.prefs,
2411 &mut self.metadata,
2412 )?;
2413 self.include_decimal_formatter()
2414 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2415 Ok(self)
2416 }
2417
2418 /// Loads all data for short and long localized offset time zone formatting
2419 /// except for decimal formatting.
2420 ///
2421 /// See:
2422 ///
2423 /// - [`LocalizedOffsetShort`](crate::fieldsets::zone::LocalizedOffsetShort)
2424 /// - [`LocalizedOffsetLong`](crate::fieldsets::zone::LocalizedOffsetLong)
2425 pub fn load_time_zone_localized_offset_names_with_fallback<P>(
2426 &mut self,
2427 provider: &P,
2428 ) -> Result<&mut Self, PatternLoadError>
2429 where
2430 P: DataProvider<DecimalSymbolsV1>
2431 + DataProvider<DecimalDigitsV1>
2432 + DataProvider<tz::EssentialsV1>
2433 + ?Sized,
2434 {
2435 let error_field = self.inner.load_time_zone_field_O_except_decimals(
2436 &tz::EssentialsV1::bind(provider),
2437 self.prefs,
2438 )?;
2439 self.load_decimal_formatter(provider)
2440 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2441 Ok(self)
2442 }
2443
2444 /// Includes all data for short and long localized offset time zone formatting
2445 /// except for decimal formatting, with compiled data.
2446 ///
2447 /// See:
2448 ///
2449 /// - [`LocalizedOffsetShort`](crate::fieldsets::zone::LocalizedOffsetShort)
2450 /// - [`LocalizedOffsetLong`](crate::fieldsets::zone::LocalizedOffsetLong)
2451 ///
2452 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2453 #[cfg(feature = "compiled_data")]
2454 pub fn include_time_zone_localized_offset_names_with_fallback(
2455 &mut self,
2456 ) -> Result<&mut Self, PatternLoadError> {
2457 let error_field = self.inner.load_time_zone_field_O_except_decimals(
2458 &tz::EssentialsV1::bind(&crate::provider::Baked),
2459 self.prefs,
2460 )?;
2461 self.include_decimal_formatter()
2462 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2463 Ok(self)
2464 }
2465
2466 /// Loads a [`DecimalFormatter`] from a data provider.
2467 #[inline]
2468 pub fn load_decimal_formatter<P>(&mut self, provider: &P) -> Result<&mut Self, DataError>
2469 where
2470 P: DataProvider<DecimalSymbolsV1> + DataProvider<DecimalDigitsV1> + ?Sized,
2471 {
2472 self.inner
2473 .load_decimal_formatter(&ExternalLoaderUnstable(provider), self.prefs)?;
2474 Ok(self)
2475 }
2476
2477 /// Loads a [`DecimalFormatter`] with compiled data.
2478 ///
2479 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2480 ///
2481 /// # Examples
2482 ///
2483 /// ```
2484 /// use icu::datetime::fieldsets::enums::TimeFieldSet;
2485 /// use icu::datetime::input::Time;
2486 /// use icu::datetime::pattern::DateTimePattern;
2487 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
2488 /// use icu::locale::locale;
2489 /// use writeable::assert_try_writeable_eq;
2490 ///
2491 /// let mut names = FixedCalendarDateTimeNames::<(), TimeFieldSet>::try_new(
2492 /// locale!("bn").into(),
2493 /// )
2494 /// .unwrap();
2495 /// names.include_decimal_formatter();
2496 ///
2497 /// // Create a pattern for the time, which is all numbers
2498 /// let pattern_str = "'The current 24-hour time is:' HH:mm";
2499 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
2500 ///
2501 /// let time = Time::try_new(6, 40, 33, 0).unwrap();
2502 ///
2503 /// assert_try_writeable_eq!(
2504 /// names.with_pattern_unchecked(&pattern).format(&time),
2505 /// "The current 24-hour time is: ০৬:৪০",
2506 /// );
2507 /// ```
2508 #[cfg(feature = "compiled_data")]
2509 #[inline]
2510 pub fn include_decimal_formatter(&mut self) -> Result<&mut Self, DataError> {
2511 self.inner
2512 .load_decimal_formatter(&ExternalLoaderCompiledData, self.prefs)?;
2513 Ok(self)
2514 }
2515}
2516
2517impl<C: CldrCalendar, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
2518 /// Associates this [`FixedCalendarDateTimeNames`] with a pattern
2519 /// without checking that all necessary data is loaded.
2520 ///
2521 /// Use this function if you know at compile time what fields your pattern contains.
2522 #[inline]
2523 pub fn with_pattern_unchecked<'l>(
2524 &'l self,
2525 pattern: &'l DateTimePattern,
2526 ) -> DateTimePatternFormatter<'l, C, FSet> {
2527 DateTimePatternFormatter::new(pattern.as_borrowed(), self.inner.as_borrowed())
2528 }
2529
2530 /// Associates this [`FixedCalendarDateTimeNames`] with a datetime pattern
2531 /// and loads all data required for that pattern.
2532 ///
2533 /// Does not duplicate textual field symbols. See [#4337](https://github.com/unicode-org/icu4x/issues/4337)
2534 pub fn load_for_pattern<'l, P>(
2535 &'l mut self,
2536 provider: &P,
2537 pattern: &'l DateTimePattern,
2538 ) -> Result<DateTimePatternFormatter<'l, C, FSet>, PatternLoadError>
2539 where
2540 P: DataProvider<C::YearNamesV1>
2541 + DataProvider<C::MonthNamesV1>
2542 + DataProvider<WeekdayNamesV1>
2543 + DataProvider<DayPeriodNamesV1>
2544 + DataProvider<tz::EssentialsV1>
2545 + DataProvider<tz::LocationsOverrideV1>
2546 + DataProvider<tz::LocationsRootV1>
2547 + DataProvider<tz::CitiesOverrideV1>
2548 + DataProvider<tz::CitiesRootV1>
2549 + DataProvider<tz::MzGenericLongV1>
2550 + DataProvider<tz::MzGenericShortV1>
2551 + DataProvider<tz::MzStandardLongV1>
2552 + DataProvider<tz::MzSpecificLongV1>
2553 + DataProvider<tz::MzSpecificShortV1>
2554 + DataProvider<tz::MzPeriodV1>
2555 + DataProvider<DecimalSymbolsV1>
2556 + DataProvider<DecimalDigitsV1>
2557 + ?Sized,
2558 {
2559 let locale = self.prefs;
2560 self.inner.load_for_pattern(
2561 &C::YearNamesV1::bind(provider),
2562 &C::MonthNamesV1::bind(provider),
2563 &WeekdayNamesV1::bind(provider),
2564 &DayPeriodNamesV1::bind(provider),
2565 &tz::EssentialsV1::bind(provider),
2566 &tz::LocationsRootV1::bind(provider),
2567 &tz::LocationsOverrideV1::bind(provider),
2568 &tz::CitiesRootV1::bind(provider),
2569 &tz::CitiesOverrideV1::bind(provider),
2570 &tz::MzGenericLongV1::bind(provider),
2571 &tz::MzGenericShortV1::bind(provider),
2572 &tz::MzStandardLongV1::bind(provider),
2573 &tz::MzSpecificLongV1::bind(provider),
2574 &tz::MzSpecificShortV1::bind(provider),
2575 &tz::MzPeriodV1::bind(provider),
2576 &ExternalLoaderUnstable(provider),
2577 locale,
2578 pattern.iter_items(),
2579 &mut self.metadata,
2580 )?;
2581 Ok(DateTimePatternFormatter::new(
2582 pattern.as_borrowed(),
2583 self.inner.as_borrowed(),
2584 ))
2585 }
2586
2587 /// Associates this [`FixedCalendarDateTimeNames`] with a pattern
2588 /// and includes all data required for that pattern, from compiled data.
2589 ///
2590 /// Does not support duplicate textual field symbols. See [#4337](https://github.com/unicode-org/icu4x/issues/4337)
2591 ///
2592 /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2593 ///
2594 /// # Examples
2595 ///
2596 /// ```
2597 /// use icu::calendar::Gregorian;
2598 /// use icu::datetime::input::Date;
2599 /// use icu::datetime::input::{DateTime, Time};
2600 /// use icu::datetime::pattern::DateTimePattern;
2601 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
2602 /// use icu::locale::locale;
2603 /// use writeable::assert_try_writeable_eq;
2604 ///
2605 /// let mut names =
2606 /// FixedCalendarDateTimeNames::<Gregorian>::try_new(locale!("en").into())
2607 /// .unwrap();
2608 ///
2609 /// // Create a pattern from a pattern string:
2610 /// let pattern_str = "MMM d (EEEE) 'of year' y G 'at' h:mm a";
2611 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
2612 ///
2613 /// // Load data for the pattern and format:
2614 /// let datetime = DateTime {
2615 /// date: Date::try_new_gregorian(2023, 12, 5).unwrap(),
2616 /// time: Time::try_new(17, 43, 12, 0).unwrap(),
2617 /// };
2618 /// assert_try_writeable_eq!(
2619 /// names
2620 /// .include_for_pattern(&pattern)
2621 /// .unwrap()
2622 /// .format(&datetime),
2623 /// "Dec 5 (Tuesday) of year 2023 AD at 5:43 PM"
2624 /// );
2625 /// ```
2626 #[cfg(feature = "compiled_data")]
2627 pub fn include_for_pattern<'l>(
2628 &'l mut self,
2629 pattern: &'l DateTimePattern,
2630 ) -> Result<DateTimePatternFormatter<'l, C, FSet>, PatternLoadError>
2631 where
2632 crate::provider::Baked: DataProvider<C::YearNamesV1> + DataProvider<C::MonthNamesV1>,
2633 crate::provider::Baked: DataProvider<C::YearNamesV1> + DataProvider<C::MonthNamesV1>,
2634 {
2635 let locale = self.prefs;
2636 self.inner.load_for_pattern(
2637 &C::YearNamesV1::bind(&crate::provider::Baked),
2638 &C::MonthNamesV1::bind(&crate::provider::Baked),
2639 &WeekdayNamesV1::bind(&crate::provider::Baked),
2640 &DayPeriodNamesV1::bind(&crate::provider::Baked),
2641 &tz::EssentialsV1::bind(&crate::provider::Baked),
2642 &tz::LocationsOverrideV1::bind(&crate::provider::Baked),
2643 &tz::LocationsRootV1::bind(&crate::provider::Baked),
2644 &tz::CitiesOverrideV1::bind(&crate::provider::Baked),
2645 &tz::CitiesRootV1::bind(&crate::provider::Baked),
2646 &tz::MzGenericLongV1::bind(&crate::provider::Baked),
2647 &tz::MzGenericShortV1::bind(&crate::provider::Baked),
2648 &tz::MzStandardLongV1::bind(&crate::provider::Baked),
2649 &tz::MzSpecificLongV1::bind(&crate::provider::Baked),
2650 &tz::MzSpecificShortV1::bind(&crate::provider::Baked),
2651 &tz::MzPeriodV1::bind(&crate::provider::Baked),
2652 &ExternalLoaderCompiledData,
2653 locale,
2654 pattern.iter_items(),
2655 &mut self.metadata,
2656 )?;
2657 Ok(DateTimePatternFormatter::new(
2658 pattern.as_borrowed(),
2659 self.inner.as_borrowed(),
2660 ))
2661 }
2662}
2663
2664impl<C, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
2665 /// Maps a [`FixedCalendarDateTimeNames`] of a specific `FSet` to a more general `FSet`.
2666 ///
2667 /// For example, this can transform a formatter for [`DateFieldSet`] to one for
2668 /// [`CompositeDateTimeFieldSet`].
2669 ///
2670 /// [`DateFieldSet`]: crate::fieldsets::enums::DateFieldSet
2671 /// [`CompositeDateTimeFieldSet`]: crate::fieldsets::enums::CompositeDateTimeFieldSet
2672 ///
2673 /// # Examples
2674 ///
2675 /// ```
2676 /// use icu::calendar::Gregorian;
2677 /// use icu::datetime::fieldsets::enums::{
2678 /// CompositeDateTimeFieldSet, DateFieldSet,
2679 /// };
2680 /// use icu::datetime::input::Date;
2681 /// use icu::datetime::input::{DateTime, Time};
2682 /// use icu::datetime::pattern::DateTimePattern;
2683 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
2684 /// use icu::datetime::pattern::MonthNameLength;
2685 /// use icu::locale::locale;
2686 /// use writeable::assert_try_writeable_eq;
2687 ///
2688 /// // Create an instance that can format abbreviated month names:
2689 /// let mut names: FixedCalendarDateTimeNames<Gregorian, DateFieldSet> =
2690 /// FixedCalendarDateTimeNames::try_new(locale!("uk").into()).unwrap();
2691 /// names
2692 /// .include_month_names(MonthNameLength::Abbreviated)
2693 /// .unwrap();
2694 ///
2695 /// // Test it with a pattern:
2696 /// let pattern_str = "MMM d y";
2697 /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
2698 /// let datetime = DateTime {
2699 /// date: Date::try_new_gregorian(2023, 11, 20).unwrap(),
2700 /// time: Time::start_of_day(),
2701 /// };
2702 /// assert_try_writeable_eq!(
2703 /// names.with_pattern_unchecked(&pattern).format(&datetime),
2704 /// "лист. 20 2023"
2705 /// );
2706 ///
2707 /// // Convert the field set to `CompositeDateTimeFieldSet`:
2708 /// let composite_names = names.cast_into_fset::<CompositeDateTimeFieldSet>();
2709 ///
2710 /// // It should still work:
2711 /// assert_try_writeable_eq!(
2712 /// composite_names
2713 /// .with_pattern_unchecked(&pattern)
2714 /// .format(&datetime),
2715 /// "лист. 20 2023"
2716 /// );
2717 /// ```
2718 ///
2719 /// Converting into a narrower type is not supported:
2720 ///
2721 /// ```compile_fail,E0277
2722 /// use icu::calendar::Gregorian;
2723 /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
2724 /// use icu::datetime::fieldsets::enums::{DateFieldSet, CompositeDateTimeFieldSet};
2725 ///
2726 /// let composite_names: FixedCalendarDateTimeNames<Gregorian, CompositeDateTimeFieldSet> = todo!();
2727 ///
2728 /// // error[E0277]: the trait bound `(): From<DataPayloadWithVariables<DayPeriodNamesV1, FieldLength>>` is not satisfied
2729 /// let narrow_names = composite_names.cast_into_fset::<DateFieldSet>();
2730 /// ```
2731 pub fn cast_into_fset<FSet2: DateTimeNamesFrom<FSet>>(
2732 self,
2733 ) -> FixedCalendarDateTimeNames<C, FSet2> {
2734 FixedCalendarDateTimeNames {
2735 prefs: self.prefs,
2736 inner: self.inner.cast_into_fset(),
2737 metadata: self.metadata,
2738 _calendar: PhantomData,
2739 }
2740 }
2741}
2742
2743impl<FSet: DateTimeNamesMarker> DateTimeNames<FSet> {
2744 /// Maps a [`FixedCalendarDateTimeNames`] of a specific `FSet` to a more general `FSet`.
2745 ///
2746 /// For example, this can transform a formatter for [`DateFieldSet`] to one for
2747 /// [`CompositeDateTimeFieldSet`].
2748 ///
2749 /// [`DateFieldSet`]: crate::fieldsets::enums::DateFieldSet
2750 /// [`CompositeDateTimeFieldSet`]: crate::fieldsets::enums::CompositeDateTimeFieldSet
2751 pub fn cast_into_fset<FSet2: DateTimeNamesFrom<FSet>>(self) -> DateTimeNames<FSet2> {
2752 DateTimeNames {
2753 inner: self.inner.cast_into_fset(),
2754 calendar: self.calendar,
2755 }
2756 }
2757}
2758
2759impl<FSet: DateTimeNamesMarker> RawDateTimeNames<FSet> {
2760 pub(crate) fn new_without_number_formatting() -> Self {
2761 Self {
2762 year_names: <FSet::YearNames as NamesContainer<
2763 YearNamesV1,
2764 YearNameLength,
2765 >>::Container::new_empty(),
2766 month_names: <FSet::MonthNames as NamesContainer<
2767 MonthNamesV1,
2768 MonthNameLength,
2769 >>::Container::new_empty(),
2770 weekday_names: <FSet::WeekdayNames as NamesContainer<
2771 WeekdayNamesV1,
2772 WeekdayNameLength,
2773 >>::Container::new_empty(),
2774 dayperiod_names: <FSet::DayPeriodNames as NamesContainer<
2775 DayPeriodNamesV1,
2776 DayPeriodNameLength,
2777 >>::Container::new_empty(),
2778 zone_essentials: <FSet::ZoneEssentials as NamesContainer<
2779 tz::EssentialsV1,
2780 (),
2781 >>::Container::new_empty(),
2782 locations_root: <FSet::ZoneLocationsRoot as NamesContainer<
2783 tz::LocationsRootV1,
2784 (),
2785 >>::Container::new_empty(),
2786 locations: <FSet::ZoneLocations as NamesContainer<
2787 tz::LocationsOverrideV1,
2788 (),
2789 >>::Container::new_empty(),
2790 exemplars: <FSet::ZoneExemplars as NamesContainer<
2791 tz::CitiesOverrideV1,
2792 (),
2793 >>::Container::new_empty(),
2794 exemplars_root: <FSet::ZoneExemplarsRoot as NamesContainer<
2795 tz::CitiesRootV1,
2796 (),
2797 >>::Container::new_empty(),
2798 mz_generic_long: <FSet::ZoneGenericLong as NamesContainer<
2799 tz::MzGenericLongV1,
2800 (),
2801 >>::Container::new_empty(),
2802 mz_generic_short: <FSet::ZoneGenericShort as NamesContainer<
2803 tz::MzGenericShortV1,
2804 (),
2805 >>::Container::new_empty(),
2806 mz_standard_long: <FSet::ZoneStandardLong as NamesContainer<
2807 tz::MzStandardLongV1,
2808 (),
2809 >>::Container::new_empty(),
2810 mz_specific_long: <FSet::ZoneSpecificLong as NamesContainer<
2811 tz::MzSpecificLongV1,
2812 (),
2813 >>::Container::new_empty(),
2814 mz_specific_short: <FSet::ZoneSpecificShort as NamesContainer<
2815 tz::MzSpecificShortV1,
2816 (),
2817 >>::Container::new_empty(),
2818 mz_periods: <FSet::MetazoneLookup as NamesContainer<
2819 tz::MzPeriodV1,
2820 (),
2821 >>::Container::new_empty(),
2822 decimal_formatter: None,
2823 _marker: PhantomData,
2824 }
2825 }
2826
2827 pub(crate) fn as_borrowed(&self) -> RawDateTimeNamesBorrowed {
2828 RawDateTimeNamesBorrowed {
2829 year_names: self.year_names.get().inner,
2830 month_names: self.month_names.get().inner,
2831 weekday_names: self.weekday_names.get().inner,
2832 dayperiod_names: self.dayperiod_names.get().inner,
2833 zone_essentials: self.zone_essentials.get().inner,
2834 locations_root: self.locations_root.get().inner,
2835 locations: self.locations.get().inner,
2836 exemplars_root: self.exemplars_root.get().inner,
2837 exemplars: self.exemplars.get().inner,
2838 mz_generic_long: self.mz_generic_long.get().inner,
2839 mz_generic_short: self.mz_generic_short.get().inner,
2840 mz_standard_long: self.mz_standard_long.get().inner,
2841 mz_specific_long: self.mz_specific_long.get().inner,
2842 mz_specific_short: self.mz_specific_short.get().inner,
2843 mz_periods: self.mz_periods.get().inner,
2844 decimal_formatter: self.decimal_formatter.as_ref(),
2845 }
2846 }
2847
2848 pub(crate) fn load_year_names<P>(
2849 &mut self,
2850 provider: &P,
2851 prefs: DateTimeFormatterPreferences,
2852 length: YearNameLength,
2853 error_field: ErrorField,
2854 ) -> Result<(), PatternLoadError>
2855 where
2856 P: BoundDataProvider<YearNamesV1> + ?Sized,
2857 {
2858 let attributes = length.to_attributes();
2859 let locale = provider
2860 .bound_marker()
2861 .make_locale(prefs.locale_preferences);
2862 let req = DataRequest {
2863 id: DataIdentifierBorrowed::for_marker_attributes_and_locale(attributes, &locale),
2864 ..Default::default()
2865 };
2866 self.year_names
2867 .load_put(provider, req, length)
2868 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
2869 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2870 Ok(())
2871 }
2872
2873 pub(crate) fn load_month_names<P>(
2874 &mut self,
2875 provider: &P,
2876 prefs: DateTimeFormatterPreferences,
2877 length: MonthNameLength,
2878 error_field: ErrorField,
2879 ) -> Result<(), PatternLoadError>
2880 where
2881 P: BoundDataProvider<MonthNamesV1> + ?Sized,
2882 {
2883 let attributes = length.to_attributes();
2884 let locale = provider
2885 .bound_marker()
2886 .make_locale(prefs.locale_preferences);
2887 let req = DataRequest {
2888 id: DataIdentifierBorrowed::for_marker_attributes_and_locale(attributes, &locale),
2889 ..Default::default()
2890 };
2891 self.month_names
2892 .load_put(provider, req, length)
2893 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
2894 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2895 Ok(())
2896 }
2897
2898 pub(crate) fn load_day_period_names<P>(
2899 &mut self,
2900 provider: &P,
2901 prefs: DateTimeFormatterPreferences,
2902 length: DayPeriodNameLength,
2903 error_field: ErrorField,
2904 ) -> Result<(), PatternLoadError>
2905 where
2906 P: BoundDataProvider<DayPeriodNamesV1> + ?Sized,
2907 {
2908 let attributes = length.to_attributes();
2909 let locale = provider
2910 .bound_marker()
2911 .make_locale(prefs.locale_preferences);
2912 let req = DataRequest {
2913 id: DataIdentifierBorrowed::for_marker_attributes_and_locale(attributes, &locale),
2914 ..Default::default()
2915 };
2916 self.dayperiod_names
2917 .load_put(provider, req, length)
2918 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
2919 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2920 Ok(())
2921 }
2922
2923 pub(crate) fn load_weekday_names<P>(
2924 &mut self,
2925 provider: &P,
2926 prefs: DateTimeFormatterPreferences,
2927 length: WeekdayNameLength,
2928 error_field: ErrorField,
2929 ) -> Result<(), PatternLoadError>
2930 where
2931 P: BoundDataProvider<WeekdayNamesV1> + ?Sized,
2932 {
2933 let attributes = length.to_attributes();
2934 let locale = provider
2935 .bound_marker()
2936 .make_locale(prefs.locale_preferences);
2937 let req = DataRequest {
2938 id: DataIdentifierBorrowed::for_marker_attributes_and_locale(attributes, &locale),
2939 ..Default::default()
2940 };
2941 self.weekday_names
2942 .load_put(provider, req, length)
2943 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
2944 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2945 Ok(())
2946 }
2947
2948 pub(crate) fn load_time_zone_essentials<P>(
2949 &mut self,
2950 provider: &P,
2951 prefs: DateTimeFormatterPreferences,
2952 ) -> Result<ErrorField, PatternLoadError>
2953 where
2954 P: BoundDataProvider<tz::EssentialsV1> + ?Sized,
2955 {
2956 let locale = provider
2957 .bound_marker()
2958 .make_locale(prefs.locale_preferences);
2959 let error_field = ErrorField(fields::Field {
2960 symbol: FieldSymbol::TimeZone(fields::TimeZone::LocalizedOffset),
2961 length: FieldLength::Four,
2962 });
2963 let variables = ();
2964 let req = DataRequest {
2965 id: DataIdentifierBorrowed::for_locale(&locale),
2966 ..Default::default()
2967 };
2968 self.zone_essentials
2969 .load_put(provider, req, variables)
2970 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
2971 .map_err(|e| PatternLoadError::Data(e, error_field))?;
2972 Ok(error_field)
2973 }
2974
2975 pub(crate) fn load_time_zone_location_names<P, P2>(
2976 &mut self,
2977 provider: &P,
2978 root_provider: &P2,
2979 prefs: DateTimeFormatterPreferences,
2980 ) -> Result<ErrorField, PatternLoadError>
2981 where
2982 P: BoundDataProvider<tz::LocationsOverrideV1> + ?Sized,
2983 P2: BoundDataProvider<tz::LocationsRootV1> + ?Sized,
2984 {
2985 let locale = provider
2986 .bound_marker()
2987 .make_locale(prefs.locale_preferences);
2988 let error_field = ErrorField(fields::Field {
2989 symbol: FieldSymbol::TimeZone(fields::TimeZone::Location),
2990 length: FieldLength::Four,
2991 });
2992 let variables = ();
2993 let req = DataRequest {
2994 id: DataIdentifierBorrowed::for_locale(&locale),
2995 ..Default::default()
2996 };
2997 self.locations_root
2998 .load_put(root_provider, req, variables)
2999 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3000 .map_err(|e| PatternLoadError::Data(e, error_field))?;
3001 self.locations
3002 .load_put(provider, req, variables)
3003 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3004 .map_err(|e| PatternLoadError::Data(e, error_field))?;
3005 Ok(error_field)
3006 }
3007
3008 pub(crate) fn load_time_zone_exemplar_city_names<P, P2>(
3009 &mut self,
3010 provider: &P,
3011 root_provider: &P2,
3012 prefs: DateTimeFormatterPreferences,
3013 ) -> Result<ErrorField, PatternLoadError>
3014 where
3015 P: BoundDataProvider<tz::CitiesOverrideV1> + ?Sized,
3016 P2: BoundDataProvider<tz::CitiesRootV1> + ?Sized,
3017 {
3018 let locale = provider
3019 .bound_marker()
3020 .make_locale(prefs.locale_preferences);
3021 let error_field = ErrorField(fields::Field {
3022 symbol: FieldSymbol::TimeZone(fields::TimeZone::Location),
3023 length: FieldLength::Three,
3024 });
3025 let variables = ();
3026 let req = DataRequest {
3027 id: DataIdentifierBorrowed::for_locale(&locale),
3028 ..Default::default()
3029 };
3030 self.exemplars_root
3031 .load_put(root_provider, req, variables)
3032 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3033 .map_err(|e| PatternLoadError::Data(e, error_field))?;
3034 self.exemplars
3035 .load_put(provider, req, variables)
3036 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3037 .map_err(|e| PatternLoadError::Data(e, error_field))?;
3038 Ok(error_field)
3039 }
3040
3041 pub(crate) fn load_time_zone_generic_long_names(
3042 &mut self,
3043 mz_generic_provider: &(impl BoundDataProvider<tz::MzGenericLongV1> + ?Sized),
3044 mz_standard_provider: &(impl BoundDataProvider<tz::MzStandardLongV1> + ?Sized),
3045 mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3046 prefs: DateTimeFormatterPreferences,
3047 names_metadata: &mut DateTimeNamesMetadata,
3048 ) -> Result<ErrorField, PatternLoadError> {
3049 let locale = mz_generic_provider
3050 .bound_marker()
3051 .make_locale(prefs.locale_preferences);
3052 let error_field = ErrorField(fields::Field {
3053 symbol: FieldSymbol::TimeZone(fields::TimeZone::GenericNonLocation),
3054 length: FieldLength::Four,
3055 });
3056 let variables = ();
3057 let req = DataRequest {
3058 id: DataIdentifierBorrowed::for_locale(&locale),
3059 ..Default::default()
3060 };
3061 let mut save_checksum = |cs: &u64| {
3062 // get_or_insert saves the value only if the Option is None.
3063 names_metadata.zone_checksum.get_or_insert(*cs);
3064 };
3065 let cs1 = self
3066 .mz_generic_long
3067 .load_put(mz_generic_provider, req, variables)
3068 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3069 .map_err(|e| PatternLoadError::Data(e, error_field))?
3070 .checksum
3071 .inspect(&mut save_checksum);
3072 let cs2 = self
3073 .mz_standard_long
3074 .load_put(mz_standard_provider, req, variables)
3075 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3076 .map_err(|e| PatternLoadError::Data(e, error_field))?
3077 .checksum
3078 .inspect(&mut save_checksum);
3079 let cs3 = self
3080 .mz_periods
3081 .load_put(mz_period_provider, Default::default(), ())
3082 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3083 .map_err(|e| PatternLoadError::Data(e, error_field))?
3084 .checksum
3085 .inspect(&mut save_checksum);
3086 // Error if any two of the checksum Options are Some and not equal.
3087 let cs = names_metadata.zone_checksum;
3088 if cs1.or(cs) != cs || cs2.or(cs) != cs || cs3.or(cs) != cs {
3089 return Err(PatternLoadError::Data(
3090 DataErrorKind::InconsistentData(tz::MzPeriodV1::INFO)
3091 .with_req(tz::MzGenericLongV1::INFO, req),
3092 error_field,
3093 ));
3094 }
3095 Ok(error_field)
3096 }
3097
3098 pub(crate) fn load_time_zone_generic_short_names(
3099 &mut self,
3100 provider: &(impl BoundDataProvider<tz::MzGenericShortV1> + ?Sized),
3101 mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3102 prefs: DateTimeFormatterPreferences,
3103 names_metadata: &mut DateTimeNamesMetadata,
3104 ) -> Result<ErrorField, PatternLoadError> {
3105 let locale = provider
3106 .bound_marker()
3107 .make_locale(prefs.locale_preferences);
3108 let error_field = ErrorField(fields::Field {
3109 symbol: FieldSymbol::TimeZone(fields::TimeZone::GenericNonLocation),
3110 length: FieldLength::One,
3111 });
3112 let variables = ();
3113 let req = DataRequest {
3114 id: DataIdentifierBorrowed::for_locale(&locale),
3115 ..Default::default()
3116 };
3117 let mut save_checksum = |cs: &u64| {
3118 // get_or_insert saves the value only if the Option is None.
3119 names_metadata.zone_checksum.get_or_insert(*cs);
3120 };
3121 let cs1 = self
3122 .mz_generic_short
3123 .load_put(provider, req, variables)
3124 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3125 .map_err(|e| PatternLoadError::Data(e, error_field))?
3126 .checksum
3127 .inspect(&mut save_checksum);
3128 let cs2 = self
3129 .mz_periods
3130 .load_put(mz_period_provider, Default::default(), ())
3131 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3132 .map_err(|e| PatternLoadError::Data(e, error_field))?
3133 .checksum
3134 .inspect(&mut save_checksum);
3135 // Error if any two of the checksum Options are Some and not equal.
3136 let cs = names_metadata.zone_checksum;
3137 if cs1.or(cs) != cs || cs2.or(cs) != cs {
3138 return Err(PatternLoadError::Data(
3139 DataErrorKind::InconsistentData(tz::MzPeriodV1::INFO)
3140 .with_req(tz::MzGenericLongV1::INFO, req),
3141 error_field,
3142 ));
3143 }
3144 Ok(error_field)
3145 }
3146
3147 pub(crate) fn load_time_zone_specific_long_names(
3148 &mut self,
3149 mz_specific_provider: &(impl BoundDataProvider<tz::MzSpecificLongV1> + ?Sized),
3150 mz_standard_provider: &(impl BoundDataProvider<tz::MzStandardLongV1> + ?Sized),
3151 mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3152 prefs: DateTimeFormatterPreferences,
3153 names_metadata: &mut DateTimeNamesMetadata,
3154 ) -> Result<ErrorField, PatternLoadError> {
3155 let locale = mz_specific_provider
3156 .bound_marker()
3157 .make_locale(prefs.locale_preferences);
3158 let error_field = ErrorField(fields::Field {
3159 symbol: FieldSymbol::TimeZone(fields::TimeZone::SpecificNonLocation),
3160 length: FieldLength::Four,
3161 });
3162 let variables = ();
3163 let req = DataRequest {
3164 id: DataIdentifierBorrowed::for_locale(&locale),
3165 ..Default::default()
3166 };
3167 let mut save_checksum = |cs: &u64| {
3168 // get_or_insert saves the value only if the Option is None.
3169 names_metadata.zone_checksum.get_or_insert(*cs);
3170 };
3171 let cs1 = self
3172 .mz_specific_long
3173 .load_put(mz_specific_provider, req, variables)
3174 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3175 .map_err(|e| PatternLoadError::Data(e, error_field))?
3176 .checksum
3177 .inspect(&mut save_checksum);
3178 let cs2 = self
3179 .mz_standard_long
3180 .load_put(mz_standard_provider, req, variables)
3181 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3182 .map_err(|e| PatternLoadError::Data(e, error_field))?
3183 .checksum
3184 .inspect(&mut save_checksum);
3185 let cs3 = self
3186 .mz_periods
3187 .load_put(mz_period_provider, Default::default(), ())
3188 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3189 .map_err(|e| PatternLoadError::Data(e, error_field))?
3190 .checksum
3191 .inspect(&mut save_checksum);
3192 // Error if any two of the checksum Options are Some and not equal.
3193 let cs = names_metadata.zone_checksum;
3194 if cs1.or(cs) != cs || cs2.or(cs) != cs || cs3.or(cs) != cs {
3195 return Err(PatternLoadError::Data(
3196 DataErrorKind::InconsistentData(tz::MzPeriodV1::INFO)
3197 .with_req(tz::MzSpecificLongV1::INFO, req),
3198 error_field,
3199 ));
3200 }
3201 Ok(error_field)
3202 }
3203
3204 pub(crate) fn load_time_zone_specific_short_names(
3205 &mut self,
3206 provider: &(impl BoundDataProvider<tz::MzSpecificShortV1> + ?Sized),
3207 mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3208 prefs: DateTimeFormatterPreferences,
3209 names_metadata: &mut DateTimeNamesMetadata,
3210 ) -> Result<ErrorField, PatternLoadError> {
3211 let locale = provider
3212 .bound_marker()
3213 .make_locale(prefs.locale_preferences);
3214 let error_field = ErrorField(fields::Field {
3215 symbol: FieldSymbol::TimeZone(fields::TimeZone::SpecificNonLocation),
3216 length: FieldLength::One,
3217 });
3218 let variables = ();
3219 let req = DataRequest {
3220 id: DataIdentifierBorrowed::for_locale(&locale),
3221 ..Default::default()
3222 };
3223 let mut save_checksum = |cs: &u64| {
3224 // get_or_insert saves the value only if the Option is None.
3225 names_metadata.zone_checksum.get_or_insert(*cs);
3226 };
3227 let cs1 = self
3228 .mz_specific_short
3229 .load_put(provider, req, variables)
3230 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3231 .map_err(|e| PatternLoadError::Data(e, error_field))?
3232 .checksum
3233 .inspect(&mut save_checksum);
3234 let cs2 = self
3235 .mz_periods
3236 .load_put(mz_period_provider, Default::default(), ())
3237 .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3238 .map_err(|e| PatternLoadError::Data(e, error_field))?
3239 .checksum
3240 .inspect(&mut save_checksum);
3241 // Error if any two of the checksum Options are Some and not equal.
3242 let cs = names_metadata.zone_checksum;
3243 if cs1.or(cs) != cs || cs2.or(cs) != cs {
3244 return Err(PatternLoadError::Data(
3245 DataErrorKind::InconsistentData(tz::MzPeriodV1::INFO)
3246 .with_req(tz::MzSpecificShortV1::INFO, req),
3247 error_field,
3248 ));
3249 }
3250 Ok(error_field)
3251 }
3252
3253 pub(crate) fn load_time_zone_field_z_except_decimals(
3254 &mut self,
3255 zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3256 mz_specific_short_provider: &(impl BoundDataProvider<tz::MzSpecificShortV1> + ?Sized),
3257 mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3258 prefs: DateTimeFormatterPreferences,
3259 names_metadata: &mut DateTimeNamesMetadata,
3260 ) -> Result<ErrorField, PatternLoadError> {
3261 self.load_time_zone_essentials(zone_essentials_provider, prefs)?;
3262 self.load_time_zone_specific_short_names(
3263 mz_specific_short_provider,
3264 mz_period_provider,
3265 prefs,
3266 names_metadata,
3267 )
3268 }
3269
3270 #[allow(clippy::too_many_arguments)]
3271 pub(crate) fn load_time_zone_field_zzzz_except_decimals(
3272 &mut self,
3273 zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3274 locations_provider: &(impl BoundDataProvider<tz::LocationsOverrideV1> + ?Sized),
3275 locations_root_provider: &(impl BoundDataProvider<tz::LocationsRootV1> + ?Sized),
3276 mz_standard_long_provider: &(impl BoundDataProvider<tz::MzStandardLongV1> + ?Sized),
3277 mz_specific_long_provider: &(impl BoundDataProvider<tz::MzSpecificLongV1> + ?Sized),
3278 mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3279 prefs: DateTimeFormatterPreferences,
3280 names_metadata: &mut DateTimeNamesMetadata,
3281 ) -> Result<ErrorField, PatternLoadError> {
3282 self.load_time_zone_essentials(zone_essentials_provider, prefs)?;
3283 self.load_time_zone_location_names(locations_provider, locations_root_provider, prefs)?;
3284 self.load_time_zone_specific_long_names(
3285 mz_specific_long_provider,
3286 mz_standard_long_provider,
3287 mz_period_provider,
3288 prefs,
3289 names_metadata,
3290 )
3291 }
3292
3293 #[allow(clippy::too_many_arguments)] // internal function with lots of generics
3294 pub(crate) fn load_time_zone_field_v_except_decimals(
3295 &mut self,
3296 zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3297 locations_provider: &(impl BoundDataProvider<tz::LocationsOverrideV1> + ?Sized),
3298 locations_root_provider: &(impl BoundDataProvider<tz::LocationsRootV1> + ?Sized),
3299 mz_generic_short_provider: &(impl BoundDataProvider<tz::MzGenericShortV1> + ?Sized),
3300 mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3301 prefs: DateTimeFormatterPreferences,
3302 names_metadata: &mut DateTimeNamesMetadata,
3303 ) -> Result<ErrorField, PatternLoadError> {
3304 self.load_time_zone_essentials(zone_essentials_provider, prefs)?;
3305 // For fallback:
3306 self.load_time_zone_location_names(locations_provider, locations_root_provider, prefs)?;
3307 self.load_time_zone_generic_short_names(
3308 mz_generic_short_provider,
3309 mz_period_provider,
3310 prefs,
3311 names_metadata,
3312 )
3313 }
3314
3315 #[allow(clippy::too_many_arguments)]
3316 pub(crate) fn load_time_zone_field_vvvv_except_decimals(
3317 &mut self,
3318 zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3319 locations_provider: &(impl BoundDataProvider<tz::LocationsOverrideV1> + ?Sized),
3320 locations_root_provider: &(impl BoundDataProvider<tz::LocationsRootV1> + ?Sized),
3321 mz_generic_long_provider: &(impl BoundDataProvider<tz::MzGenericLongV1> + ?Sized),
3322 mz_standard_long_provider: &(impl BoundDataProvider<tz::MzStandardLongV1> + ?Sized),
3323 mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3324 prefs: DateTimeFormatterPreferences,
3325 names_metadata: &mut DateTimeNamesMetadata,
3326 ) -> Result<ErrorField, PatternLoadError> {
3327 self.load_time_zone_essentials(zone_essentials_provider, prefs)?;
3328 // For fallback:
3329 self.load_time_zone_location_names(locations_provider, locations_root_provider, prefs)?;
3330 self.load_time_zone_generic_long_names(
3331 mz_generic_long_provider,
3332 mz_standard_long_provider,
3333 mz_period_provider,
3334 prefs,
3335 names_metadata,
3336 )
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_V(
3341 &mut self,
3342 _prefs: DateTimeFormatterPreferences,
3343 ) -> Result<(), PatternLoadError> {
3344 // no data required
3345 Ok(())
3346 }
3347
3348 #[allow(non_snake_case)] // this is a private function named after the case-sensitive CLDR field
3349 pub(crate) fn load_time_zone_field_VVV(
3350 &mut self,
3351 locations_provider: &(impl BoundDataProvider<tz::LocationsOverrideV1> + ?Sized),
3352 locations_root_provider: &(impl BoundDataProvider<tz::LocationsRootV1> + ?Sized),
3353 exemplar_cities_provider: &(impl BoundDataProvider<tz::CitiesOverrideV1> + ?Sized),
3354 exemplar_cities_root_provider: &(impl BoundDataProvider<tz::CitiesRootV1> + ?Sized),
3355 prefs: DateTimeFormatterPreferences,
3356 ) -> Result<ErrorField, PatternLoadError> {
3357 self.load_time_zone_location_names(locations_provider, locations_root_provider, prefs)?;
3358 self.load_time_zone_exemplar_city_names(
3359 exemplar_cities_provider,
3360 exemplar_cities_root_provider,
3361 prefs,
3362 )
3363 }
3364
3365 #[allow(non_snake_case)] // this is a private function named after the case-sensitive CLDR field
3366 pub(crate) fn load_time_zone_field_VVVV_except_decimals(
3367 &mut self,
3368 zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3369 locations_provider: &(impl BoundDataProvider<tz::LocationsOverrideV1> + ?Sized),
3370 locations_root_provider: &(impl BoundDataProvider<tz::LocationsRootV1> + ?Sized),
3371 prefs: DateTimeFormatterPreferences,
3372 ) -> Result<ErrorField, PatternLoadError> {
3373 self.load_time_zone_essentials(zone_essentials_provider, prefs)?;
3374 self.load_time_zone_location_names(locations_provider, locations_root_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_O_except_decimals(
3379 &mut self,
3380 zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3381 prefs: DateTimeFormatterPreferences,
3382 ) -> Result<ErrorField, PatternLoadError> {
3383 self.load_time_zone_essentials(zone_essentials_provider, prefs)
3384 }
3385
3386 #[allow(non_snake_case)] // this is a private function named after the case-sensitive CLDR field
3387 pub(crate) fn load_time_zone_field_X(
3388 &mut self,
3389 _prefs: DateTimeFormatterPreferences,
3390 ) -> Result<(), PatternLoadError> {
3391 // no data required
3392 Ok(())
3393 }
3394
3395 pub(crate) fn load_decimal_formatter(
3396 &mut self,
3397 loader: &impl DecimalFormatterLoader,
3398 prefs: DateTimeFormatterPreferences,
3399 ) -> Result<(), DataError> {
3400 if self.decimal_formatter.is_some() {
3401 return Ok(());
3402 }
3403 let mut options = DecimalFormatterOptions::default();
3404 options.grouping_strategy = Some(GroupingStrategy::Never);
3405 self.decimal_formatter = Some(DecimalFormatterLoader::load(
3406 loader,
3407 (&prefs).into(),
3408 options,
3409 )?);
3410 Ok(())
3411 }
3412
3413 /// Loads all data required for formatting the given [`PatternItem`]s.
3414 ///
3415 /// This function has a lot of arguments because many of the arguments are generic,
3416 /// and pulling them out to an options struct would be cumbersome.
3417 #[allow(clippy::too_many_arguments)]
3418 pub(crate) fn load_for_pattern(
3419 &mut self,
3420 year_provider: &(impl BoundDataProvider<YearNamesV1> + ?Sized),
3421 month_provider: &(impl BoundDataProvider<MonthNamesV1> + ?Sized),
3422 weekday_provider: &(impl BoundDataProvider<WeekdayNamesV1> + ?Sized),
3423 dayperiod_provider: &(impl BoundDataProvider<DayPeriodNamesV1> + ?Sized),
3424 zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3425 locations_provider: &(impl BoundDataProvider<tz::LocationsOverrideV1> + ?Sized),
3426 locations_root_provider: &(impl BoundDataProvider<tz::LocationsRootV1> + ?Sized),
3427 exemplar_cities_provider: &(impl BoundDataProvider<tz::CitiesOverrideV1> + ?Sized),
3428 exemplar_cities_root_provider: &(impl BoundDataProvider<tz::CitiesRootV1> + ?Sized),
3429 mz_generic_long_provider: &(impl BoundDataProvider<tz::MzGenericLongV1> + ?Sized),
3430 mz_generic_short_provider: &(impl BoundDataProvider<tz::MzGenericShortV1> + ?Sized),
3431 mz_standard_long_provider: &(impl BoundDataProvider<tz::MzStandardLongV1> + ?Sized),
3432 mz_specific_long_provider: &(impl BoundDataProvider<tz::MzSpecificLongV1> + ?Sized),
3433 mz_specific_short_provider: &(impl BoundDataProvider<tz::MzSpecificShortV1> + ?Sized),
3434 mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3435 decimal_formatter_loader: &impl DecimalFormatterLoader,
3436 prefs: DateTimeFormatterPreferences,
3437 pattern_items: impl Iterator<Item = PatternItem>,
3438 names_metadata: &mut DateTimeNamesMetadata,
3439 ) -> Result<(), PatternLoadError> {
3440 let mut numeric_field = None;
3441
3442 for item in pattern_items {
3443 let PatternItem::Field(field) = item else {
3444 continue;
3445 };
3446 let error_field = ErrorField(field);
3447
3448 use crate::provider::fields::*;
3449 use FieldLength::*;
3450 use FieldSymbol as FS;
3451
3452 match (field.symbol, field.length) {
3453 ///// Textual symbols /////
3454
3455 // G..GGGGG
3456 (FS::Era, One | Two | Three | Four | Five) => {
3457 self.load_year_names(
3458 year_provider,
3459 prefs,
3460 YearNameLength::from_field_length(field.length)
3461 .ok_or(PatternLoadError::UnsupportedLength(error_field))?,
3462 error_field,
3463 )?;
3464 }
3465
3466 // U..UUUUU
3467 (FS::Year(Year::Cyclic), One | Two | Three | Four | Five) => {
3468 numeric_field = Some(field);
3469 self.load_year_names(
3470 year_provider,
3471 prefs,
3472 YearNameLength::from_field_length(field.length)
3473 .ok_or(PatternLoadError::UnsupportedLength(error_field))?,
3474 error_field,
3475 )?;
3476 }
3477
3478 // MMM..MMMMM, LLL..LLLLL
3479 (
3480 FS::Month(field_symbol @ Month::Format | field_symbol @ Month::StandAlone),
3481 Three | Four | Five,
3482 ) => {
3483 self.load_month_names(
3484 month_provider,
3485 prefs,
3486 MonthNameLength::from_field(field_symbol, field.length)
3487 .ok_or(PatternLoadError::UnsupportedLength(error_field))?,
3488 error_field,
3489 )?;
3490 }
3491
3492 // e..ee, c..cc
3493 (FS::Weekday(Weekday::Local | Weekday::StandAlone), One | Two) => {
3494 // TODO(#5643): Requires locale-aware day-of-week calculation
3495 return Err(PatternLoadError::UnsupportedLength(ErrorField(field)));
3496 }
3497
3498 // E..EEEEEE, eee..eeeeee, ccc..cccccc
3499 (FS::Weekday(field_symbol), One | Two | Three | Four | Five | Six) => {
3500 self.load_weekday_names(
3501 weekday_provider,
3502 prefs,
3503 WeekdayNameLength::from_field(field_symbol, field.length)
3504 .ok_or(PatternLoadError::UnsupportedLength(error_field))?,
3505 error_field,
3506 )?;
3507 }
3508
3509 // a..aaaaa, b..bbbbb
3510 (FS::DayPeriod(field_symbol), One | Two | Three | Four | Five) => {
3511 self.load_day_period_names(
3512 dayperiod_provider,
3513 prefs,
3514 DayPeriodNameLength::from_field(field_symbol, field.length)
3515 .ok_or(PatternLoadError::UnsupportedLength(error_field))?,
3516 error_field,
3517 )?;
3518 }
3519
3520 ///// Time zone symbols /////
3521
3522 // z..zzz
3523 (FS::TimeZone(TimeZone::SpecificNonLocation), One | Two | Three) => {
3524 self.load_time_zone_field_z_except_decimals(
3525 zone_essentials_provider,
3526 mz_specific_short_provider,
3527 mz_period_provider,
3528 prefs,
3529 names_metadata,
3530 )?;
3531 numeric_field = Some(field);
3532 }
3533 // zzzz
3534 (FS::TimeZone(TimeZone::SpecificNonLocation), Four) => {
3535 self.load_time_zone_field_zzzz_except_decimals(
3536 zone_essentials_provider,
3537 locations_provider,
3538 locations_root_provider,
3539 mz_standard_long_provider,
3540 mz_specific_long_provider,
3541 mz_period_provider,
3542 prefs,
3543 names_metadata,
3544 )?;
3545 numeric_field = Some(field);
3546 }
3547 // v
3548 (FS::TimeZone(TimeZone::GenericNonLocation), One) => {
3549 self.load_time_zone_field_v_except_decimals(
3550 zone_essentials_provider,
3551 locations_provider,
3552 locations_root_provider,
3553 mz_generic_short_provider,
3554 mz_period_provider,
3555 prefs,
3556 names_metadata,
3557 )?;
3558 numeric_field = Some(field);
3559 }
3560 // vvvv
3561 (FS::TimeZone(TimeZone::GenericNonLocation), Four) => {
3562 self.load_time_zone_field_vvvv_except_decimals(
3563 zone_essentials_provider,
3564 locations_provider,
3565 locations_root_provider,
3566 mz_generic_long_provider,
3567 mz_standard_long_provider,
3568 mz_period_provider,
3569 prefs,
3570 names_metadata,
3571 )?;
3572 numeric_field = Some(field);
3573 }
3574
3575 // V
3576 (FS::TimeZone(TimeZone::Location), One) => {
3577 self.load_time_zone_field_V(prefs)?;
3578 }
3579 // VVV
3580 (FS::TimeZone(TimeZone::Location), Three) => {
3581 self.load_time_zone_field_VVV(
3582 locations_provider,
3583 locations_root_provider,
3584 exemplar_cities_provider,
3585 exemplar_cities_root_provider,
3586 prefs,
3587 )?;
3588 }
3589 // VVVV
3590 (FS::TimeZone(TimeZone::Location), Four) => {
3591 self.load_time_zone_field_VVVV_except_decimals(
3592 zone_essentials_provider,
3593 locations_provider,
3594 locations_root_provider,
3595 prefs,
3596 )?;
3597 numeric_field = Some(field);
3598 }
3599 // O, OOOO
3600 (FS::TimeZone(TimeZone::LocalizedOffset), One | Four) => {
3601 self.load_time_zone_field_O_except_decimals(zone_essentials_provider, prefs)?;
3602 numeric_field = Some(field);
3603 }
3604 // X..XXXXX, x..xxxxx
3605 (
3606 FS::TimeZone(TimeZone::IsoWithZ | TimeZone::Iso),
3607 One | Two | Three | Four | Five,
3608 ) => {
3609 self.load_time_zone_field_X(prefs)?;
3610 }
3611
3612 ///// Numeric symbols /////
3613
3614 // y+
3615 (FS::Year(Year::Calendar), _) => numeric_field = Some(field),
3616 // r+
3617 (FS::Year(Year::RelatedIso), _) => {
3618 // always formats as ASCII
3619 }
3620
3621 // M..MM, L..LL
3622 (FS::Month(_), One | Two) => numeric_field = Some(field),
3623
3624 // d..dd
3625 (FS::Day(Day::DayOfMonth), One | Two) => numeric_field = Some(field),
3626 // D..DDD
3627 (FS::Day(Day::DayOfYear), One | Two | Three) => numeric_field = Some(field),
3628 // F
3629 (FS::Day(Day::DayOfWeekInMonth), One) => numeric_field = Some(field),
3630
3631 // K..KK, h..hh, H..HH, k..kk
3632 (FS::Hour(_), One | Two) => numeric_field = Some(field),
3633
3634 // m..mm
3635 (FS::Minute, One | Two) => numeric_field = Some(field),
3636
3637 // s..ss
3638 (FS::Second(Second::Second), One | Two) => numeric_field = Some(field),
3639
3640 // A+
3641 (FS::Second(Second::MillisInDay), _) => numeric_field = Some(field),
3642
3643 // s.S+, ss.S+ (s is modelled by length, S+ by symbol)
3644 (FS::DecimalSecond(_), One | Two) => numeric_field = Some(field),
3645
3646 ///// Unsupported symbols /////
3647 _ => {
3648 return Err(PatternLoadError::UnsupportedLength(ErrorField(field)));
3649 }
3650 }
3651 }
3652
3653 if let Some(field) = numeric_field {
3654 self.load_decimal_formatter(decimal_formatter_loader, prefs)
3655 .map_err(|e| PatternLoadError::Data(e, ErrorField(field)))?;
3656 }
3657
3658 Ok(())
3659 }
3660}
3661
3662impl RawDateTimeNamesBorrowed<'_> {
3663 pub(crate) fn get_name_for_month(
3664 &self,
3665 field_symbol: fields::Month,
3666 field_length: FieldLength,
3667 code: MonthCode,
3668 ) -> Result<MonthPlaceholderValue, GetNameForMonthError> {
3669 let month_name_length = MonthNameLength::from_field(field_symbol, field_length)
3670 .ok_or(GetNameForMonthError::InvalidFieldLength)?;
3671 let month_names = self
3672 .month_names
3673 .get_with_variables(month_name_length)
3674 .ok_or(GetNameForMonthError::NotLoaded)?;
3675 let Some((month_number, is_leap)) = code.parsed() else {
3676 return Err(GetNameForMonthError::InvalidMonthCode);
3677 };
3678 let Some(month_index) = month_number.checked_sub(1) else {
3679 return Err(GetNameForMonthError::InvalidMonthCode);
3680 };
3681 let month_index = usize::from(month_index);
3682 let name = match month_names {
3683 MonthNames::Linear(linear) => {
3684 if is_leap {
3685 None
3686 } else {
3687 linear.get(month_index)
3688 }
3689 }
3690 MonthNames::LeapLinear(leap_linear) => {
3691 let num_months = leap_linear.len() / 2;
3692 if is_leap {
3693 leap_linear.get(month_index + num_months)
3694 } else if month_index < num_months {
3695 leap_linear.get(month_index)
3696 } else {
3697 None
3698 }
3699 }
3700 MonthNames::LeapNumeric(leap_numeric) => {
3701 if is_leap {
3702 return Ok(MonthPlaceholderValue::NumericPattern(leap_numeric));
3703 } else {
3704 return Ok(MonthPlaceholderValue::Numeric);
3705 }
3706 }
3707 };
3708 // Note: Always return `false` for the second argument since neo MonthNames
3709 // knows how to handle leap months and we don't need the fallback logic
3710 name.map(MonthPlaceholderValue::PlainString)
3711 .ok_or(GetNameForMonthError::InvalidMonthCode)
3712 }
3713
3714 pub(crate) fn get_name_for_weekday(
3715 &self,
3716 field_symbol: fields::Weekday,
3717 field_length: FieldLength,
3718 day: icu_calendar::types::Weekday,
3719 ) -> Result<&str, GetNameForWeekdayError> {
3720 let weekday_name_length = WeekdayNameLength::from_field(field_symbol, field_length)
3721 .ok_or(GetNameForWeekdayError::InvalidFieldLength)?;
3722 let weekday_names = self
3723 .weekday_names
3724 .get_with_variables(weekday_name_length)
3725 .ok_or(GetNameForWeekdayError::NotLoaded)?;
3726 weekday_names
3727 .names
3728 .get((day as usize) % 7)
3729 // Note: LinearNames does not guarantee a length of 7.
3730 .ok_or(GetNameForWeekdayError::NotLoaded)
3731 }
3732
3733 /// Gets the era symbol, or `None` if data is loaded but symbol isn't found.
3734 ///
3735 /// `None` should fall back to the era code directly, if, for example,
3736 /// a japanext datetime is formatted with a `DateTimeFormat<Japanese>`
3737 pub(crate) fn get_name_for_era(
3738 &self,
3739 field_length: FieldLength,
3740 era_year: EraYear,
3741 ) -> Result<&str, GetNameForEraError> {
3742 let year_name_length = YearNameLength::from_field_length(field_length)
3743 .ok_or(GetNameForEraError::InvalidFieldLength)?;
3744 let year_names = self
3745 .year_names
3746 .get_with_variables(year_name_length)
3747 .ok_or(GetNameForEraError::NotLoaded)?;
3748
3749 match (year_names, era_year.era_index) {
3750 (YearNames::VariableEras(era_names), None) => {
3751 crate::provider::neo::get_year_name_from_map(
3752 era_names,
3753 era_year.era.as_str().into(),
3754 )
3755 .ok_or(GetNameForEraError::InvalidEraCode)
3756 }
3757 (YearNames::FixedEras(era_names), Some(index)) => era_names
3758 .get(index as usize)
3759 .ok_or(GetNameForEraError::InvalidEraCode),
3760 _ => Err(GetNameForEraError::InvalidEraCode),
3761 }
3762 }
3763
3764 pub(crate) fn get_name_for_cyclic(
3765 &self,
3766 field_length: FieldLength,
3767 cyclic: u8,
3768 ) -> Result<&str, GetNameForCyclicYearError> {
3769 let year_name_length = YearNameLength::from_field_length(field_length)
3770 .ok_or(GetNameForCyclicYearError::InvalidFieldLength)?;
3771 let year_names = self
3772 .year_names
3773 .get_with_variables(year_name_length)
3774 .ok_or(GetNameForCyclicYearError::NotLoaded)?;
3775
3776 let YearNames::Cyclic(cyclics) = year_names else {
3777 return Err(GetNameForCyclicYearError::InvalidYearNumber { max: 0 });
3778 };
3779
3780 cyclics
3781 .get(cyclic as usize - 1)
3782 .ok_or(GetNameForCyclicYearError::InvalidYearNumber {
3783 max: cyclics.len() as u8 + 1,
3784 })
3785 }
3786
3787 pub(crate) fn get_name_for_day_period(
3788 &self,
3789 field_symbol: fields::DayPeriod,
3790 field_length: FieldLength,
3791 hour: icu_time::Hour,
3792 is_top_of_hour: bool,
3793 ) -> Result<&str, GetNameForDayPeriodError> {
3794 use fields::DayPeriod::NoonMidnight;
3795 let day_period_name_length = DayPeriodNameLength::from_field(field_symbol, field_length)
3796 .ok_or(GetNameForDayPeriodError::InvalidFieldLength)?;
3797 let dayperiod_names = self
3798 .dayperiod_names
3799 .get_with_variables(day_period_name_length)
3800 .ok_or(GetNameForDayPeriodError::NotLoaded)?;
3801 let option_value: Option<&str> = match (field_symbol, u8::from(hour), is_top_of_hour) {
3802 (NoonMidnight, 00, true) => dayperiod_names.midnight().or_else(|| dayperiod_names.am()),
3803 (NoonMidnight, 12, true) => dayperiod_names.noon().or_else(|| dayperiod_names.pm()),
3804 (_, hour, _) if hour < 12 => dayperiod_names.am(),
3805 _ => dayperiod_names.pm(),
3806 };
3807 option_value.ok_or(GetNameForDayPeriodError::NotLoaded)
3808 }
3809}
3810
3811/// A container contains all data payloads for time zone formatting (borrowed version).
3812#[derive(Debug, Copy, Clone, Default)]
3813pub(crate) struct TimeZoneDataPayloadsBorrowed<'a> {
3814 /// The data that contains meta information about how to display content.
3815 pub(crate) essentials: Option<&'a tz::Essentials<'a>>,
3816 /// The root location names, e.g. Italy
3817 pub(crate) locations_root: Option<&'a tz::Locations<'a>>,
3818 /// The language specific location names, e.g. Italia
3819 pub(crate) locations: Option<&'a tz::Locations<'a>>,
3820 /// The root exemplar city names, e.g. Rome
3821 pub(crate) exemplars_root: Option<&'a tz::ExemplarCities<'a>>,
3822 /// The language specific exemplar names, e.g. Roma
3823 pub(crate) exemplars: Option<&'a tz::ExemplarCities<'a>>,
3824 /// The generic long metazone names, e.g. Pacific Time
3825 pub(crate) mz_generic_long: Option<&'a tz::MzGeneric<'a>>,
3826 /// The long metazone names shared between generic and standard, e.g. Gulf Standard Time
3827 pub(crate) mz_standard_long: Option<&'a tz::MzGeneric<'a>>,
3828 /// The generic short metazone names, e.g. PT
3829 pub(crate) mz_generic_short: Option<&'a tz::MzGeneric<'a>>,
3830 /// The specific long metazone names, e.g. Pacific Daylight Time
3831 pub(crate) mz_specific_long: Option<&'a tz::MzSpecific<'a>>,
3832 /// The specific short metazone names, e.g. Pacific Daylight Time
3833 pub(crate) mz_specific_short: Option<&'a tz::MzSpecific<'a>>,
3834 /// The metazone lookup
3835 pub(crate) mz_periods: Option<&'a tz::MzPeriod<'a>>,
3836}
3837
3838impl<'data> RawDateTimeNamesBorrowed<'data> {
3839 pub(crate) fn get_payloads(&self) -> TimeZoneDataPayloadsBorrowed<'data> {
3840 TimeZoneDataPayloadsBorrowed {
3841 essentials: self.zone_essentials.get_option(),
3842 locations_root: self.locations_root.get_option(),
3843 locations: self.locations.get_option(),
3844 exemplars: self.exemplars.get_option(),
3845 exemplars_root: self.exemplars_root.get_option(),
3846 mz_generic_long: self.mz_generic_long.get_option(),
3847 mz_standard_long: self.mz_standard_long.get_option(),
3848 mz_generic_short: self.mz_generic_short.get_option(),
3849 mz_specific_long: self.mz_specific_long.get_option(),
3850 mz_specific_short: self.mz_specific_short.get_option(),
3851 mz_periods: self.mz_periods.get_option(),
3852 }
3853 }
3854}