• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

zbraniecki / icu4x / 13958601093

19 Mar 2025 04:17PM UTC coverage: 74.164% (-1.5%) from 75.71%
13958601093

push

github

web-flow
Clean up properties docs (#6315)

58056 of 78281 relevant lines covered (74.16%)

819371.32 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

38.01
/components/datetime/src/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

5
use super::{
6
    DateTimePattern, DateTimePatternFormatter, GetNameForCyclicYearError, GetNameForDayPeriodError,
7
    GetNameForEraError, GetNameForMonthError, GetNameForWeekdayError, MonthPlaceholderValue,
8
    PatternLoadError,
9
};
10
use crate::error::ErrorField;
11
use crate::fieldsets::enums::{CompositeDateTimeFieldSet, CompositeFieldSet};
12
use crate::provider::fields::{self, FieldLength, FieldSymbol};
13
use crate::provider::neo::{marker_attrs, *};
14
use crate::provider::pattern::PatternItem;
15
use crate::provider::time_zones::tz;
16
use crate::size_test_macro::size_test;
17
use crate::FixedCalendarDateTimeFormatter;
18
use crate::{external_loaders::*, DateTimeFormatterPreferences};
19
use crate::{scaffold::*, DateTimeFormatter, DateTimeFormatterLoadError};
20
use core::fmt;
21
use core::marker::PhantomData;
22
use core::num::NonZeroU8;
23
use icu_calendar::types::FormattingEra;
24
use icu_calendar::types::MonthCode;
25
use icu_calendar::AnyCalendar;
26
use icu_decimal::options::DecimalFormatterOptions;
27
use icu_decimal::options::GroupingStrategy;
28
use icu_decimal::provider::{DecimalDigitsV1, DecimalSymbolsV1};
29
use icu_decimal::DecimalFormatter;
30
use icu_provider::prelude::*;
31

32
/// Choices for loading year names.
33
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
522✔
34
#[non_exhaustive]
35
pub enum YearNameLength {
36
    /// An abbreviated calendar-dependent year or era name.
37
    ///
38
    /// Examples:
39
    ///
40
    /// - "AD"
41
    /// - "甲子"
42
    Abbreviated,
43
    /// A wide calendar-dependent year or era name.
44
    ///
45
    /// Examples:
46
    ///
47
    /// - "Anno Domini"
48
    /// - "甲子"
49
    Wide,
50
    /// A narrow calendar-dependent year or era name. Not necesarily unique.
51
    ///
52
    /// Examples:
53
    ///
54
    /// - "A"
55
    /// - "甲子"
56
    Narrow,
57
}
58

59
impl YearNameLength {
60
    pub(crate) fn to_attributes(self) -> &'static DataMarkerAttributes {
259✔
61
        use marker_attrs::Length;
62
        let length = match self {
259✔
63
            YearNameLength::Abbreviated => Length::Abbr,
241✔
64
            YearNameLength::Wide => Length::Wide,
4✔
65
            YearNameLength::Narrow => Length::Narrow,
14✔
66
        };
67
        marker_attrs::name_attr_for(marker_attrs::Context::Format, length)
259✔
68
    }
259✔
69

70
    pub(crate) fn from_field_length(field_length: FieldLength) -> Option<Self> {
773✔
71
        // UTS 35 says that "G..GGG" and "U..UUU" are all Abbreviated
72
        let field_length = field_length.numeric_to_abbr();
773✔
73
        match field_length {
773✔
74
            FieldLength::Three => Some(YearNameLength::Abbreviated),
697✔
75
            FieldLength::Four => Some(YearNameLength::Wide),
6✔
76
            FieldLength::Five => Some(YearNameLength::Narrow),
70✔
77
            _ => None,
×
78
        }
79
    }
773✔
80

81
    /// Returns an [`ErrorField`] sufficient for error reporting.
82
    pub(crate) fn to_approximate_error_field(self) -> ErrorField {
10✔
83
        let field_length = match self {
10✔
84
            YearNameLength::Abbreviated => FieldLength::Three,
4✔
85
            YearNameLength::Wide => FieldLength::Four,
4✔
86
            YearNameLength::Narrow => FieldLength::Five,
2✔
87
        };
88
        ErrorField(fields::Field {
10✔
89
            symbol: FieldSymbol::Era,
10✔
90
            length: field_length,
10✔
91
        })
92
    }
10✔
93
}
94

95
/// Choices for loading month names.
96
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
710✔
97
#[non_exhaustive]
98
pub enum MonthNameLength {
99
    /// An abbreviated calendar-dependent month name for formatting with other fields.
100
    ///
101
    /// Example: "Sep"
102
    Abbreviated,
103
    /// A wide calendar-dependent month name for formatting with other fields.
104
    ///
105
    /// Example: "September"
106
    Wide,
107
    /// A narrow calendar-dependent month name for formatting with other fields. Not necesarily unique.
108
    ///
109
    /// Example: "S"
110
    Narrow,
111
    /// An abbreviated calendar-dependent month name for stand-alone display.
112
    ///
113
    /// Example: "Sep"
114
    StandaloneAbbreviated,
115
    /// A wide calendar-dependent month name for stand-alone display.
116
    ///
117
    /// Example: "September"
118
    StandaloneWide,
119
    /// A narrow calendar-dependent month name for stand-alone display. Not necesarily unique.
120
    ///
121
    /// Example: "S"
122
    StandaloneNarrow,
123
}
124

125
impl MonthNameLength {
126
    pub(crate) fn to_attributes(self) -> &'static DataMarkerAttributes {
208✔
127
        use marker_attrs::{Context, Length};
128
        let (context, length) = match self {
416✔
129
            MonthNameLength::Abbreviated => (Context::Format, Length::Abbr),
75✔
130
            MonthNameLength::Wide => (Context::Format, Length::Wide),
122✔
131
            MonthNameLength::Narrow => (Context::Format, Length::Narrow),
1✔
132
            MonthNameLength::StandaloneAbbreviated => (Context::Standalone, Length::Abbr),
5✔
133
            MonthNameLength::StandaloneWide => (Context::Standalone, Length::Wide),
4✔
134
            MonthNameLength::StandaloneNarrow => (Context::Standalone, Length::Narrow),
1✔
135
        };
136
        marker_attrs::name_attr_for(context, length)
208✔
137
    }
208✔
138

139
    pub(crate) fn from_field(
906✔
140
        field_symbol: fields::Month,
141
        field_length: FieldLength,
142
    ) -> Option<Self> {
143
        use fields::Month;
144
        match (field_symbol, field_length) {
906✔
145
            (Month::Format, FieldLength::Three) => Some(MonthNameLength::Abbreviated),
299✔
146
            (Month::Format, FieldLength::Four) => Some(MonthNameLength::Wide),
569✔
147
            (Month::Format, FieldLength::Five) => Some(MonthNameLength::Narrow),
2✔
148
            (Month::StandAlone, FieldLength::Three) => Some(MonthNameLength::StandaloneAbbreviated),
24✔
149
            (Month::StandAlone, FieldLength::Four) => Some(MonthNameLength::StandaloneWide),
10✔
150
            (Month::StandAlone, FieldLength::Five) => Some(MonthNameLength::StandaloneNarrow),
2✔
151
            _ => None,
×
152
        }
153
    }
906✔
154

155
    /// Returns an [`ErrorField`] sufficient for error reporting.
156
    pub(crate) fn to_approximate_error_field(self) -> ErrorField {
14✔
157
        use fields::Month;
158
        let (field_symbol, field_length) = match self {
28✔
159
            MonthNameLength::Abbreviated => (Month::Format, FieldLength::Three),
4✔
160
            MonthNameLength::Wide => (Month::Format, FieldLength::Four),
5✔
161
            MonthNameLength::Narrow => (Month::Format, FieldLength::Five),
1✔
162
            MonthNameLength::StandaloneAbbreviated => (Month::StandAlone, FieldLength::Three),
1✔
163
            MonthNameLength::StandaloneWide => (Month::StandAlone, FieldLength::Four),
2✔
164
            MonthNameLength::StandaloneNarrow => (Month::StandAlone, FieldLength::Five),
1✔
165
        };
166
        ErrorField(fields::Field {
14✔
167
            symbol: FieldSymbol::Month(field_symbol),
14✔
168
            length: field_length,
169
        })
170
    }
14✔
171
}
172

173
/// Choices for loading weekday names.
174
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
572✔
175
#[non_exhaustive]
176
pub enum WeekdayNameLength {
177
    /// An abbreviated weekday name for formatting with other fields.
178
    ///
179
    /// Example: "Tue"
180
    Abbreviated,
181
    /// A wide weekday name for formatting with other fields.
182
    ///
183
    /// Example: "Tuesday"
184
    Wide,
185
    /// A narrow weekday name for formatting with other fields. Not necesarily unique.
186
    ///
187
    /// Example: "T"
188
    Narrow,
189
    /// A short weekday name for formatting with other fields.
190
    ///
191
    /// Example: "Tu"
192
    Short,
193
    /// An abbreviated weekday name for stand-alone display.
194
    ///
195
    /// Example: "Tue"
196
    StandaloneAbbreviated,
197
    /// A wide weekday name for stand-alone display.
198
    ///
199
    /// Example: "Tuesday"
200
    StandaloneWide,
201
    /// A narrow weekday name for stand-alone display. Not necesarily unique.
202
    ///
203
    /// Example: "T"
204
    StandaloneNarrow,
205
    /// A short weekday name for stand-alone display.
206
    ///
207
    /// Example: "Tu"
208
    StandaloneShort,
209
}
210

211
impl WeekdayNameLength {
212
    pub(crate) fn to_attributes(self) -> &'static DataMarkerAttributes {
157✔
213
        use marker_attrs::{Context, Length};
214
        // UTS 35 says that "e" and "E" have the same non-numeric names
215
        let (context, length) = match self {
314✔
216
            WeekdayNameLength::Abbreviated => (Context::Format, Length::Abbr),
37✔
217
            WeekdayNameLength::Wide => (Context::Format, Length::Wide),
98✔
218
            WeekdayNameLength::Narrow => (Context::Format, Length::Narrow),
2✔
219
            WeekdayNameLength::Short => (Context::Format, Length::Short),
2✔
220
            WeekdayNameLength::StandaloneAbbreviated => (Context::Standalone, Length::Abbr),
12✔
221
            WeekdayNameLength::StandaloneWide => (Context::Standalone, Length::Wide),
4✔
222
            WeekdayNameLength::StandaloneNarrow => (Context::Standalone, Length::Narrow),
1✔
223
            WeekdayNameLength::StandaloneShort => (Context::Standalone, Length::Short),
1✔
224
        };
225
        marker_attrs::name_attr_for(context, length)
157✔
226
    }
157✔
227

228
    pub(crate) fn from_field(
711✔
229
        field_symbol: fields::Weekday,
230
        field_length: FieldLength,
231
    ) -> Option<Self> {
232
        use fields::Weekday;
233
        // UTS 35 says that "e" and "E" have the same non-numeric names
234
        let field_symbol = field_symbol.to_format_symbol();
711✔
235
        // UTS 35 says that "E..EEE" are all Abbreviated
236
        // However, this doesn't apply to "e" and "c".
237
        let field_length = if matches!(field_symbol, fields::Weekday::Format) {
711✔
238
            field_length.numeric_to_abbr()
642✔
239
        } else {
240
            field_length
69✔
241
        };
242
        match (field_symbol, field_length) {
711✔
243
            (Weekday::Format, FieldLength::Three) => Some(WeekdayNameLength::Abbreviated),
152✔
244
            (Weekday::Format, FieldLength::Four) => Some(WeekdayNameLength::Wide),
484✔
245
            (Weekday::Format, FieldLength::Five) => Some(WeekdayNameLength::Narrow),
4✔
246
            (Weekday::Format, FieldLength::Six) => Some(WeekdayNameLength::Short),
4✔
247
            (Weekday::StandAlone, FieldLength::Three) => {
248
                Some(WeekdayNameLength::StandaloneAbbreviated)
55✔
249
            }
250
            (Weekday::StandAlone, FieldLength::Four) => Some(WeekdayNameLength::StandaloneWide),
10✔
251
            (Weekday::StandAlone, FieldLength::Five) => Some(WeekdayNameLength::StandaloneNarrow),
2✔
252
            (Weekday::StandAlone, FieldLength::Six) => Some(WeekdayNameLength::StandaloneShort),
2✔
253
            _ => None,
2✔
254
        }
255
    }
715✔
256

257
    /// Returns an [`ErrorField`] sufficient for error reporting.
258
    pub(crate) fn to_approximate_error_field(self) -> ErrorField {
20✔
259
        use fields::Weekday;
260
        let (field_symbol, field_length) = match self {
40✔
261
            WeekdayNameLength::Abbreviated => (Weekday::Format, FieldLength::Three),
7✔
262
            WeekdayNameLength::Wide => (Weekday::Format, FieldLength::Four),
4✔
263
            WeekdayNameLength::Narrow => (Weekday::Format, FieldLength::Five),
2✔
264
            WeekdayNameLength::Short => (Weekday::Format, FieldLength::Six),
2✔
265
            WeekdayNameLength::StandaloneAbbreviated => (Weekday::StandAlone, FieldLength::Three),
1✔
266
            WeekdayNameLength::StandaloneWide => (Weekday::StandAlone, FieldLength::Four),
2✔
267
            WeekdayNameLength::StandaloneNarrow => (Weekday::StandAlone, FieldLength::Five),
1✔
268
            WeekdayNameLength::StandaloneShort => (Weekday::StandAlone, FieldLength::Six),
1✔
269
        };
270
        ErrorField(fields::Field {
20✔
271
            symbol: FieldSymbol::Weekday(field_symbol),
20✔
272
            length: field_length,
273
        })
274
    }
20✔
275
}
276

277
/// Choices for loading day period names.
278
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
617✔
279
#[non_exhaustive]
280
pub enum DayPeriodNameLength {
281
    /// An abbreviated 12-hour day period name, including display names for 0h and 12h.
282
    ///
283
    /// Examples:
284
    ///
285
    /// - "AM"
286
    /// - "mid."
287
    Abbreviated,
288
    /// A wide 12-hour day period name, including display names for 0h and 12h.
289
    ///
290
    /// The wide form may be the same as the abbreviated form if the "real" long form
291
    /// (eg "ante meridiem") is not customarily used.
292
    ///
293
    /// Examples:
294
    ///
295
    /// - "AM"
296
    /// - "mignight"
297
    Wide,
298
    /// An abbreviated 12-hour day period name, including display names for 0h and 12h.
299
    ///
300
    /// The narrow form must be unique, unlike some other fields.
301
    ///
302
    /// Examples:
303
    ///
304
    /// - "AM"
305
    /// - "md"
306
    Narrow,
307
}
308

309
impl DayPeriodNameLength {
310
    pub(crate) fn to_attributes(self) -> &'static DataMarkerAttributes {
243✔
311
        use marker_attrs::Length;
312
        let length = match self {
243✔
313
            DayPeriodNameLength::Abbreviated => Length::Abbr,
201✔
314
            DayPeriodNameLength::Wide => Length::Wide,
22✔
315
            DayPeriodNameLength::Narrow => Length::Narrow,
20✔
316
        };
317
        marker_attrs::name_attr_for(marker_attrs::Context::Format, length)
243✔
318
    }
243✔
319

320
    pub(crate) fn from_field(
842✔
321
        field_symbol: fields::DayPeriod,
322
        field_length: FieldLength,
323
    ) -> Option<Self> {
324
        use fields::DayPeriod;
325
        // Names for 'a' and 'b' are stored in the same data marker
326
        let field_symbol = match field_symbol {
842✔
327
            DayPeriod::NoonMidnight => DayPeriod::AmPm,
225✔
328
            other => other,
617✔
329
        };
330
        // UTS 35 says that "a..aaa" and "b..bbb" are all Abbreviated
331
        let field_length = field_length.numeric_to_abbr();
842✔
332
        match (field_symbol, field_length) {
842✔
333
            (DayPeriod::AmPm, FieldLength::Three) => Some(DayPeriodNameLength::Abbreviated),
726✔
334
            (DayPeriod::AmPm, FieldLength::Four) => Some(DayPeriodNameLength::Wide),
58✔
335
            (DayPeriod::AmPm, FieldLength::Five) => Some(DayPeriodNameLength::Narrow),
58✔
336
            _ => None,
×
337
        }
338
    }
842✔
339

340
    /// Returns an [`ErrorField`] sufficient for error reporting.
341
    pub(crate) fn to_approximate_error_field(self) -> ErrorField {
20✔
342
        // Names for 'a' and 'b' are stored in the same data marker
343
        let field_symbol = fields::DayPeriod::AmPm;
20✔
344
        let field_length = match self {
20✔
345
            DayPeriodNameLength::Abbreviated => FieldLength::Three,
14✔
346
            DayPeriodNameLength::Wide => FieldLength::Four,
4✔
347
            DayPeriodNameLength::Narrow => FieldLength::Five,
2✔
348
        };
349
        ErrorField(fields::Field {
20✔
350
            symbol: FieldSymbol::DayPeriod(field_symbol),
20✔
351
            length: field_length,
20✔
352
        })
353
    }
20✔
354
}
355

356
pub(crate) struct EmptyDataProvider;
357

358
impl<M> DataProvider<M> for EmptyDataProvider
359
where
360
    M: DataMarker,
361
{
362
    fn load(&self, base_req: DataRequest) -> Result<DataResponse<M>, DataError> {
×
363
        Err(DataErrorKind::MarkerNotFound.with_req(M::INFO, base_req))
×
364
    }
×
365
}
366

367
size_test!(
368
    FixedCalendarDateTimeNames<icu_calendar::Gregorian>,
369
    typed_date_time_names_size,
370
    312
371
);
372

373
/// A low-level type that formats datetime patterns with localized names.
374
/// The calendar should be chosen at compile time.
375
#[doc = typed_date_time_names_size!()]
376
///
377
/// Type parameters:
378
///
379
/// 1. The calendar chosen at compile time for additional type safety
380
/// 2. A components object type containing the fields that might be formatted
381
///
382
/// By default, the components object is set to [`CompositeDateTimeFieldSet`],
383
/// meaning that dates and times, but not time zones, are supported. A smaller
384
/// components object results in smaller stack size.
385
///
386
/// To support all fields including time zones, use [`CompositeFieldSet`].
387
///
388
/// [`CompositeFieldSet`]: crate::fieldsets::enums::CompositeFieldSet
389
/// [`CompositeDateTimeFieldSet`]: crate::fieldsets::enums::CompositeDateTimeFieldSet
390
///
391
/// # Examples
392
///
393
/// ```
394
/// use icu::calendar::Gregorian;
395
/// use icu::datetime::input::Date;
396
/// use icu::datetime::pattern::FixedCalendarDateTimeNames;
397
/// use icu::datetime::pattern::DateTimePattern;
398
/// use icu::datetime::pattern::MonthNameLength;
399
/// use icu::datetime::pattern::WeekdayNameLength;
400
/// use icu::datetime::pattern::DayPeriodNameLength;
401
/// use icu::locale::locale;
402
/// use icu::datetime::input::{DateTime, Time};
403
/// use writeable::assert_try_writeable_eq;
404
///
405
/// // Create an instance that can format abbreviated month, weekday, and day period names:
406
/// let mut names: FixedCalendarDateTimeNames<Gregorian> =
407
///     FixedCalendarDateTimeNames::try_new(locale!("uk").into()).unwrap();
408
/// names
409
///     .include_month_names(MonthNameLength::Abbreviated)
410
///     .unwrap()
411
///     .include_weekday_names(WeekdayNameLength::Abbreviated)
412
///     .unwrap()
413
///     .include_day_period_names(DayPeriodNameLength::Abbreviated)
414
///     .unwrap();
415
///
416
/// // Create a pattern from a pattern string (note: K is the hour with h11 hour cycle):
417
/// let pattern_str = "E MMM d y -- K:mm a";
418
/// let pattern: DateTimePattern = pattern_str.parse().unwrap();
419
///
420
/// // Test it:
421
/// let datetime = DateTime { date: Date::try_new_gregorian(2023, 11, 20).unwrap(), time: Time::try_new(12, 35, 3, 0).unwrap() };
422
/// assert_try_writeable_eq!(names.with_pattern_unchecked(&pattern).format(&datetime), "пн лист. 20 2023 -- 0:35 пп");
423
/// ```
424
///
425
/// If the correct data is not loaded, and error will occur:
426
///
427
/// ```
428
/// use icu::calendar::Gregorian;
429
/// use icu::datetime::input::Date;
430
/// use icu::datetime::DateTimeWriteError;
431
/// use icu::datetime::parts;
432
/// use icu::datetime::pattern::FixedCalendarDateTimeNames;
433
/// use icu::datetime::pattern::{DateTimePattern, PatternLoadError};
434
/// use icu::datetime::fieldsets::enums::CompositeFieldSet;
435
/// use icu::locale::locale;
436
/// use icu::time::zone::{IanaParser, VariantOffsetsCalculator};
437
/// use icu::datetime::input::{Time, TimeZoneInfo, ZonedDateTime};
438
/// use icu_provider_adapters::empty::EmptyDataProvider;
439
/// use writeable::{Part, assert_try_writeable_parts_eq};
440
///
441
/// // Unstable API used only for error construction below
442
/// use icu::datetime::provider::fields::{Field, FieldLength, FieldSymbol, Weekday};
443
///
444
/// // Create an instance that can format all fields (CompositeFieldSet):
445
/// let mut names: FixedCalendarDateTimeNames<Gregorian, CompositeFieldSet> =
446
///     FixedCalendarDateTimeNames::try_new(locale!("en").into()).unwrap();
447
///
448
/// // Create a pattern from a pattern string:
449
/// let pattern_str = "'It is:' E MMM d y G 'at' h:mm:ssSSS a zzzz";
450
/// let pattern: DateTimePattern = pattern_str.parse().unwrap();
451
///
452
/// // The pattern string contains lots of symbols including "E", "MMM", and "a",
453
/// // but we did not load any data!
454
///
455
/// let mut dtz = ZonedDateTime::try_from_str("2023-11-20T11:35:03+00:00[Europe/London]", Gregorian, IanaParser::new(), VariantOffsetsCalculator::new()).unwrap();
456
///
457
/// // Missing data is filled in on a best-effort basis, and an error is signaled.
458
/// assert_try_writeable_parts_eq!(
459
///     names.with_pattern_unchecked(&pattern).format(&dtz),
460
///     "It is: mon M11 20 2023 CE at 11:35:03.000 AM +0000",
461
///     Err(DateTimeWriteError::NamesNotLoaded(Field { symbol: FieldSymbol::Weekday(Weekday::Format), length: FieldLength::One }.into())),
462
///     [
463
///         (7, 10, Part::ERROR), // mon
464
///         (7, 10, parts::WEEKDAY), // mon
465
///         (11, 14, Part::ERROR), // M11
466
///         (11, 14, parts::MONTH), // M11
467
///         (15, 17, icu::decimal::parts::INTEGER), // 20
468
///         (15, 17, parts::DAY), // 20
469
///         (18, 22, icu::decimal::parts::INTEGER), // 2023
470
///         (18, 22, parts::YEAR), // 2023
471
///         (23, 25, Part::ERROR), // CE
472
///         (23, 25, parts::ERA), // CE
473
///         (29, 31, icu::decimal::parts::INTEGER), // 11
474
///         (29, 31, parts::HOUR), // 11
475
///         (32, 34, icu::decimal::parts::INTEGER), // 35
476
///         (32, 34, parts::MINUTE), // 35
477
///         (35, 41, parts::SECOND), // 03.000
478
///         (35, 37, icu::decimal::parts::INTEGER), // 03
479
///         (37, 38, icu::decimal::parts::DECIMAL), // .
480
///         (38, 41, icu::decimal::parts::FRACTION), // 000
481
///         (42, 44, Part::ERROR), // AM
482
///         (42, 44, parts::DAY_PERIOD), // AM
483
///         (45, 50, Part::ERROR), // +0000
484
///         (45, 50, parts::TIME_ZONE_NAME), // +0000
485
///     ]
486
/// );
487
///
488
/// // To make the error occur sooner, one can use an EmptyDataProvider:
489
/// let empty = EmptyDataProvider::new();
490
/// assert!(matches!(
491
///     names.load_for_pattern(&empty, &pattern),
492
///     Err(PatternLoadError::Data(_, _)),
493
/// ));
494
/// ```
495
///
496
/// If the pattern contains fields inconsistent with the receiver, an error will occur:
497
///
498
/// ```
499
/// use icu::calendar::Gregorian;
500
/// use icu::datetime::DateTimeWriteError;
501
/// use icu::datetime::parts;
502
/// use icu::datetime::pattern::FixedCalendarDateTimeNames;
503
/// use icu::datetime::pattern::DateTimePattern;
504
/// use icu::datetime::fieldsets::zone::LocalizedOffsetLong;
505
/// use icu::locale::locale;
506
/// use icu::datetime::input::{DateTime, TimeZoneInfo};
507
/// use writeable::{Part, assert_try_writeable_parts_eq};
508
///
509
/// // Create an instance that can format abbreviated month, weekday, and day period names:
510
/// let mut names: FixedCalendarDateTimeNames<Gregorian, LocalizedOffsetLong> =
511
///     FixedCalendarDateTimeNames::try_new(locale!("en").into()).unwrap();
512
///
513
/// // Create a pattern from a pattern string:
514
/// let pattern_str = "'It is:' E MMM d y G 'at' h:mm:ssSSS a zzzz";
515
/// let pattern: DateTimePattern = pattern_str.parse().unwrap();
516
///
517
/// // The pattern string contains lots of symbols including "E", "MMM", and "a",
518
/// // but the `FixedCalendarDateTimeNames` is configured to format only time zones!
519
/// // Further, the time zone we provide doesn't contain any offset into!
520
/// // Missing data is filled in on a best-effort basis, and an error is signaled.
521
/// assert_try_writeable_parts_eq!(
522
///     names.with_pattern_unchecked(&pattern).format(&TimeZoneInfo::unknown()),
523
///     "It is: {E} {M} {d} {y} {G} at {h}:{m}:{s} {a} {z}",
524
///     Err(DateTimeWriteError::MissingInputField("iso_weekday")),
525
///     [
526
///         (7, 10, Part::ERROR), // {E}
527
///         (7, 10, parts::WEEKDAY), // {E}
528
///         (11, 14, Part::ERROR), // {M}
529
///         (11, 14, parts::MONTH), // {M}
530
///         (15, 18, Part::ERROR), // {d}
531
///         (15, 18, parts::DAY), // {d}
532
///         (19, 22, Part::ERROR), // {y}
533
///         (19, 22, parts::YEAR), // {y}
534
///         (23, 26, Part::ERROR), // {G}
535
///         (23, 26, parts::ERA), // {G}
536
///         (30, 33, Part::ERROR), // {h}
537
///         (30, 33, parts::HOUR), // {h}
538
///         (34, 37, Part::ERROR), // {m}
539
///         (34, 37, parts::MINUTE), // {m}
540
///         (38, 41, Part::ERROR), // {s}
541
///         (38, 41, parts::SECOND), // {s}
542
///         (42, 45, Part::ERROR), // {a}
543
///         (42, 45, parts::DAY_PERIOD), // {a}
544
///         (46, 49, Part::ERROR), // {z}
545
///         (46, 49, parts::TIME_ZONE_NAME), // {z}
546
///     ]
547
/// );
548
/// ```
549
///
550
/// When loading data for time zones, currently only one type can be loaded; see:
551
/// <https://github.com/unicode-org/icu4x/issues/6063>
552
///
553
/// ```
554
/// use icu::datetime::input::Date;
555
/// use icu::datetime::pattern::FixedCalendarDateTimeNames;
556
/// use icu::datetime::fieldsets::enums::ZoneFieldSet;
557
/// use icu::locale::locale;
558
/// use icu::datetime::input::{DateTime, Time};
559
/// use writeable::assert_try_writeable_eq;
560
///
561
/// // Create an instance that can format abbreviated month, weekday, and day period names:
562
/// let mut names: FixedCalendarDateTimeNames<(), ZoneFieldSet> =
563
///     FixedCalendarDateTimeNames::try_new(locale!("uk").into()).unwrap();
564
///
565
/// // Load the names for generic short:
566
/// names.include_time_zone_essentials().unwrap();
567
/// names.include_time_zone_generic_short_names().unwrap();
568
/// names.include_time_zone_location_names().unwrap();
569
///
570
/// // The same functions can be called a second time (nothing will happen):
571
/// names.include_time_zone_essentials().unwrap();
572
/// names.include_time_zone_generic_short_names().unwrap();
573
/// names.include_time_zone_location_names().unwrap();
574
///
575
/// // But loading names for a different zone style does not currently work:
576
/// names.include_time_zone_specific_short_names().unwrap_err();
577
/// ```
578
#[derive(Debug, Clone)]
579
pub struct FixedCalendarDateTimeNames<C, FSet: DateTimeNamesMarker = CompositeDateTimeFieldSet> {
580
    prefs: DateTimeFormatterPreferences,
581
    inner: RawDateTimeNames<FSet>,
582
    _calendar: PhantomData<C>,
583
}
584

585
/// A low-level type that formats datetime patterns with localized names.
586
/// The calendar is chosen in the constructor at runtime.
587
///
588
/// Currently this only supports loading of non-calendar-specific names, but
589
/// additional functions may be added in the future. If you need this, see
590
/// <https://github.com/unicode-org/icu4x/issues/6107>
591
#[derive(Debug, Clone)]
592
pub struct DateTimeNames<FSet: DateTimeNamesMarker> {
593
    inner: FixedCalendarDateTimeNames<(), FSet>,
594
    calendar: AnyCalendar,
595
}
596

597
pub(crate) struct RawDateTimeNames<FSet: DateTimeNamesMarker> {
598
    year_names: <FSet::YearNames as NamesContainer<YearNamesV1, YearNameLength>>::Container,
599
    month_names: <FSet::MonthNames as NamesContainer<MonthNamesV1, MonthNameLength>>::Container,
600
    weekday_names:
601
        <FSet::WeekdayNames as NamesContainer<WeekdayNamesV1, WeekdayNameLength>>::Container,
602
    dayperiod_names:
603
        <FSet::DayPeriodNames as NamesContainer<DayPeriodNamesV1, DayPeriodNameLength>>::Container,
604
    zone_essentials: <FSet::ZoneEssentials as NamesContainer<tz::EssentialsV1, ()>>::Container,
605
    locations_root: <FSet::ZoneLocationsRoot as NamesContainer<tz::LocationsRootV1, ()>>::Container,
606
    locations: <FSet::ZoneLocations as NamesContainer<tz::LocationsV1, ()>>::Container,
607
    exemplars_root:
608
        <FSet::ZoneExemplarsRoot as NamesContainer<tz::ExemplarCitiesRootV1, ()>>::Container,
609
    exemplars: <FSet::ZoneExemplars as NamesContainer<tz::ExemplarCitiesV1, ()>>::Container,
610
    mz_generic_long: <FSet::ZoneGenericLong as NamesContainer<tz::MzGenericLongV1, ()>>::Container,
611
    mz_generic_short:
612
        <FSet::ZoneGenericShort as NamesContainer<tz::MzGenericShortV1, ()>>::Container,
613
    mz_standard_long:
614
        <FSet::ZoneStandardLong as NamesContainer<tz::MzStandardLongV1, ()>>::Container,
615
    mz_specific_long:
616
        <FSet::ZoneSpecificLong as NamesContainer<tz::MzSpecificLongV1, ()>>::Container,
617
    mz_specific_short:
618
        <FSet::ZoneSpecificShort as NamesContainer<tz::MzSpecificShortV1, ()>>::Container,
619
    mz_periods: <FSet::MetazoneLookup as NamesContainer<tz::MzPeriodV1, ()>>::Container,
620
    // TODO(#4340): Make the DecimalFormatter optional
621
    decimal_formatter: Option<DecimalFormatter>,
622
    _marker: PhantomData<FSet>,
623
}
624

625
// Need a custom impl because not all of the associated types impl Debug
626
impl<FSet: DateTimeNamesMarker> fmt::Debug for RawDateTimeNames<FSet> {
627
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
628
        f.debug_struct("RawDateTimeNames")
629
            .field("year_names", &self.year_names)
630
            .field("month_names", &self.month_names)
631
            .field("weekday_names", &self.weekday_names)
632
            .field("dayperiod_names", &self.dayperiod_names)
633
            .field("zone_essentials", &self.zone_essentials)
634
            .field("locations_root", &self.locations_root)
635
            .field("locations", &self.locations)
636
            .field("exemplars_root", &self.exemplars_root)
637
            .field("exemplars", &self.exemplars)
638
            .field("mz_generic_long", &self.mz_generic_long)
639
            .field("mz_generic_short", &self.mz_generic_short)
640
            .field("mz_standard_long", &self.mz_standard_long)
641
            .field("mz_specific_long", &self.mz_specific_long)
642
            .field("mz_specific_short", &self.mz_specific_short)
643
            .field("mz_periods", &self.mz_periods)
644
            .field("decimal_formatter", &self.decimal_formatter)
645
            .finish()
646
    }
647
}
648

649
impl<FSet: DateTimeNamesMarker> Clone for RawDateTimeNames<FSet> {
650
    fn clone(&self) -> Self {
×
651
        Self {
×
652
            year_names: self.year_names.clone(),
×
653
            month_names: self.month_names.clone(),
×
654
            weekday_names: self.weekday_names.clone(),
×
655
            dayperiod_names: self.dayperiod_names.clone(),
×
656
            zone_essentials: self.zone_essentials.clone(),
×
657
            locations_root: self.locations_root.clone(),
×
658
            locations: self.locations.clone(),
×
659
            exemplars_root: self.exemplars_root.clone(),
×
660
            exemplars: self.exemplars.clone(),
×
661
            mz_generic_long: self.mz_generic_long.clone(),
×
662
            mz_generic_short: self.mz_generic_short.clone(),
×
663
            mz_standard_long: self.mz_standard_long.clone(),
×
664
            mz_specific_long: self.mz_specific_long.clone(),
×
665
            mz_specific_short: self.mz_specific_short.clone(),
×
666
            mz_periods: self.mz_periods.clone(),
×
667
            decimal_formatter: self.decimal_formatter.clone(),
×
668
            _marker: PhantomData,
669
        }
×
670
    }
×
671
}
672

673
impl<FSet: DateTimeNamesMarker> RawDateTimeNames<FSet> {
674
    pub(crate) fn cast_into_fset<FSet2: DateTimeNamesFrom<FSet>>(self) -> RawDateTimeNames<FSet2> {
×
675
        RawDateTimeNames {
×
676
            year_names: FSet2::map_year_names(self.year_names),
×
677
            month_names: FSet2::map_month_names(self.month_names),
×
678
            weekday_names: FSet2::map_weekday_names(self.weekday_names),
×
679
            dayperiod_names: FSet2::map_day_period_names(self.dayperiod_names),
×
680
            zone_essentials: FSet2::map_zone_essentials(self.zone_essentials),
×
681
            locations_root: FSet2::map_zone_locations_root(self.locations_root),
×
682
            locations: FSet2::map_zone_locations(self.locations),
×
683
            exemplars_root: FSet2::map_zone_exemplars_root(self.exemplars_root),
×
684
            exemplars: FSet2::map_zone_exemplars(self.exemplars),
×
685
            mz_generic_long: FSet2::map_zone_generic_long(self.mz_generic_long),
×
686
            mz_generic_short: FSet2::map_zone_generic_short(self.mz_generic_short),
×
687
            mz_standard_long: FSet2::map_zone_standard_long(self.mz_standard_long),
×
688
            mz_specific_long: FSet2::map_zone_specific_long(self.mz_specific_long),
×
689
            mz_specific_short: FSet2::map_zone_specific_short(self.mz_specific_short),
×
690
            mz_periods: FSet2::map_metazone_lookup(self.mz_periods),
×
691
            decimal_formatter: self.decimal_formatter,
×
692
            _marker: PhantomData,
693
        }
×
694
    }
×
695
}
696

697
#[derive(Debug, Copy, Clone)]
×
698
pub(crate) struct RawDateTimeNamesBorrowed<'l> {
699
    year_names: OptionalNames<YearNameLength, &'l YearNames<'l>>,
700
    month_names: OptionalNames<MonthNameLength, &'l MonthNames<'l>>,
×
701
    weekday_names: OptionalNames<WeekdayNameLength, &'l LinearNames<'l>>,
×
702
    dayperiod_names: OptionalNames<DayPeriodNameLength, &'l LinearNames<'l>>,
×
703
    zone_essentials: OptionalNames<(), &'l tz::Essentials<'l>>,
×
704
    locations_root: OptionalNames<(), &'l tz::Locations<'l>>,
×
705
    locations: OptionalNames<(), &'l tz::Locations<'l>>,
×
706
    exemplars_root: OptionalNames<(), &'l tz::ExemplarCities<'l>>,
×
707
    exemplars: OptionalNames<(), &'l tz::ExemplarCities<'l>>,
×
708
    mz_generic_long: OptionalNames<(), &'l tz::MzGeneric<'l>>,
×
709
    mz_standard_long: OptionalNames<(), &'l tz::MzGeneric<'l>>,
×
710
    mz_generic_short: OptionalNames<(), &'l tz::MzGeneric<'l>>,
×
711
    mz_specific_long: OptionalNames<(), &'l tz::MzSpecific<'l>>,
×
712
    mz_specific_short: OptionalNames<(), &'l tz::MzSpecific<'l>>,
×
713
    mz_periods: OptionalNames<(), &'l tz::MzPeriod<'l>>,
×
714
    pub(crate) decimal_formatter: Option<&'l DecimalFormatter>,
×
715
}
716

717
impl<C, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
718
    /// Constructor that takes a selected locale and creates an empty instance.
719
    ///
720
    /// For an example, see [`FixedCalendarDateTimeNames`].
721
    ///
722
    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
723
    ///
724
    /// [📚 Help choosing a constructor](icu_provider::constructors)
725
    #[cfg(feature = "compiled_data")]
726
    pub fn try_new(prefs: DateTimeFormatterPreferences) -> Result<Self, DataError> {
37✔
727
        let mut names = Self {
37✔
728
            prefs,
729
            inner: RawDateTimeNames::new_without_number_formatting(),
37✔
730
            _calendar: PhantomData,
731
        };
732
        names.include_decimal_formatter()?;
37✔
733
        Ok(names)
35✔
734
    }
35✔
735

736
    #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::try_new)]
737
    pub fn try_new_unstable<P>(
738
        provider: &P,
739
        prefs: DateTimeFormatterPreferences,
740
    ) -> Result<Self, DataError>
741
    where
742
        P: DataProvider<DecimalSymbolsV1> + DataProvider<DecimalDigitsV1> + ?Sized,
743
    {
744
        let mut names = Self {
745
            prefs,
746
            inner: RawDateTimeNames::new_without_number_formatting(),
747
            _calendar: PhantomData,
748
        };
749
        names.load_decimal_formatter(provider)?;
750
        Ok(names)
751
    }
752

753
    icu_provider::gen_buffer_data_constructors!(
754
        (prefs: DateTimeFormatterPreferences) -> error: DataError,
755
        functions: [
756
            try_new: skip,
757
            try_new_with_buffer_provider,
758
            try_new_unstable,
759
            Self,
760
        ]
761
    );
762

763
    /// Creates a completely empty instance, not even with number formatting.
764
    ///
765
    /// # Examples
766
    ///
767
    /// Errors occur if a number formatter is not loaded but one is required:
768
    ///
769
    /// ```
770
    /// use icu::calendar::Gregorian;
771
    /// use icu::datetime::input::Date;
772
    /// use icu::datetime::parts;
773
    /// use icu::datetime::DateTimeWriteError;
774
    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
775
    /// use icu::datetime::pattern::DateTimePattern;
776
    /// use icu::datetime::fieldsets::enums::DateFieldSet;
777
    /// use icu::locale::locale;
778
    /// use writeable::{Part, assert_try_writeable_parts_eq};
779
    ///
780
    /// // Create an instance that can format only date fields:
781
    /// let names: FixedCalendarDateTimeNames<Gregorian, DateFieldSet> =
782
    ///     FixedCalendarDateTimeNames::new_without_number_formatting(locale!("en").into());
783
    ///
784
    /// // Create a pattern from a pattern string:
785
    /// let pattern_str = "'It is:' y-MM-dd";
786
    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
787
    ///
788
    /// // The pattern string contains lots of numeric symbols,
789
    /// // but we did not load any data!
790
    ///
791
    /// let date = Date::try_new_gregorian(2024, 7, 1).unwrap();
792
    ///
793
    /// // Missing data is filled in on a best-effort basis, and an error is signaled.
794
    /// // (note that the padding is ignored in this fallback mode)
795
    /// assert_try_writeable_parts_eq!(
796
    ///     names.with_pattern_unchecked(&pattern).format(&date),
797
    ///     "It is: 2024-07-01",
798
    ///     Err(DateTimeWriteError::DecimalFormatterNotLoaded),
799
    ///     [
800
    ///         (7, 11, Part::ERROR), // 2024
801
    ///         (7, 11, parts::YEAR), // 2024
802
    ///         (12, 14, Part::ERROR), // 07
803
    ///         (12, 14, parts::MONTH), // 07
804
    ///         (15, 17, Part::ERROR), // 01
805
    ///         (15, 17, parts::DAY), // 01
806
    ///     ]
807
    /// );
808
    /// ```
809
    pub fn new_without_number_formatting(prefs: DateTimeFormatterPreferences) -> Self {
810
        Self {
811
            prefs,
812
            inner: RawDateTimeNames::new_without_number_formatting(),
813
            _calendar: PhantomData,
814
        }
815
    }
816
}
817

818
impl<C: CldrCalendar, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
819
    /// Creates an instance with the names loaded in a [`FixedCalendarDateTimeFormatter`].
820
    ///
821
    /// This function requires passing in the [`DateTimeFormatterPreferences`] because it is not
822
    /// retained in the formatter. Pass the same value or else unexpected behavior may occur.
823
    ///
824
    /// # Examples
825
    ///
826
    /// ```
827
    /// use icu::datetime::input::Date;
828
    /// use icu::datetime::input::{DateTime, Time};
829
    /// use icu::datetime::FixedCalendarDateTimeFormatter;
830
    /// use icu::datetime::fieldsets::{YMD, YMDT};
831
    /// use icu::datetime::pattern::{FixedCalendarDateTimeNames, DayPeriodNameLength};
832
    /// use icu::locale::locale;
833
    /// use writeable::assert_writeable_eq;
834
    ///
835
    /// let prefs = locale!("es-MX").into();
836
    ///
837
    /// let formatter =
838
    ///     FixedCalendarDateTimeFormatter::try_new(
839
    ///         prefs,
840
    ///         YMD::long(),
841
    ///     )
842
    ///     .unwrap();
843
    ///
844
    /// assert_writeable_eq!(
845
    ///     formatter.format(&Date::try_new_gregorian(2025, 2, 13).unwrap()),
846
    ///     "13 de febrero de 2025"
847
    /// );
848
    ///
849
    /// // Change the YMD formatter to a YMDT formatter, after loading day period names.
850
    /// // This assumes that the locale uses Abbreviated names for the given semantic skeleton!
851
    /// let mut names = FixedCalendarDateTimeNames::from_formatter(prefs, formatter).cast_into_fset::<YMDT>();
852
    /// names.include_day_period_names(DayPeriodNameLength::Abbreviated).unwrap();
853
    /// let formatter = names.try_into_formatter(YMDT::long().hm()).unwrap();
854
    ///
855
    /// assert_writeable_eq!(
856
    ///     formatter.format(&DateTime {
857
    ///         date: Date::try_new_gregorian(2025, 2, 13).unwrap(),
858
    ///         time: Time::midnight(),
859
    ///     }),
860
    ///     "13 de febrero de 2025, 12:00 a.m."
861
    /// );
862
    /// ```
863
    pub fn from_formatter(
×
864
        prefs: DateTimeFormatterPreferences,
865
        formatter: FixedCalendarDateTimeFormatter<C, FSet>,
866
    ) -> Self {
867
        Self {
×
868
            prefs,
869
            inner: formatter.names,
×
870
            _calendar: PhantomData,
871
        }
872
    }
×
873

874
    fn from_parts(prefs: DateTimeFormatterPreferences, inner: RawDateTimeNames<FSet>) -> Self {
×
875
        Self {
×
876
            prefs,
877
            inner,
878
            _calendar: PhantomData,
879
        }
880
    }
×
881
}
882

883
impl<C: CldrCalendar, FSet: DateTimeMarkers> FixedCalendarDateTimeNames<C, FSet>
884
where
885
    FSet::D: TypedDateDataMarkers<C>,
886
    FSet::T: TimeMarkers,
887
    FSet::Z: ZoneMarkers,
888
    FSet: GetField<CompositeFieldSet>,
889
{
890
    /// Loads a pattern for the given field set and returns a [`FixedCalendarDateTimeFormatter`].
891
    ///
892
    /// The names in the current [`FixedCalendarDateTimeNames`] _must_ be sufficient for the field set.
893
    /// If not, the input object will be returned with an error.
894
    ///
895
    /// # Examples
896
    ///
897
    /// ```
898
    /// use icu::datetime::fieldsets::T;
899
    /// use icu::datetime::input::Time;
900
    /// use icu::datetime::pattern::{
901
    ///     DayPeriodNameLength, FixedCalendarDateTimeNames,
902
    /// };
903
    /// use icu::locale::locale;
904
    /// use writeable::assert_writeable_eq;
905
    ///
906
    /// let names =
907
    ///     FixedCalendarDateTimeNames::<(), _>::new_without_number_formatting(
908
    ///         locale!("es-MX").into(),
909
    ///     );
910
    ///
911
    /// let field_set = T::long().hm();
912
    ///
913
    /// // Cannot convert yet: no names are loaded
914
    /// let mut names = names.try_into_formatter(field_set).unwrap_err().1;
915
    ///
916
    /// // Load the data we need:
917
    /// names
918
    ///     .include_day_period_names(DayPeriodNameLength::Abbreviated)
919
    ///     .unwrap();
920
    /// names.include_decimal_formatter().unwrap();
921
    ///
922
    /// // Now the conversion is successful:
923
    /// let formatter = names.try_into_formatter(field_set).unwrap();
924
    ///
925
    /// assert_writeable_eq!(formatter.format(&Time::midnight()), "12:00 a.m.");
926
    /// ```
927
    #[allow(clippy::result_large_err)] // returning self as the error
928
    #[cfg(feature = "compiled_data")]
929
    pub fn try_into_formatter(
×
930
        self,
931
        field_set: FSet,
932
    ) -> Result<FixedCalendarDateTimeFormatter<C, FSet>, (DateTimeFormatterLoadError, Self)>
933
    where
934
        crate::provider::Baked: AllFixedCalendarPatternDataMarkers<C, FSet>,
935
    {
936
        FixedCalendarDateTimeFormatter::try_new_internal_with_names(
×
937
            &crate::provider::Baked,
938
            &EmptyDataProvider,
939
            &ExternalLoaderUnstable(&EmptyDataProvider), // for decimals only
940
            self.prefs,
×
941
            field_set.get_field(),
×
942
            self.inner,
×
943
        )
944
        .map_err(|e| (e.0, Self::from_parts(self.prefs, e.1)))
×
945
    }
×
946

947
    #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::try_into_formatter)]
948
    #[allow(clippy::result_large_err)] // returning self as the error
949
    pub fn try_into_formatter_unstable<P>(
950
        self,
951
        provider: &P,
952
        field_set: FSet,
953
    ) -> Result<FixedCalendarDateTimeFormatter<C, FSet>, (DateTimeFormatterLoadError, Self)>
954
    where
955
        P: AllFixedCalendarPatternDataMarkers<C, FSet> + ?Sized,
956
    {
957
        FixedCalendarDateTimeFormatter::try_new_internal_with_names(
958
            provider,
959
            &EmptyDataProvider,
960
            &ExternalLoaderUnstable(&EmptyDataProvider), // for decimals only
961
            self.prefs,
962
            field_set.get_field(),
963
            self.inner,
964
        )
965
        .map_err(|e| (e.0, Self::from_parts(self.prefs, e.1)))
966
    }
967

968
    #[doc = icu_provider::gen_buffer_unstable_docs!(BUFFER, Self::try_into_formatter)]
969
    #[allow(clippy::result_large_err)] // returning self as the error
970
    #[cfg(feature = "serde")]
971
    pub fn try_into_formatter_with_buffer_provider<P>(
×
972
        self,
973
        provider: &P,
974
        field_set: FSet,
975
    ) -> Result<FixedCalendarDateTimeFormatter<C, FSet>, (DateTimeFormatterLoadError, Self)>
976
    where
977
        P: BufferProvider + ?Sized,
978
    {
979
        FixedCalendarDateTimeFormatter::try_new_internal_with_names(
×
980
            &provider.as_deserializing(),
×
981
            &EmptyDataProvider,
982
            &ExternalLoaderUnstable(&EmptyDataProvider), // for decimals only
983
            self.prefs,
×
984
            field_set.get_field(),
×
985
            self.inner,
×
986
        )
987
        .map_err(|e| (e.0, Self::from_parts(self.prefs, e.1)))
×
988
    }
×
989
}
990

991
impl<FSet: DateTimeNamesMarker> DateTimeNames<FSet> {
992
    /// Creates a completely empty instance, not even with number formatting.
993
    pub fn new_without_number_formatting(
994
        prefs: DateTimeFormatterPreferences,
995
        calendar: AnyCalendar,
996
    ) -> Self {
997
        Self {
998
            inner: FixedCalendarDateTimeNames::new_without_number_formatting(prefs),
999
            calendar,
1000
        }
1001
    }
1002

1003
    /// Creates an instance with the names and calendar loaded in a [`DateTimeFormatter`].
1004
    ///
1005
    /// This function requires passing in the [`DateTimeFormatterPreferences`] because it is not
1006
    /// retained in the formatter. Pass the same value or else unexpected behavior may occur.
1007
    ///
1008
    /// # Examples
1009
    ///
1010
    /// ```
1011
    /// use icu::datetime::input::Date;
1012
    /// use icu::datetime::input::{DateTime, Time};
1013
    /// use icu::datetime::DateTimeFormatter;
1014
    /// use icu::datetime::fieldsets::{YMD, YMDT};
1015
    /// use icu::datetime::pattern::{DateTimeNames, DayPeriodNameLength};
1016
    /// use icu::locale::locale;
1017
    /// use writeable::assert_writeable_eq;
1018
    ///
1019
    /// let prefs = locale!("es-MX").into();
1020
    ///
1021
    /// let formatter =
1022
    ///     DateTimeFormatter::try_new(
1023
    ///         prefs,
1024
    ///         YMD::long(),
1025
    ///     )
1026
    ///     .unwrap();
1027
    ///
1028
    /// assert_writeable_eq!(
1029
    ///     formatter.format(&Date::try_new_iso(2025, 2, 13).unwrap()),
1030
    ///     "13 de febrero de 2025"
1031
    /// );
1032
    ///
1033
    /// // Change the YMD formatter to a YMDT formatter, after loading day period names.
1034
    /// // This assumes that the locale uses Abbreviated names for the given semantic skeleton!
1035
    /// let mut names = DateTimeNames::from_formatter(prefs, formatter).cast_into_fset::<YMDT>();
1036
    /// names.as_mut().include_day_period_names(DayPeriodNameLength::Abbreviated).unwrap();
1037
    /// let formatter = names.try_into_formatter(YMDT::long().hm()).unwrap();
1038
    ///
1039
    /// assert_writeable_eq!(
1040
    ///     formatter.format(&DateTime {
1041
    ///         date: Date::try_new_iso(2025, 2, 13).unwrap(),
1042
    ///         time: Time::midnight(),
1043
    ///     }),
1044
    ///     "13 de febrero de 2025, 12:00 a.m."
1045
    /// );
1046
    /// ```
1047
    pub fn from_formatter(
×
1048
        prefs: DateTimeFormatterPreferences,
1049
        formatter: DateTimeFormatter<FSet>,
1050
    ) -> Self {
1051
        Self::from_parts(prefs, (formatter.calendar, formatter.names))
×
1052
    }
×
1053

1054
    fn from_parts(
×
1055
        prefs: DateTimeFormatterPreferences,
1056
        parts: (AnyCalendar, RawDateTimeNames<FSet>),
1057
    ) -> Self {
1058
        Self {
×
1059
            inner: FixedCalendarDateTimeNames {
×
1060
                prefs,
1061
                inner: parts.1,
×
1062
                _calendar: PhantomData,
1063
            },
1064
            calendar: parts.0,
×
1065
        }
1066
    }
×
1067
}
1068

1069
impl<FSet: DateTimeMarkers> DateTimeNames<FSet>
1070
where
1071
    FSet::D: DateDataMarkers,
1072
    FSet::T: TimeMarkers,
1073
    FSet::Z: ZoneMarkers,
1074
    FSet: GetField<CompositeFieldSet>,
1075
{
1076
    /// Loads a pattern for the given field set and returns a [`DateTimeFormatter`].
1077
    ///
1078
    /// The names in the current [`DateTimeNames`] _must_ be sufficient for the field set.
1079
    /// If not, the input object will be returned with an error.
1080
    ///
1081
    /// # Examples
1082
    ///
1083
    /// ```
1084
    /// use icu::calendar::AnyCalendar;
1085
    /// use icu::datetime::fieldsets::T;
1086
    /// use icu::datetime::input::Time;
1087
    /// use icu::datetime::pattern::{DateTimeNames, DayPeriodNameLength};
1088
    /// use icu::locale::locale;
1089
    /// use writeable::assert_writeable_eq;
1090
    ///
1091
    /// let names = DateTimeNames::new_without_number_formatting(
1092
    ///     locale!("es-MX").into(),
1093
    ///     AnyCalendar::try_new(locale!("es-MX").into()).unwrap(),
1094
    /// );
1095
    ///
1096
    /// let field_set = T::long().hm();
1097
    ///
1098
    /// // Cannot convert yet: no names are loaded
1099
    /// let mut names = names.try_into_formatter(field_set).unwrap_err().1;
1100
    ///
1101
    /// // Load the data we need:
1102
    /// names
1103
    ///     .as_mut()
1104
    ///     .include_day_period_names(DayPeriodNameLength::Abbreviated)
1105
    ///     .unwrap();
1106
    /// names.as_mut().include_decimal_formatter().unwrap();
1107
    ///
1108
    /// // Now the conversion is successful:
1109
    /// let formatter = names.try_into_formatter(field_set).unwrap();
1110
    ///
1111
    /// assert_writeable_eq!(formatter.format(&Time::midnight()), "12:00 a.m.");
1112
    /// ```
1113
    #[allow(clippy::result_large_err)] // returning self as the error
1114
    #[cfg(feature = "compiled_data")]
1115
    pub fn try_into_formatter(
×
1116
        self,
1117
        field_set: FSet,
1118
    ) -> Result<DateTimeFormatter<FSet>, (DateTimeFormatterLoadError, Self)>
1119
    where
1120
        crate::provider::Baked: AllAnyCalendarPatternDataMarkers<FSet>,
1121
    {
1122
        DateTimeFormatter::try_new_internal_with_calendar_and_names(
×
1123
            &crate::provider::Baked,
1124
            &EmptyDataProvider,
1125
            &ExternalLoaderUnstable(&EmptyDataProvider), // for decimals only
1126
            self.inner.prefs,
×
1127
            field_set.get_field(),
×
1128
            self.calendar,
×
1129
            self.inner.inner,
×
1130
        )
1131
        .map_err(|e| (e.0, Self::from_parts(self.inner.prefs, e.1)))
×
1132
    }
×
1133

1134
    #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::try_into_formatter)]
1135
    #[allow(clippy::result_large_err)] // returning self as the error
1136
    pub fn try_into_formatter_unstable<P>(
1137
        self,
1138
        provider: &P,
1139
        field_set: FSet,
1140
    ) -> Result<DateTimeFormatter<FSet>, (DateTimeFormatterLoadError, Self)>
1141
    where
1142
        P: AllAnyCalendarPatternDataMarkers<FSet> + ?Sized,
1143
    {
1144
        DateTimeFormatter::try_new_internal_with_calendar_and_names(
1145
            provider,
1146
            &EmptyDataProvider,
1147
            &ExternalLoaderUnstable(&EmptyDataProvider), // for decimals only
1148
            self.inner.prefs,
1149
            field_set.get_field(),
1150
            self.calendar,
1151
            self.inner.inner,
1152
        )
1153
        .map_err(|e| (e.0, Self::from_parts(self.inner.prefs, e.1)))
1154
    }
1155

1156
    #[doc = icu_provider::gen_buffer_unstable_docs!(BUFFER, Self::try_into_formatter)]
1157
    #[allow(clippy::result_large_err)] // returning self as the error
1158
    #[cfg(feature = "serde")]
1159
    pub fn try_into_formatter_with_buffer_provider<P>(
×
1160
        self,
1161
        provider: &P,
1162
        field_set: FSet,
1163
    ) -> Result<DateTimeFormatter<FSet>, (DateTimeFormatterLoadError, Self)>
1164
    where
1165
        P: BufferProvider + ?Sized,
1166
    {
1167
        DateTimeFormatter::try_new_internal_with_calendar_and_names(
×
1168
            &provider.as_deserializing(),
×
1169
            &EmptyDataProvider,
1170
            &ExternalLoaderUnstable(&EmptyDataProvider), // for decimals only
1171
            self.inner.prefs,
×
1172
            field_set.get_field(),
×
1173
            self.calendar,
×
1174
            self.inner.inner,
×
1175
        )
1176
        .map_err(|e| (e.0, Self::from_parts(self.inner.prefs, e.1)))
×
1177
    }
×
1178
}
1179

1180
impl<FSet: DateTimeNamesMarker> AsRef<FixedCalendarDateTimeNames<(), FSet>>
1181
    for DateTimeNames<FSet>
1182
{
1183
    fn as_ref(&self) -> &FixedCalendarDateTimeNames<(), FSet> {
1184
        &self.inner
1185
    }
1186
}
1187

1188
impl<FSet: DateTimeNamesMarker> AsMut<FixedCalendarDateTimeNames<(), FSet>>
1189
    for DateTimeNames<FSet>
1190
{
1191
    fn as_mut(&mut self) -> &mut FixedCalendarDateTimeNames<(), FSet> {
×
1192
        &mut self.inner
1193
    }
×
1194
}
1195

1196
impl<C: CldrCalendar, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
1197
    /// Loads year (era or cycle) names for the specified length.
1198
    ///
1199
    /// Does not support multiple field symbols or lengths. See #4337
1200
    pub fn load_year_names<P>(
6✔
1201
        &mut self,
1202
        provider: &P,
1203
        length: YearNameLength,
1204
    ) -> Result<&mut Self, PatternLoadError>
1205
    where
1206
        P: DataProvider<C::YearNamesV1> + ?Sized,
1207
    {
1208
        self.inner.load_year_names(
12✔
1209
            &C::YearNamesV1::bind(provider),
6✔
1210
            self.prefs,
6✔
1211
            length,
1212
            length.to_approximate_error_field(),
6✔
1213
        )?;
×
1214
        Ok(self)
6✔
1215
    }
6✔
1216

1217
    /// Includes year (era or cycle) names for the specified length.
1218
    ///
1219
    /// Does not support multiple field symbols or lengths. See #4337
1220
    ///
1221
    /// # Examples
1222
    ///
1223
    /// ```
1224
    /// use icu::calendar::Gregorian;
1225
    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1226
    /// use icu::datetime::pattern::PatternLoadError;
1227
    /// use icu::datetime::pattern::YearNameLength;
1228
    /// use icu::locale::locale;
1229
    ///
1230
    /// let mut names =
1231
    ///     FixedCalendarDateTimeNames::<Gregorian>::try_new(locale!("und").into())
1232
    ///         .unwrap();
1233
    ///
1234
    /// // First length is successful:
1235
    /// names.include_year_names(YearNameLength::Wide).unwrap();
1236
    ///
1237
    /// // Attempting to load the first length a second time will succeed:
1238
    /// names.include_year_names(YearNameLength::Wide).unwrap();
1239
    ///
1240
    /// // But loading a new length fails:
1241
    /// assert!(matches!(
1242
    ///     names.include_year_names(YearNameLength::Abbreviated),
1243
    ///     Err(PatternLoadError::ConflictingField(_))
1244
    /// ));
1245
    /// ```
1246
    #[cfg(feature = "compiled_data")]
1247
    pub fn include_year_names(
1248
        &mut self,
1249
        length: YearNameLength,
1250
    ) -> Result<&mut Self, PatternLoadError>
1251
    where
1252
        crate::provider::Baked: icu_provider::DataProvider<<C as CldrCalendar>::YearNamesV1>,
1253
    {
1254
        self.load_year_names(&crate::provider::Baked, length)
1255
    }
1256

1257
    /// Loads month names for the specified symbol and length.
1258
    ///
1259
    /// Does not support multiple field symbols or lengths. See #4337
1260
    pub fn load_month_names<P>(
7✔
1261
        &mut self,
1262
        provider: &P,
1263
        length: MonthNameLength,
1264
    ) -> Result<&mut Self, PatternLoadError>
1265
    where
1266
        P: DataProvider<C::MonthNamesV1> + ?Sized,
1267
    {
1268
        self.inner.load_month_names(
14✔
1269
            &C::MonthNamesV1::bind(provider),
7✔
1270
            self.prefs,
7✔
1271
            length,
1272
            length.to_approximate_error_field(),
7✔
1273
        )?;
×
1274
        Ok(self)
7✔
1275
    }
7✔
1276

1277
    /// Includes month names for the specified symbol and length.
1278
    ///
1279
    /// Does not support multiple field symbols or lengths. See #4337
1280
    ///
1281
    /// # Examples
1282
    ///
1283
    /// ```
1284
    /// use icu::calendar::Gregorian;
1285
    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1286
    /// use icu::datetime::pattern::MonthNameLength;
1287
    /// use icu::datetime::pattern::PatternLoadError;
1288
    /// use icu::locale::locale;
1289
    ///
1290
    /// let mut names =
1291
    ///     FixedCalendarDateTimeNames::<Gregorian>::try_new(locale!("und").into())
1292
    ///         .unwrap();
1293
    ///
1294
    /// // First length is successful:
1295
    /// names.include_month_names(MonthNameLength::Wide).unwrap();
1296
    ///
1297
    /// // Attempting to load the first length a second time will succeed:
1298
    /// names.include_month_names(MonthNameLength::Wide).unwrap();
1299
    ///
1300
    /// // But loading a new symbol or length fails:
1301
    /// assert!(matches!(
1302
    ///     names.include_month_names(MonthNameLength::StandaloneWide),
1303
    ///     Err(PatternLoadError::ConflictingField(_))
1304
    /// ));
1305
    /// assert!(matches!(
1306
    ///     names.include_month_names(MonthNameLength::Abbreviated),
1307
    ///     Err(PatternLoadError::ConflictingField(_))
1308
    /// ));
1309
    /// ```
1310
    #[cfg(feature = "compiled_data")]
1311
    pub fn include_month_names(
1312
        &mut self,
1313
        length: MonthNameLength,
1314
    ) -> Result<&mut Self, PatternLoadError>
1315
    where
1316
        crate::provider::Baked: icu_provider::DataProvider<<C as CldrCalendar>::MonthNamesV1>,
1317
    {
1318
        self.load_month_names(&crate::provider::Baked, length)
1319
    }
1320
}
1321

1322
impl<C, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
1323
    /// Loads day period names for the specified length.
1324
    ///
1325
    /// Does not support multiple field symbols or lengths. See #4337
1326
    pub fn load_day_period_names<P>(
11✔
1327
        &mut self,
1328
        provider: &P,
1329
        length: DayPeriodNameLength,
1330
    ) -> Result<&mut Self, PatternLoadError>
1331
    where
1332
        P: DataProvider<DayPeriodNamesV1> + ?Sized,
1333
    {
1334
        let provider = DayPeriodNamesV1::bind(provider);
11✔
1335
        self.inner.load_day_period_names(
22✔
1336
            &provider,
1337
            self.prefs,
11✔
1338
            length,
1339
            length.to_approximate_error_field(),
11✔
1340
        )?;
×
1341
        Ok(self)
11✔
1342
    }
11✔
1343

1344
    /// Includes day period names for the specified length.
1345
    ///
1346
    /// Does not support multiple field symbols or lengths. See #4337
1347
    ///
1348
    /// # Examples
1349
    ///
1350
    /// ```
1351
    /// use icu::calendar::Gregorian;
1352
    /// use icu::datetime::pattern::DayPeriodNameLength;
1353
    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1354
    /// use icu::datetime::pattern::PatternLoadError;
1355
    /// use icu::locale::locale;
1356
    ///
1357
    /// let mut names =
1358
    ///     FixedCalendarDateTimeNames::<Gregorian>::try_new(locale!("und").into())
1359
    ///         .unwrap();
1360
    ///
1361
    /// // First length is successful:
1362
    /// names
1363
    ///     .include_day_period_names(DayPeriodNameLength::Wide)
1364
    ///     .unwrap();
1365
    ///
1366
    /// // Attempting to load the first length a second time will succeed:
1367
    /// names
1368
    ///     .include_day_period_names(DayPeriodNameLength::Wide)
1369
    ///     .unwrap();
1370
    ///
1371
    /// // But loading a new length fails:
1372
    /// assert!(matches!(
1373
    ///     names.include_day_period_names(DayPeriodNameLength::Abbreviated),
1374
    ///     Err(PatternLoadError::ConflictingField(_))
1375
    /// ));
1376
    /// ```
1377
    #[cfg(feature = "compiled_data")]
1378
    pub fn include_day_period_names(
1379
        &mut self,
1380
        length: DayPeriodNameLength,
1381
    ) -> Result<&mut Self, PatternLoadError> {
1382
        self.load_day_period_names(&crate::provider::Baked, length)
1383
    }
1384

1385
    /// Loads weekday names for the specified symbol and length.
1386
    ///
1387
    /// Does not support multiple field symbols or lengths. See #4337
1388
    pub fn load_weekday_names<P>(
15✔
1389
        &mut self,
1390
        provider: &P,
1391
        length: WeekdayNameLength,
1392
    ) -> Result<&mut Self, PatternLoadError>
1393
    where
1394
        P: DataProvider<WeekdayNamesV1> + ?Sized,
1395
    {
1396
        self.inner.load_weekday_names(
30✔
1397
            &WeekdayNamesV1::bind(provider),
15✔
1398
            self.prefs,
15✔
1399
            length,
1400
            length.to_approximate_error_field(),
15✔
1401
        )?;
×
1402
        Ok(self)
15✔
1403
    }
15✔
1404

1405
    /// Includes weekday names for the specified symbol and length.
1406
    ///
1407
    /// Does not support multiple field symbols or lengths. See #4337
1408
    ///
1409
    /// # Examples
1410
    ///
1411
    /// ```
1412
    /// use icu::calendar::Gregorian;
1413
    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1414
    /// use icu::datetime::pattern::PatternLoadError;
1415
    /// use icu::datetime::pattern::WeekdayNameLength;
1416
    /// use icu::locale::locale;
1417
    ///
1418
    /// let mut names =
1419
    ///     FixedCalendarDateTimeNames::<Gregorian>::try_new(locale!("und").into())
1420
    ///         .unwrap();
1421
    ///
1422
    /// // First length is successful:
1423
    /// names
1424
    ///     .include_weekday_names(WeekdayNameLength::Wide)
1425
    ///     .unwrap();
1426
    ///
1427
    /// // Attempting to load the first length a second time will succeed:
1428
    /// names
1429
    ///     .include_weekday_names(WeekdayNameLength::Wide)
1430
    ///     .unwrap();
1431
    ///
1432
    /// // But loading a new symbol or length fails:
1433
    /// assert!(matches!(
1434
    ///     names.include_weekday_names(WeekdayNameLength::StandaloneWide),
1435
    ///     Err(PatternLoadError::ConflictingField(_))
1436
    /// ));
1437
    /// assert!(matches!(
1438
    ///     names.include_weekday_names(WeekdayNameLength::Abbreviated),
1439
    ///     Err(PatternLoadError::ConflictingField(_))
1440
    /// ));
1441
    /// ```
1442
    #[cfg(feature = "compiled_data")]
1443
    pub fn include_weekday_names(
1444
        &mut self,
1445
        length: WeekdayNameLength,
1446
    ) -> Result<&mut Self, PatternLoadError> {
1447
        self.load_weekday_names(&crate::provider::Baked, length)
1448
    }
1449

1450
    /// Loads shared essential patterns for time zone formatting.
1451
    pub fn load_time_zone_essentials<P>(
1452
        &mut self,
1453
        provider: &P,
1454
    ) -> Result<&mut Self, PatternLoadError>
1455
    where
1456
        P: DataProvider<tz::EssentialsV1> + ?Sized,
1457
    {
1458
        self.inner
1459
            .load_time_zone_essentials(&tz::EssentialsV1::bind(provider), self.prefs)?;
1460
        Ok(self)
1461
    }
1462

1463
    /// Includes shared essential patterns for time zone formatting.
1464
    ///
1465
    /// This data should always be loaded when performing time zone formatting.
1466
    /// By itself, it allows localized offset formats.
1467
    ///
1468
    /// # Examples
1469
    ///
1470
    /// ```
1471
    /// use icu::calendar::Gregorian;
1472
    /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
1473
    /// use icu::datetime::input::ZonedDateTime;
1474
    /// use icu::datetime::pattern::DateTimePattern;
1475
    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1476
    /// use icu::locale::locale;
1477
    /// use icu::time::zone::{IanaParser, VariantOffsetsCalculator};
1478
    /// use writeable::assert_try_writeable_eq;
1479
    ///
1480
    /// let mut zone_london_winter = ZonedDateTime::try_from_str(
1481
    ///     "2024-01-01T00:00:00+00:00[Europe/London]",
1482
    ///     Gregorian,
1483
    ///     IanaParser::new(),
1484
    ///     VariantOffsetsCalculator::new(),
1485
    /// )
1486
    /// .unwrap()
1487
    /// .zone;
1488
    /// let mut zone_london_summer = ZonedDateTime::try_from_str(
1489
    ///     "2024-07-01T00:00:00+01:00[Europe/London]",
1490
    ///     Gregorian,
1491
    ///     IanaParser::new(),
1492
    ///     VariantOffsetsCalculator::new(),
1493
    /// )
1494
    /// .unwrap()
1495
    /// .zone;
1496
    ///
1497
    /// let mut names =
1498
    ///     FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
1499
    ///         locale!("en-GB").into(),
1500
    ///     )
1501
    ///     .unwrap();
1502
    ///
1503
    /// names.include_time_zone_essentials().unwrap();
1504
    ///
1505
    /// // Create a pattern with symbol `OOOO`:
1506
    /// let pattern_str = "'Your time zone is:' OOOO";
1507
    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1508
    ///
1509
    /// assert_try_writeable_eq!(
1510
    ///     names
1511
    ///         .with_pattern_unchecked(&pattern)
1512
    ///         .format(&zone_london_winter),
1513
    ///     "Your time zone is: GMT+00:00",
1514
    /// );
1515
    /// assert_try_writeable_eq!(
1516
    ///     names
1517
    ///         .with_pattern_unchecked(&pattern)
1518
    ///         .format(&zone_london_summer),
1519
    ///     "Your time zone is: GMT+01:00",
1520
    /// );
1521
    ///
1522
    /// // Now try `V`:
1523
    /// let pattern_str = "'Your time zone is:' V";
1524
    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1525
    ///
1526
    /// assert_try_writeable_eq!(
1527
    ///     names
1528
    ///         .with_pattern_unchecked(&pattern)
1529
    ///         .format(&zone_london_winter),
1530
    ///     "Your time zone is: gblon",
1531
    /// );
1532
    ///
1533
    /// // Now try `Z`:
1534
    /// let pattern_str = "'Your time zone is:' Z";
1535
    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1536
    ///
1537
    /// assert_try_writeable_eq!(
1538
    ///     names
1539
    ///         .with_pattern_unchecked(&pattern)
1540
    ///         .format(&zone_london_winter),
1541
    ///     "Your time zone is: +0000",
1542
    /// );
1543
    ///
1544
    /// // Now try `ZZZZZ`:
1545
    /// let pattern_str = "'Your time zone is:' ZZZZZ";
1546
    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1547
    ///
1548
    /// assert_try_writeable_eq!(
1549
    ///     names
1550
    ///         .with_pattern_unchecked(&pattern)
1551
    ///         .format(&zone_london_winter),
1552
    ///     "Your time zone is: Z",
1553
    /// );
1554
    /// assert_try_writeable_eq!(
1555
    ///     names
1556
    ///         .with_pattern_unchecked(&pattern)
1557
    ///         .format(&zone_london_summer),
1558
    ///     "Your time zone is: +01:00",
1559
    /// );
1560
    /// ```
1561
    #[cfg(feature = "compiled_data")]
1562
    pub fn include_time_zone_essentials(&mut self) -> Result<&mut Self, PatternLoadError> {
1563
        self.load_time_zone_essentials(&crate::provider::Baked)
1564
    }
1565

1566
    /// Loads location names for time zone formatting.
1567
    pub fn load_time_zone_location_names<P>(
1568
        &mut self,
1569
        provider: &P,
1570
    ) -> Result<&mut Self, PatternLoadError>
1571
    where
1572
        P: DataProvider<tz::LocationsV1> + DataProvider<tz::LocationsRootV1> + ?Sized,
1573
    {
1574
        self.inner.load_time_zone_location_names(
1575
            &tz::LocationsV1::bind(provider),
1576
            &tz::LocationsRootV1::bind(provider),
1577
            self.prefs,
1578
        )?;
1579
        Ok(self)
1580
    }
1581

1582
    /// Includes location names for time zone formatting.
1583
    ///
1584
    /// Important: When performing manual time zone data loading, in addition to the
1585
    /// specific time zone format data, also call either:
1586
    ///
1587
    /// - [`FixedCalendarDateTimeNames::include_time_zone_essentials`]
1588
    /// - [`FixedCalendarDateTimeNames::load_time_zone_essentials`]
1589
    ///
1590
    /// # Examples
1591
    ///
1592
    /// ```
1593
    /// use icu::calendar::Gregorian;
1594
    /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
1595
    /// use icu::datetime::input::ZonedDateTime;
1596
    /// use icu::datetime::pattern::DateTimePattern;
1597
    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1598
    /// use icu::locale::locale;
1599
    /// use icu::time::zone::{IanaParser, VariantOffsetsCalculator};
1600
    /// use writeable::assert_try_writeable_eq;
1601
    ///
1602
    /// let mut zone_london_winter = ZonedDateTime::try_from_str(
1603
    ///     "2024-01-01T00:00:00+00:00[Europe/London]",
1604
    ///     Gregorian,
1605
    ///     IanaParser::new(),
1606
    ///     VariantOffsetsCalculator::new(),
1607
    /// )
1608
    /// .unwrap()
1609
    /// .zone;
1610
    ///
1611
    /// let mut names =
1612
    ///     FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
1613
    ///         locale!("en-GB").into(),
1614
    ///     )
1615
    ///     .unwrap();
1616
    ///
1617
    /// names.include_time_zone_essentials().unwrap();
1618
    /// names.include_time_zone_location_names().unwrap();
1619
    ///
1620
    /// // Try `VVVV`:
1621
    /// let pattern_str = "'Your time zone is:' VVVV";
1622
    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1623
    ///
1624
    /// assert_try_writeable_eq!(
1625
    ///     names
1626
    ///         .with_pattern_unchecked(&pattern)
1627
    ///         .format(&zone_london_winter),
1628
    ///     "Your time zone is: UK Time",
1629
    /// );
1630
    /// ```
1631
    #[cfg(feature = "compiled_data")]
1632
    pub fn include_time_zone_location_names(&mut self) -> Result<&mut Self, PatternLoadError> {
1633
        self.load_time_zone_location_names(&crate::provider::Baked)
1634
    }
1635

1636
    /// Loads exemplar city names for time zone formatting.
1637
    pub fn load_time_zone_exemplar_city_names<P>(
1638
        &mut self,
1639
        provider: &P,
1640
    ) -> Result<&mut Self, PatternLoadError>
1641
    where
1642
        P: DataProvider<tz::ExemplarCitiesV1> + DataProvider<tz::ExemplarCitiesRootV1> + ?Sized,
1643
    {
1644
        self.inner.load_time_zone_exemplar_city_names(
1645
            &tz::ExemplarCitiesV1::bind(provider),
1646
            &tz::ExemplarCitiesRootV1::bind(provider),
1647
            self.prefs,
1648
        )?;
1649
        Ok(self)
1650
    }
1651

1652
    /// Includes exemplar city names for time zone formatting.
1653
    ///
1654
    /// Important: The `VVV` format requires location data in addition to exemplar
1655
    /// city data. Also call either:
1656
    ///
1657
    /// - [`FixedCalendarDateTimeNames::include_time_zone_location_names`]
1658
    /// - [`FixedCalendarDateTimeNames::load_time_zone_location_names`]
1659
    ///
1660
    /// # Examples
1661
    ///
1662
    /// ```
1663
    /// use icu::calendar::Gregorian;
1664
    /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
1665
    /// use icu::datetime::input::ZonedDateTime;
1666
    /// use icu::datetime::pattern::DateTimePattern;
1667
    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1668
    /// use icu::locale::locale;
1669
    /// use icu::time::zone::{IanaParser, VariantOffsetsCalculator};
1670
    /// use writeable::assert_try_writeable_eq;
1671
    ///
1672
    /// let mut zone_london_winter = ZonedDateTime::try_from_str(
1673
    ///     "2024-01-01T00:00:00+00:00[Europe/London]",
1674
    ///     Gregorian,
1675
    ///     IanaParser::new(),
1676
    ///     VariantOffsetsCalculator::new(),
1677
    /// )
1678
    /// .unwrap()
1679
    /// .zone;
1680
    ///
1681
    /// let mut names =
1682
    ///     FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
1683
    ///         locale!("en-GB").into(),
1684
    ///     )
1685
    ///     .unwrap();
1686
    ///
1687
    /// names.include_time_zone_location_names().unwrap();
1688
    /// names.include_time_zone_exemplar_city_names().unwrap();
1689
    ///
1690
    /// // Try `VVVV`:
1691
    /// let pattern_str = "'Your time zone is:' VVV";
1692
    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1693
    ///
1694
    /// assert_try_writeable_eq!(
1695
    ///     names
1696
    ///         .with_pattern_unchecked(&pattern)
1697
    ///         .format(&zone_london_winter),
1698
    ///     "Your time zone is: London",
1699
    /// );
1700
    /// ```
1701
    #[cfg(feature = "compiled_data")]
1702
    pub fn include_time_zone_exemplar_city_names(&mut self) -> Result<&mut Self, PatternLoadError> {
1703
        self.load_time_zone_exemplar_city_names(&crate::provider::Baked)
1704
    }
1705

1706
    /// Loads generic non-location long time zone names.
1707
    pub fn load_time_zone_generic_long_names<P>(
1708
        &mut self,
1709
        provider: &P,
1710
    ) -> Result<&mut Self, PatternLoadError>
1711
    where
1712
        P: DataProvider<tz::MzGenericLongV1>
1713
            + DataProvider<tz::MzStandardLongV1>
1714
            + DataProvider<tz::MzPeriodV1>
1715
            + ?Sized,
1716
    {
1717
        self.inner.load_time_zone_generic_long_names(
1718
            &tz::MzGenericLongV1::bind(provider),
1719
            &tz::MzStandardLongV1::bind(provider),
1720
            &tz::MzPeriodV1::bind(provider),
1721
            self.prefs,
1722
        )?;
1723
        Ok(self)
1724
    }
1725

1726
    /// Includes generic non-location long time zone names.
1727
    ///
1728
    /// Important: When performing manual time zone data loading, in addition to the
1729
    /// specific time zone format data, also call either:
1730
    ///
1731
    /// - [`FixedCalendarDateTimeNames::include_time_zone_essentials`]
1732
    /// - [`FixedCalendarDateTimeNames::load_time_zone_essentials`]
1733
    ///
1734
    /// # Examples
1735
    ///
1736
    /// ```
1737
    /// use icu::calendar::Gregorian;
1738
    /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
1739
    /// use icu::datetime::input::ZonedDateTime;
1740
    /// use icu::datetime::pattern::DateTimePattern;
1741
    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1742
    /// use icu::locale::locale;
1743
    /// use icu::time::zone::{IanaParser, VariantOffsetsCalculator};
1744
    /// use writeable::assert_try_writeable_eq;
1745
    ///
1746
    /// let mut zone_london_winter = ZonedDateTime::try_from_str(
1747
    ///     "2024-01-01T00:00:00+00:00[Europe/London]",
1748
    ///     Gregorian,
1749
    ///     IanaParser::new(),
1750
    ///     VariantOffsetsCalculator::new(),
1751
    /// )
1752
    /// .unwrap()
1753
    /// .zone;
1754
    /// let mut zone_london_summer = ZonedDateTime::try_from_str(
1755
    ///     "2024-07-01T00:00:00+01:00[Europe/London]",
1756
    ///     Gregorian,
1757
    ///     IanaParser::new(),
1758
    ///     VariantOffsetsCalculator::new(),
1759
    /// )
1760
    /// .unwrap()
1761
    /// .zone;
1762
    ///
1763
    /// let mut names =
1764
    ///     FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
1765
    ///         locale!("en-GB").into(),
1766
    ///     )
1767
    ///     .unwrap();
1768
    ///
1769
    /// names.include_time_zone_essentials().unwrap();
1770
    /// names.include_time_zone_generic_long_names().unwrap();
1771
    ///
1772
    /// // Create a pattern with symbol `vvvv`:
1773
    /// let pattern_str = "'Your time zone is:' vvvv";
1774
    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1775
    ///
1776
    /// assert_try_writeable_eq!(
1777
    ///     names
1778
    ///         .with_pattern_unchecked(&pattern)
1779
    ///         .format(&zone_london_winter),
1780
    ///     "Your time zone is: Greenwich Mean Time",
1781
    /// );
1782
    /// assert_try_writeable_eq!(
1783
    ///     names
1784
    ///         .with_pattern_unchecked(&pattern)
1785
    ///         .format(&zone_london_summer),
1786
    ///     "Your time zone is: Greenwich Mean Time", // TODO
1787
    /// );
1788
    /// ```
1789
    #[cfg(feature = "compiled_data")]
1790
    pub fn include_time_zone_generic_long_names(&mut self) -> Result<&mut Self, PatternLoadError> {
1791
        self.load_time_zone_generic_long_names(&crate::provider::Baked)
1792
    }
1793

1794
    /// Loads generic non-location short time zone names.
1795
    pub fn load_time_zone_generic_short_names<P>(
1796
        &mut self,
1797
        provider: &P,
1798
    ) -> Result<&mut Self, PatternLoadError>
1799
    where
1800
        P: DataProvider<tz::MzGenericShortV1> + DataProvider<tz::MzPeriodV1> + ?Sized,
1801
    {
1802
        self.inner.load_time_zone_generic_short_names(
1803
            &tz::MzGenericShortV1::bind(provider),
1804
            &tz::MzPeriodV1::bind(provider),
1805
            self.prefs,
1806
        )?;
1807
        Ok(self)
1808
    }
1809

1810
    /// Includes generic non-location short time zone names.
1811
    ///
1812
    /// Important: When performing manual time zone data loading, in addition to the
1813
    /// specific time zone format data, also call either:
1814
    ///
1815
    /// - [`FixedCalendarDateTimeNames::include_time_zone_essentials`]
1816
    /// - [`FixedCalendarDateTimeNames::load_time_zone_essentials`]
1817
    ///
1818
    /// # Examples
1819
    ///
1820
    /// ```
1821
    /// use icu::calendar::Gregorian;
1822
    /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
1823
    /// use icu::datetime::input::ZonedDateTime;
1824
    /// use icu::datetime::pattern::DateTimePattern;
1825
    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1826
    /// use icu::locale::locale;
1827
    /// use icu::time::zone::{IanaParser, VariantOffsetsCalculator};
1828
    /// use writeable::assert_try_writeable_eq;
1829
    ///
1830
    /// let mut zone_london_winter = ZonedDateTime::try_from_str(
1831
    ///     "2024-01-01T00:00:00+00:00[Europe/London]",
1832
    ///     Gregorian,
1833
    ///     IanaParser::new(),
1834
    ///     VariantOffsetsCalculator::new(),
1835
    /// )
1836
    /// .unwrap()
1837
    /// .zone;
1838
    /// let mut zone_london_summer = ZonedDateTime::try_from_str(
1839
    ///     "2024-07-01T00:00:00+01:00[Europe/London]",
1840
    ///     Gregorian,
1841
    ///     IanaParser::new(),
1842
    ///     VariantOffsetsCalculator::new(),
1843
    /// )
1844
    /// .unwrap()
1845
    /// .zone;
1846
    ///
1847
    /// let mut names =
1848
    ///     FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
1849
    ///         locale!("en-GB").into(),
1850
    ///     )
1851
    ///     .unwrap();
1852
    ///
1853
    /// names.include_time_zone_essentials().unwrap();
1854
    /// names.include_time_zone_generic_short_names().unwrap();
1855
    ///
1856
    /// // Create a pattern with symbol `v`:
1857
    /// let pattern_str = "'Your time zone is:' v";
1858
    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1859
    ///
1860
    /// assert_try_writeable_eq!(
1861
    ///     names
1862
    ///         .with_pattern_unchecked(&pattern)
1863
    ///         .format(&zone_london_winter),
1864
    ///     "Your time zone is: GMT",
1865
    /// );
1866
    /// assert_try_writeable_eq!(
1867
    ///     names
1868
    ///         .with_pattern_unchecked(&pattern)
1869
    ///         .format(&zone_london_summer),
1870
    ///     "Your time zone is: GMT", // TODO
1871
    /// );
1872
    /// ```
1873
    #[cfg(feature = "compiled_data")]
1874
    pub fn include_time_zone_generic_short_names(&mut self) -> Result<&mut Self, PatternLoadError> {
1875
        self.load_time_zone_generic_short_names(&crate::provider::Baked)
1876
    }
1877

1878
    /// Loads specific non-location long time zone names.
1879
    pub fn load_time_zone_specific_long_names<P>(
1880
        &mut self,
1881
        provider: &P,
1882
    ) -> Result<&mut Self, PatternLoadError>
1883
    where
1884
        P: DataProvider<tz::MzSpecificLongV1>
1885
            + DataProvider<tz::MzStandardLongV1>
1886
            + DataProvider<tz::MzPeriodV1>
1887
            + ?Sized,
1888
    {
1889
        self.inner.load_time_zone_specific_long_names(
1890
            &tz::MzSpecificLongV1::bind(provider),
1891
            &tz::MzStandardLongV1::bind(provider),
1892
            &tz::MzPeriodV1::bind(provider),
1893
            self.prefs,
1894
        )?;
1895
        Ok(self)
1896
    }
1897

1898
    /// Includes specific non-location long time zone names.
1899
    ///
1900
    /// Important: When performing manual time zone data loading, in addition to the
1901
    /// specific time zone format data, also call either:
1902
    ///
1903
    /// - [`FixedCalendarDateTimeNames::include_time_zone_essentials`]
1904
    /// - [`FixedCalendarDateTimeNames::load_time_zone_essentials`]
1905
    ///
1906
    /// # Examples
1907
    ///
1908
    /// ```
1909
    /// use icu::calendar::Gregorian;
1910
    /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
1911
    /// use icu::datetime::input::ZonedDateTime;
1912
    /// use icu::datetime::pattern::DateTimePattern;
1913
    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1914
    /// use icu::locale::locale;
1915
    /// use icu::time::zone::{IanaParser, VariantOffsetsCalculator};
1916
    /// use writeable::assert_try_writeable_eq;
1917
    ///
1918
    /// let mut zone_london_winter = ZonedDateTime::try_from_str(
1919
    ///     "2024-01-01T00:00:00+00:00[Europe/London]",
1920
    ///     Gregorian,
1921
    ///     IanaParser::new(),
1922
    ///     VariantOffsetsCalculator::new(),
1923
    /// )
1924
    /// .unwrap()
1925
    /// .zone;
1926
    /// let mut zone_london_summer = ZonedDateTime::try_from_str(
1927
    ///     "2024-07-01T00:00:00+01:00[Europe/London]",
1928
    ///     Gregorian,
1929
    ///     IanaParser::new(),
1930
    ///     VariantOffsetsCalculator::new(),
1931
    /// )
1932
    /// .unwrap()
1933
    /// .zone;
1934
    ///
1935
    /// let mut names =
1936
    ///     FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
1937
    ///         locale!("en-GB").into(),
1938
    ///     )
1939
    ///     .unwrap();
1940
    ///
1941
    /// names.include_time_zone_essentials().unwrap();
1942
    /// names.include_time_zone_specific_long_names().unwrap();
1943
    ///
1944
    /// // Create a pattern with symbol `zzzz`:
1945
    /// let pattern_str = "'Your time zone is:' zzzz";
1946
    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1947
    ///
1948
    /// assert_try_writeable_eq!(
1949
    ///     names
1950
    ///         .with_pattern_unchecked(&pattern)
1951
    ///         .format(&zone_london_winter),
1952
    ///     "Your time zone is: Greenwich Mean Time",
1953
    /// );
1954
    /// assert_try_writeable_eq!(
1955
    ///     names
1956
    ///         .with_pattern_unchecked(&pattern)
1957
    ///         .format(&zone_london_summer),
1958
    ///     "Your time zone is: British Summer Time",
1959
    /// );
1960
    /// ```
1961
    #[cfg(feature = "compiled_data")]
1962
    pub fn include_time_zone_specific_long_names(&mut self) -> Result<&mut Self, PatternLoadError> {
1963
        self.load_time_zone_specific_long_names(&crate::provider::Baked)
1964
    }
1965

1966
    /// Loads specific non-location short time zone names.
1967
    pub fn load_time_zone_specific_short_names<P>(
1968
        &mut self,
1969
        provider: &P,
1970
    ) -> Result<&mut Self, PatternLoadError>
1971
    where
1972
        P: DataProvider<tz::MzSpecificShortV1> + DataProvider<tz::MzPeriodV1> + ?Sized,
1973
    {
1974
        self.inner.load_time_zone_specific_short_names(
1975
            &tz::MzSpecificShortV1::bind(provider),
1976
            &tz::MzPeriodV1::bind(provider),
1977
            self.prefs,
1978
        )?;
1979
        Ok(self)
1980
    }
1981

1982
    /// Includes specific non-location short time zone names.
1983
    ///
1984
    /// Important: When performing manual time zone data loading, in addition to the
1985
    /// specific time zone format data, also call either:
1986
    ///
1987
    /// - [`FixedCalendarDateTimeNames::include_time_zone_essentials`]
1988
    /// - [`FixedCalendarDateTimeNames::load_time_zone_essentials`]
1989
    ///
1990
    /// # Examples
1991
    ///
1992
    /// ```
1993
    /// use icu::calendar::Gregorian;
1994
    /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
1995
    /// use icu::datetime::input::ZonedDateTime;
1996
    /// use icu::datetime::pattern::DateTimePattern;
1997
    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1998
    /// use icu::locale::locale;
1999
    /// use icu::time::zone::{IanaParser, VariantOffsetsCalculator};
2000
    /// use writeable::assert_try_writeable_eq;
2001
    ///
2002
    /// let mut zone_london_winter = ZonedDateTime::try_from_str(
2003
    ///     "2024-01-01T00:00:00+00:00[Europe/London]",
2004
    ///     Gregorian,
2005
    ///     IanaParser::new(),
2006
    ///     VariantOffsetsCalculator::new(),
2007
    /// )
2008
    /// .unwrap()
2009
    /// .zone;
2010
    /// let mut zone_london_summer = ZonedDateTime::try_from_str(
2011
    ///     "2024-07-01T00:00:00+01:00[Europe/London]",
2012
    ///     Gregorian,
2013
    ///     IanaParser::new(),
2014
    ///     VariantOffsetsCalculator::new(),
2015
    /// )
2016
    /// .unwrap()
2017
    /// .zone;
2018
    ///
2019
    /// let mut names =
2020
    ///     FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
2021
    ///         locale!("en-GB").into(),
2022
    ///     )
2023
    ///     .unwrap();
2024
    ///
2025
    /// names.include_time_zone_essentials().unwrap();
2026
    /// names.include_time_zone_specific_short_names().unwrap();
2027
    ///
2028
    /// // Create a pattern with symbol `z`:
2029
    /// let pattern_str = "'Your time zone is:' z";
2030
    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
2031
    ///
2032
    /// assert_try_writeable_eq!(
2033
    ///     names
2034
    ///         .with_pattern_unchecked(&pattern)
2035
    ///         .format(&zone_london_winter),
2036
    ///     "Your time zone is: GMT",
2037
    /// );
2038
    /// assert_try_writeable_eq!(
2039
    ///     names
2040
    ///         .with_pattern_unchecked(&pattern)
2041
    ///         .format(&zone_london_summer),
2042
    ///     "Your time zone is: BST",
2043
    /// );
2044
    /// ```
2045
    #[cfg(feature = "compiled_data")]
2046
    pub fn include_time_zone_specific_short_names(
2047
        &mut self,
2048
    ) -> Result<&mut Self, PatternLoadError> {
2049
        self.load_time_zone_specific_short_names(&crate::provider::Baked)
2050
    }
2051

2052
    /// Loads generic non-location short time zone names
2053
    /// and all data required for its fallback formats.
2054
    ///
2055
    /// See [`GenericShort`](crate::fieldsets::zone::GenericShort)
2056
    pub fn load_time_zone_generic_short_names_with_fallback<P>(
×
2057
        &mut self,
2058
        provider: &P,
2059
    ) -> Result<&mut Self, PatternLoadError>
2060
    where
2061
        P: DataProvider<DecimalSymbolsV1>
2062
            + DataProvider<DecimalDigitsV1>
2063
            + DataProvider<tz::EssentialsV1>
2064
            + DataProvider<tz::LocationsV1>
2065
            + DataProvider<tz::LocationsRootV1>
2066
            + DataProvider<tz::MzGenericShortV1>
2067
            + DataProvider<tz::MzPeriodV1>
2068
            + ?Sized,
2069
    {
2070
        let error_field = self.inner.load_time_zone_field_v_except_decimals(
×
2071
            &tz::EssentialsV1::bind(provider),
×
2072
            &tz::LocationsV1::bind(provider),
×
2073
            &tz::LocationsRootV1::bind(provider),
×
2074
            &tz::MzGenericShortV1::bind(provider),
×
2075
            &tz::MzPeriodV1::bind(provider),
×
2076
            self.prefs,
×
2077
        )?;
×
2078
        self.load_decimal_formatter(provider)
×
2079
            .map_err(|e| PatternLoadError::Data(e, error_field))?;
×
2080
        Ok(self)
×
2081
    }
×
2082

2083
    /// Includes generic non-location short time zone names
2084
    /// and all data required for its fallback formats.
2085
    ///
2086
    /// See [`GenericShort`](crate::fieldsets::zone::GenericShort)
2087
    #[cfg(feature = "compiled_data")]
2088
    pub fn include_time_zone_generic_short_names_with_fallback(
×
2089
        &mut self,
2090
    ) -> Result<&mut Self, PatternLoadError> {
2091
        let error_field = self.inner.load_time_zone_field_v_except_decimals(
×
2092
            &tz::EssentialsV1::bind(&crate::provider::Baked),
×
2093
            &tz::LocationsV1::bind(&crate::provider::Baked),
×
2094
            &tz::LocationsRootV1::bind(&crate::provider::Baked),
×
2095
            &tz::MzGenericShortV1::bind(&crate::provider::Baked),
×
2096
            &tz::MzPeriodV1::bind(&crate::provider::Baked),
×
2097
            self.prefs,
×
2098
        )?;
×
2099
        self.include_decimal_formatter()
×
2100
            .map_err(|e| PatternLoadError::Data(e, error_field))?;
×
2101
        Ok(self)
×
2102
    }
×
2103

2104
    /// Loads generic non-location long time zone names
2105
    /// and all data required for its fallback formats.
2106
    ///
2107
    /// See [`GenericLong`](crate::fieldsets::zone::GenericLong)
2108
    pub fn load_time_zone_generic_long_names_with_fallback<P>(
×
2109
        &mut self,
2110
        provider: &P,
2111
    ) -> Result<&mut Self, PatternLoadError>
2112
    where
2113
        P: DataProvider<DecimalSymbolsV1>
2114
            + DataProvider<DecimalDigitsV1>
2115
            + DataProvider<tz::EssentialsV1>
2116
            + DataProvider<tz::LocationsV1>
2117
            + DataProvider<tz::LocationsRootV1>
2118
            + DataProvider<tz::MzGenericLongV1>
2119
            + DataProvider<tz::MzStandardLongV1>
2120
            + DataProvider<tz::MzPeriodV1>
2121
            + ?Sized,
2122
    {
2123
        let error_field = self.inner.load_time_zone_field_vvvv_except_decimals(
×
2124
            &tz::EssentialsV1::bind(provider),
×
2125
            &tz::LocationsV1::bind(provider),
×
2126
            &tz::LocationsRootV1::bind(provider),
×
2127
            &tz::MzGenericLongV1::bind(provider),
×
2128
            &tz::MzStandardLongV1::bind(provider),
×
2129
            &tz::MzPeriodV1::bind(provider),
×
2130
            self.prefs,
×
2131
        )?;
×
2132
        self.load_decimal_formatter(provider)
×
2133
            .map_err(|e| PatternLoadError::Data(e, error_field))?;
×
2134
        Ok(self)
×
2135
    }
×
2136

2137
    /// Includes generic non-location long time zone names
2138
    /// and all data required for its fallback formats.
2139
    ///
2140
    /// See [`GenericLong`](crate::fieldsets::zone::GenericLong)
2141
    #[cfg(feature = "compiled_data")]
2142
    pub fn include_time_zone_generic_long_names_with_fallback(
×
2143
        &mut self,
2144
    ) -> Result<&mut Self, PatternLoadError> {
2145
        let error_field = self.inner.load_time_zone_field_vvvv_except_decimals(
×
2146
            &tz::EssentialsV1::bind(&crate::provider::Baked),
×
2147
            &tz::LocationsV1::bind(&crate::provider::Baked),
×
2148
            &tz::LocationsRootV1::bind(&crate::provider::Baked),
×
2149
            &tz::MzGenericLongV1::bind(&crate::provider::Baked),
×
2150
            &tz::MzStandardLongV1::bind(&crate::provider::Baked),
×
2151
            &tz::MzPeriodV1::bind(&crate::provider::Baked),
×
2152
            self.prefs,
×
2153
        )?;
×
2154
        self.include_decimal_formatter()
×
2155
            .map_err(|e| PatternLoadError::Data(e, error_field))?;
×
2156
        Ok(self)
×
2157
    }
×
2158

2159
    /// Loads specific non-location short time zone names
2160
    /// and all data required for its fallback formats
2161
    /// except for decimal formatting.
2162
    ///
2163
    /// See [`SpecificShort`](crate::fieldsets::zone::SpecificShort)
2164
    pub fn load_time_zone_specific_short_names_with_fallback<P>(
×
2165
        &mut self,
2166
        provider: &P,
2167
    ) -> Result<&mut Self, PatternLoadError>
2168
    where
2169
        P: DataProvider<DecimalSymbolsV1>
2170
            + DataProvider<DecimalDigitsV1>
2171
            + DataProvider<tz::EssentialsV1>
2172
            + DataProvider<tz::LocationsV1>
2173
            + DataProvider<tz::LocationsRootV1>
2174
            + DataProvider<tz::MzSpecificShortV1>
2175
            + DataProvider<tz::MzPeriodV1>
2176
            + ?Sized,
2177
    {
2178
        let error_field = self.inner.load_time_zone_field_z_except_decimals(
×
2179
            &tz::EssentialsV1::bind(provider),
×
2180
            &tz::MzSpecificShortV1::bind(provider),
×
2181
            &tz::MzPeriodV1::bind(provider),
×
2182
            self.prefs,
×
2183
        )?;
×
2184
        self.load_decimal_formatter(provider)
×
2185
            .map_err(|e| PatternLoadError::Data(e, error_field))?;
×
2186
        Ok(self)
×
2187
    }
×
2188

2189
    /// Includes specific non-location short time zone names
2190
    /// and all data required for its fallback formats
2191
    /// except for decimal formatting.
2192
    ///
2193
    /// See [`SpecificShort`](crate::fieldsets::zone::SpecificShort)
2194
    #[cfg(feature = "compiled_data")]
2195
    pub fn include_time_zone_specific_short_names_with_fallback(
×
2196
        &mut self,
2197
    ) -> Result<&mut Self, PatternLoadError> {
2198
        let error_field = self.inner.load_time_zone_field_z_except_decimals(
×
2199
            &tz::EssentialsV1::bind(&crate::provider::Baked),
×
2200
            &tz::MzSpecificShortV1::bind(&crate::provider::Baked),
×
2201
            &tz::MzPeriodV1::bind(&crate::provider::Baked),
×
2202
            self.prefs,
×
2203
        )?;
×
2204
        self.include_decimal_formatter()
×
2205
            .map_err(|e| PatternLoadError::Data(e, error_field))?;
×
2206
        Ok(self)
×
2207
    }
×
2208

2209
    /// Loads specific non-location long time zone names
2210
    /// and all data required for its fallback formats
2211
    /// except for decimal formatting.
2212
    ///
2213
    /// See [`SpecificLong`](crate::fieldsets::zone::SpecificLong)
2214
    pub fn load_time_zone_specific_long_names_with_fallback<P>(
×
2215
        &mut self,
2216
        provider: &P,
2217
    ) -> Result<&mut Self, PatternLoadError>
2218
    where
2219
        P: DataProvider<DecimalSymbolsV1>
2220
            + DataProvider<DecimalDigitsV1>
2221
            + DataProvider<tz::EssentialsV1>
2222
            + DataProvider<tz::LocationsV1>
2223
            + DataProvider<tz::LocationsRootV1>
2224
            + DataProvider<tz::MzSpecificLongV1>
2225
            + DataProvider<tz::MzStandardLongV1>
2226
            + DataProvider<tz::MzPeriodV1>
2227
            + ?Sized,
2228
    {
2229
        let error_field = self.inner.load_time_zone_field_zzzz_except_decimals(
×
2230
            &tz::EssentialsV1::bind(provider),
×
2231
            &tz::LocationsV1::bind(provider),
×
2232
            &tz::LocationsRootV1::bind(provider),
×
2233
            &tz::MzStandardLongV1::bind(provider),
×
2234
            &tz::MzSpecificLongV1::bind(provider),
×
2235
            &tz::MzPeriodV1::bind(provider),
×
2236
            self.prefs,
×
2237
        )?;
×
2238
        self.load_decimal_formatter(provider)
×
2239
            .map_err(|e| PatternLoadError::Data(e, error_field))?;
×
2240
        Ok(self)
×
2241
    }
×
2242

2243
    /// Includes specific non-location long time zone names
2244
    /// and all data required for its fallback formats
2245
    /// except for decimal formatting.
2246
    ///
2247
    /// See [`SpecificLong`](crate::fieldsets::zone::SpecificLong)
2248
    #[cfg(feature = "compiled_data")]
2249
    pub fn include_time_zone_specific_long_names_with_fallback(
×
2250
        &mut self,
2251
    ) -> Result<&mut Self, PatternLoadError> {
2252
        let error_field = self.inner.load_time_zone_field_zzzz_except_decimals(
×
2253
            &tz::EssentialsV1::bind(&crate::provider::Baked),
×
2254
            &tz::LocationsV1::bind(&crate::provider::Baked),
×
2255
            &tz::LocationsRootV1::bind(&crate::provider::Baked),
×
2256
            &tz::MzStandardLongV1::bind(&crate::provider::Baked),
×
2257
            &tz::MzSpecificLongV1::bind(&crate::provider::Baked),
×
2258
            &tz::MzPeriodV1::bind(&crate::provider::Baked),
×
2259
            self.prefs,
×
2260
        )?;
×
2261
        self.include_decimal_formatter()
×
2262
            .map_err(|e| PatternLoadError::Data(e, error_field))?;
×
2263
        Ok(self)
×
2264
    }
×
2265

2266
    /// Loads all data for short and long localized offset time zone formatting
2267
    /// except for decimal formatting.
2268
    ///
2269
    /// See:
2270
    ///
2271
    /// - [`LocalizedOffsetShort`](crate::fieldsets::zone::LocalizedOffsetShort)
2272
    /// - [`LocalizedOffsetLong`](crate::fieldsets::zone::LocalizedOffsetLong)
2273
    pub fn load_time_zone_localized_offset_names_with_fallback<P>(
×
2274
        &mut self,
2275
        provider: &P,
2276
    ) -> Result<&mut Self, PatternLoadError>
2277
    where
2278
        P: DataProvider<DecimalSymbolsV1>
2279
            + DataProvider<DecimalDigitsV1>
2280
            + DataProvider<tz::EssentialsV1>
2281
            + ?Sized,
2282
    {
2283
        let error_field = self.inner.load_time_zone_field_O_except_decimals(
×
2284
            &tz::EssentialsV1::bind(provider),
×
2285
            self.prefs,
×
2286
        )?;
×
2287
        self.load_decimal_formatter(provider)
×
2288
            .map_err(|e| PatternLoadError::Data(e, error_field))?;
×
2289
        Ok(self)
×
2290
    }
×
2291

2292
    /// Includes all data for short and long localized offset time zone formatting
2293
    /// except for decimal formatting.
2294
    ///
2295
    /// See:
2296
    ///
2297
    /// - [`LocalizedOffsetShort`](crate::fieldsets::zone::LocalizedOffsetShort)
2298
    /// - [`LocalizedOffsetLong`](crate::fieldsets::zone::LocalizedOffsetLong)
2299
    #[cfg(feature = "compiled_data")]
2300
    pub fn include_time_zone_localized_offset_names_with_fallback(
×
2301
        &mut self,
2302
    ) -> Result<&mut Self, PatternLoadError> {
2303
        let error_field = self.inner.load_time_zone_field_O_except_decimals(
×
2304
            &tz::EssentialsV1::bind(&crate::provider::Baked),
×
2305
            self.prefs,
×
2306
        )?;
×
2307
        self.include_decimal_formatter()
×
2308
            .map_err(|e| PatternLoadError::Data(e, error_field))?;
×
2309
        Ok(self)
×
2310
    }
×
2311

2312
    /// Loads a [`DecimalFormatter`] from a data provider.
2313
    #[inline]
2314
    pub fn load_decimal_formatter<P>(&mut self, provider: &P) -> Result<&mut Self, DataError>
×
2315
    where
2316
        P: DataProvider<DecimalSymbolsV1> + DataProvider<DecimalDigitsV1> + ?Sized,
2317
    {
2318
        self.inner
×
2319
            .load_decimal_formatter(&ExternalLoaderUnstable(provider), self.prefs)?;
×
2320
        Ok(self)
×
2321
    }
×
2322

2323
    /// Loads a [`DecimalFormatter`] with compiled data.
2324
    ///
2325
    /// # Examples
2326
    ///
2327
    /// ```
2328
    /// use icu::datetime::fieldsets::enums::TimeFieldSet;
2329
    /// use icu::datetime::input::Time;
2330
    /// use icu::datetime::pattern::DateTimePattern;
2331
    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
2332
    /// use icu::locale::locale;
2333
    /// use writeable::assert_try_writeable_eq;
2334
    ///
2335
    /// let mut names = FixedCalendarDateTimeNames::<(), TimeFieldSet>::try_new(
2336
    ///     locale!("bn").into(),
2337
    /// )
2338
    /// .unwrap();
2339
    /// names.include_decimal_formatter();
2340
    ///
2341
    /// // Create a pattern for the time, which is all numbers
2342
    /// let pattern_str = "'The current 24-hour time is:' HH:mm";
2343
    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
2344
    ///
2345
    /// let time = Time::try_new(6, 40, 33, 0).unwrap();
2346
    ///
2347
    /// assert_try_writeable_eq!(
2348
    ///     names.with_pattern_unchecked(&pattern).format(&time),
2349
    ///     "The current 24-hour time is: ০৬:৪০",
2350
    /// );
2351
    /// ```
2352
    #[cfg(feature = "compiled_data")]
2353
    #[inline]
2354
    pub fn include_decimal_formatter(&mut self) -> Result<&mut Self, DataError> {
36✔
2355
        self.inner
72✔
2356
            .load_decimal_formatter(&ExternalLoaderCompiledData, self.prefs)?;
36✔
2357
        Ok(self)
36✔
2358
    }
36✔
2359
}
2360

2361
impl<C: CldrCalendar, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
2362
    /// Associates this [`FixedCalendarDateTimeNames`] with a pattern
2363
    /// without checking that all necessary data is loaded.
2364
    #[inline]
2365
    pub fn with_pattern_unchecked<'l>(
35✔
2366
        &'l self,
2367
        pattern: &'l DateTimePattern,
2368
    ) -> DateTimePatternFormatter<'l, C, FSet> {
2369
        DateTimePatternFormatter::new(pattern.as_borrowed(), self.inner.as_borrowed())
35✔
2370
    }
35✔
2371

2372
    /// Associates this [`FixedCalendarDateTimeNames`] with a datetime pattern
2373
    /// and loads all data required for that pattern.
2374
    ///
2375
    /// Does not duplicate textual field symbols. See #4337
2376
    pub fn load_for_pattern<'l, P>(
2377
        &'l mut self,
2378
        provider: &P,
2379
        pattern: &'l DateTimePattern,
2380
    ) -> Result<DateTimePatternFormatter<'l, C, FSet>, PatternLoadError>
2381
    where
2382
        P: DataProvider<C::YearNamesV1>
2383
            + DataProvider<C::MonthNamesV1>
2384
            + DataProvider<WeekdayNamesV1>
2385
            + DataProvider<DayPeriodNamesV1>
2386
            + DataProvider<tz::EssentialsV1>
2387
            + DataProvider<tz::LocationsV1>
2388
            + DataProvider<tz::LocationsRootV1>
2389
            + DataProvider<tz::ExemplarCitiesV1>
2390
            + DataProvider<tz::ExemplarCitiesRootV1>
2391
            + DataProvider<tz::MzGenericLongV1>
2392
            + DataProvider<tz::MzGenericShortV1>
2393
            + DataProvider<tz::MzStandardLongV1>
2394
            + DataProvider<tz::MzSpecificLongV1>
2395
            + DataProvider<tz::MzSpecificShortV1>
2396
            + DataProvider<tz::MzPeriodV1>
2397
            + DataProvider<DecimalSymbolsV1>
2398
            + DataProvider<DecimalDigitsV1>
2399
            + ?Sized,
2400
    {
2401
        let locale = self.prefs;
2402
        self.inner.load_for_pattern(
2403
            &C::YearNamesV1::bind(provider),
2404
            &C::MonthNamesV1::bind(provider),
2405
            &WeekdayNamesV1::bind(provider),
2406
            &DayPeriodNamesV1::bind(provider),
2407
            // TODO: Consider making time zone name loading optional here (lots of data)
2408
            &tz::EssentialsV1::bind(provider),
2409
            &tz::LocationsRootV1::bind(provider),
2410
            &tz::LocationsV1::bind(provider),
2411
            &tz::ExemplarCitiesRootV1::bind(provider),
2412
            &tz::ExemplarCitiesV1::bind(provider),
2413
            &tz::MzGenericLongV1::bind(provider),
2414
            &tz::MzGenericShortV1::bind(provider),
2415
            &tz::MzStandardLongV1::bind(provider),
2416
            &tz::MzSpecificLongV1::bind(provider),
2417
            &tz::MzSpecificShortV1::bind(provider),
2418
            &tz::MzPeriodV1::bind(provider),
2419
            &ExternalLoaderUnstable(provider),
2420
            locale,
2421
            pattern.iter_items(),
2422
        )?;
2423
        Ok(DateTimePatternFormatter::new(
2424
            pattern.as_borrowed(),
2425
            self.inner.as_borrowed(),
2426
        ))
2427
    }
2428

2429
    /// Associates this [`FixedCalendarDateTimeNames`] with a pattern
2430
    /// and includes all data required for that pattern.
2431
    ///
2432
    /// Does not support duplicate textual field symbols. See #4337
2433
    ///
2434
    /// # Examples
2435
    ///
2436
    /// ```
2437
    /// use icu::calendar::Gregorian;
2438
    /// use icu::datetime::input::Date;
2439
    /// use icu::datetime::input::{DateTime, Time};
2440
    /// use icu::datetime::pattern::DateTimePattern;
2441
    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
2442
    /// use icu::locale::locale;
2443
    /// use writeable::assert_try_writeable_eq;
2444
    ///
2445
    /// let mut names =
2446
    ///     FixedCalendarDateTimeNames::<Gregorian>::try_new(locale!("en").into())
2447
    ///         .unwrap();
2448
    ///
2449
    /// // Create a pattern from a pattern string:
2450
    /// let pattern_str = "MMM d (EEEE) 'of year' y G 'at' h:mm a";
2451
    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
2452
    ///
2453
    /// // Load data for the pattern and format:
2454
    /// let datetime = DateTime {
2455
    ///     date: Date::try_new_gregorian(2023, 12, 5).unwrap(),
2456
    ///     time: Time::try_new(17, 43, 12, 0).unwrap(),
2457
    /// };
2458
    /// assert_try_writeable_eq!(
2459
    ///     names
2460
    ///         .include_for_pattern(&pattern)
2461
    ///         .unwrap()
2462
    ///         .format(&datetime),
2463
    ///     "Dec 5 (Tuesday) of year 2023 AD at 5:43 PM"
2464
    /// );
2465
    /// ```
2466
    #[cfg(feature = "compiled_data")]
2467
    pub fn include_for_pattern<'l>(
2468
        &'l mut self,
2469
        pattern: &'l DateTimePattern,
2470
    ) -> Result<DateTimePatternFormatter<'l, C, FSet>, PatternLoadError>
2471
    where
2472
        crate::provider::Baked: DataProvider<C::YearNamesV1> + DataProvider<C::MonthNamesV1>,
2473
        crate::provider::Baked: DataProvider<C::YearNamesV1> + DataProvider<C::MonthNamesV1>,
2474
    {
2475
        let locale = self.prefs;
2476
        self.inner.load_for_pattern(
2477
            &C::YearNamesV1::bind(&crate::provider::Baked),
2478
            &C::MonthNamesV1::bind(&crate::provider::Baked),
2479
            &WeekdayNamesV1::bind(&crate::provider::Baked),
2480
            &DayPeriodNamesV1::bind(&crate::provider::Baked),
2481
            &tz::EssentialsV1::bind(&crate::provider::Baked),
2482
            &tz::LocationsV1::bind(&crate::provider::Baked),
2483
            &tz::LocationsRootV1::bind(&crate::provider::Baked),
2484
            &tz::ExemplarCitiesV1::bind(&crate::provider::Baked),
2485
            &tz::ExemplarCitiesRootV1::bind(&crate::provider::Baked),
2486
            &tz::MzGenericLongV1::bind(&crate::provider::Baked),
2487
            &tz::MzGenericShortV1::bind(&crate::provider::Baked),
2488
            &tz::MzStandardLongV1::bind(&crate::provider::Baked),
2489
            &tz::MzSpecificLongV1::bind(&crate::provider::Baked),
2490
            &tz::MzSpecificShortV1::bind(&crate::provider::Baked),
2491
            &tz::MzPeriodV1::bind(&crate::provider::Baked),
2492
            &ExternalLoaderCompiledData,
2493
            locale,
2494
            pattern.iter_items(),
2495
        )?;
2496
        Ok(DateTimePatternFormatter::new(
2497
            pattern.as_borrowed(),
2498
            self.inner.as_borrowed(),
2499
        ))
2500
    }
2501
}
2502

2503
impl<C, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
2504
    /// Maps a [`FixedCalendarDateTimeNames`] of a specific `FSet` to a more general `FSet`.
2505
    ///
2506
    /// For example, this can transform a formatter for [`DateFieldSet`] to one for
2507
    /// [`CompositeDateTimeFieldSet`].
2508
    ///
2509
    /// [`DateFieldSet`]: crate::fieldsets::enums::DateFieldSet
2510
    /// [`CompositeDateTimeFieldSet`]: crate::fieldsets::enums::CompositeDateTimeFieldSet
2511
    ///
2512
    /// # Examples
2513
    ///
2514
    /// ```
2515
    /// use icu::calendar::Gregorian;
2516
    /// use icu::datetime::fieldsets::enums::{
2517
    ///     CompositeDateTimeFieldSet, DateFieldSet,
2518
    /// };
2519
    /// use icu::datetime::input::Date;
2520
    /// use icu::datetime::input::{DateTime, Time};
2521
    /// use icu::datetime::pattern::DateTimePattern;
2522
    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
2523
    /// use icu::datetime::pattern::MonthNameLength;
2524
    /// use icu::locale::locale;
2525
    /// use writeable::assert_try_writeable_eq;
2526
    ///
2527
    /// // Create an instance that can format abbreviated month names:
2528
    /// let mut names: FixedCalendarDateTimeNames<Gregorian, DateFieldSet> =
2529
    ///     FixedCalendarDateTimeNames::try_new(locale!("uk").into()).unwrap();
2530
    /// names
2531
    ///     .include_month_names(MonthNameLength::Abbreviated)
2532
    ///     .unwrap();
2533
    ///
2534
    /// // Test it with a pattern:
2535
    /// let pattern_str = "MMM d y";
2536
    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
2537
    /// let datetime = DateTime {
2538
    ///     date: Date::try_new_gregorian(2023, 11, 20).unwrap(),
2539
    ///     time: Time::midnight(),
2540
    /// };
2541
    /// assert_try_writeable_eq!(
2542
    ///     names.with_pattern_unchecked(&pattern).format(&datetime),
2543
    ///     "лист. 20 2023"
2544
    /// );
2545
    ///
2546
    /// // Convert the field set to `CompositeDateTimeFieldSet`:
2547
    /// let composite_names = names.cast_into_fset::<CompositeDateTimeFieldSet>();
2548
    ///
2549
    /// // It should still work:
2550
    /// assert_try_writeable_eq!(
2551
    ///     composite_names
2552
    ///         .with_pattern_unchecked(&pattern)
2553
    ///         .format(&datetime),
2554
    ///     "лист. 20 2023"
2555
    /// );
2556
    /// ```
2557
    ///
2558
    /// Converting into a narrower type is not supported:
2559
    ///
2560
    /// ```compile_fail,E0277
2561
    /// use icu::calendar::Gregorian;
2562
    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
2563
    /// use icu::datetime::fieldsets::enums::{DateFieldSet, CompositeDateTimeFieldSet};
2564
    ///
2565
    /// let composite_names: FixedCalendarDateTimeNames<Gregorian, CompositeDateTimeFieldSet> = todo!();
2566
    ///
2567
    /// // error[E0277]: the trait bound `(): From<DataPayloadWithVariables<DayPeriodNamesV1, FieldLength>>` is not satisfied
2568
    /// let narrow_names = composite_names.cast_into_fset::<DateFieldSet>();
2569
    /// ```
2570
    pub fn cast_into_fset<FSet2: DateTimeNamesFrom<FSet>>(
×
2571
        self,
2572
    ) -> FixedCalendarDateTimeNames<C, FSet2> {
2573
        FixedCalendarDateTimeNames {
×
2574
            prefs: self.prefs,
×
2575
            inner: self.inner.cast_into_fset(),
×
2576
            _calendar: PhantomData,
2577
        }
2578
    }
×
2579
}
2580

2581
impl<FSet: DateTimeNamesMarker> DateTimeNames<FSet> {
2582
    /// Maps a [`FixedCalendarDateTimeNames`] of a specific `FSet` to a more general `FSet`.
2583
    ///
2584
    /// For example, this can transform a formatter for [`DateFieldSet`] to one for
2585
    /// [`CompositeDateTimeFieldSet`].
2586
    ///
2587
    /// [`DateFieldSet`]: crate::fieldsets::enums::DateFieldSet
2588
    /// [`CompositeDateTimeFieldSet`]: crate::fieldsets::enums::CompositeDateTimeFieldSet
2589
    pub fn cast_into_fset<FSet2: DateTimeNamesFrom<FSet>>(self) -> DateTimeNames<FSet2> {
×
2590
        DateTimeNames {
×
2591
            inner: self.inner.cast_into_fset(),
×
2592
            calendar: self.calendar,
×
2593
        }
2594
    }
×
2595
}
2596

2597
impl<FSet: DateTimeNamesMarker> RawDateTimeNames<FSet> {
2598
    pub(crate) fn new_without_number_formatting() -> Self {
34✔
2599
        Self {
34✔
2600
            year_names: <FSet::YearNames as NamesContainer<
34✔
2601
                YearNamesV1,
2602
                YearNameLength,
2603
            >>::Container::new_empty(),
2604
            month_names: <FSet::MonthNames as NamesContainer<
34✔
2605
                MonthNamesV1,
2606
                MonthNameLength,
2607
            >>::Container::new_empty(),
2608
            weekday_names: <FSet::WeekdayNames as NamesContainer<
34✔
2609
                WeekdayNamesV1,
2610
                WeekdayNameLength,
2611
            >>::Container::new_empty(),
2612
            dayperiod_names: <FSet::DayPeriodNames as NamesContainer<
34✔
2613
                DayPeriodNamesV1,
2614
                DayPeriodNameLength,
2615
            >>::Container::new_empty(),
2616
            zone_essentials: <FSet::ZoneEssentials as NamesContainer<
34✔
2617
                tz::EssentialsV1,
2618
                (),
2619
            >>::Container::new_empty(),
2620
            locations_root: <FSet::ZoneLocationsRoot as NamesContainer<
34✔
2621
                tz::LocationsRootV1,
2622
                (),
2623
            >>::Container::new_empty(),
2624
            locations: <FSet::ZoneLocations as NamesContainer<
34✔
2625
                tz::LocationsV1,
2626
                (),
2627
            >>::Container::new_empty(),
2628
            exemplars: <FSet::ZoneExemplars as NamesContainer<
34✔
2629
                tz::ExemplarCitiesV1,
2630
                (),
2631
            >>::Container::new_empty(),
2632
            exemplars_root: <FSet::ZoneExemplarsRoot as NamesContainer<
34✔
2633
                tz::ExemplarCitiesRootV1,
2634
                (),
2635
            >>::Container::new_empty(),
2636
            mz_generic_long: <FSet::ZoneGenericLong as NamesContainer<
34✔
2637
                tz::MzGenericLongV1,
2638
                (),
2639
            >>::Container::new_empty(),
2640
            mz_generic_short: <FSet::ZoneGenericShort as NamesContainer<
34✔
2641
                tz::MzGenericShortV1,
2642
                (),
2643
            >>::Container::new_empty(),
2644
            mz_standard_long: <FSet::ZoneStandardLong as NamesContainer<
34✔
2645
                tz::MzStandardLongV1,
2646
                (),
2647
            >>::Container::new_empty(),
2648
            mz_specific_long: <FSet::ZoneSpecificLong as NamesContainer<
34✔
2649
                tz::MzSpecificLongV1,
2650
                (),
2651
            >>::Container::new_empty(),
2652
            mz_specific_short: <FSet::ZoneSpecificShort as NamesContainer<
34✔
2653
                tz::MzSpecificShortV1,
2654
                (),
2655
            >>::Container::new_empty(),
2656
            mz_periods: <FSet::MetazoneLookup as NamesContainer<
34✔
2657
                tz::MzPeriodV1,
2658
                (),
2659
            >>::Container::new_empty(),
2660
            decimal_formatter: None,
34✔
2661
            _marker: PhantomData,
2662
        }
×
2663
    }
34✔
2664

2665
    pub(crate) fn as_borrowed(&self) -> RawDateTimeNamesBorrowed {
36✔
2666
        RawDateTimeNamesBorrowed {
36✔
2667
            year_names: self.year_names.get().inner,
36✔
2668
            month_names: self.month_names.get().inner,
36✔
2669
            weekday_names: self.weekday_names.get().inner,
36✔
2670
            dayperiod_names: self.dayperiod_names.get().inner,
36✔
2671
            zone_essentials: self.zone_essentials.get().inner,
36✔
2672
            locations_root: self.locations_root.get().inner,
36✔
2673
            locations: self.locations.get().inner,
36✔
2674
            exemplars_root: self.exemplars_root.get().inner,
36✔
2675
            exemplars: self.exemplars.get().inner,
36✔
2676
            mz_generic_long: self.mz_generic_long.get().inner,
36✔
2677
            mz_generic_short: self.mz_generic_short.get().inner,
36✔
2678
            mz_standard_long: self.mz_standard_long.get().inner,
36✔
2679
            mz_specific_long: self.mz_specific_long.get().inner,
36✔
2680
            mz_specific_short: self.mz_specific_short.get().inner,
36✔
2681
            mz_periods: self.mz_periods.get().inner,
36✔
2682
            decimal_formatter: self.decimal_formatter.as_ref(),
36✔
2683
        }
2684
    }
36✔
2685

2686
    pub(crate) fn load_year_names<P>(
6✔
2687
        &mut self,
2688
        provider: &P,
2689
        prefs: DateTimeFormatterPreferences,
2690
        length: YearNameLength,
2691
        error_field: ErrorField,
2692
    ) -> Result<(), PatternLoadError>
2693
    where
2694
        P: BoundDataProvider<YearNamesV1> + ?Sized,
2695
    {
2696
        let attributes = length.to_attributes();
6✔
2697
        let locale = provider
12✔
2698
            .bound_marker()
2699
            .make_locale(prefs.locale_preferences);
6✔
2700
        let req = DataRequest {
6✔
2701
            id: DataIdentifierBorrowed::for_marker_attributes_and_locale(attributes, &locale),
6✔
2702
            ..Default::default()
6✔
2703
        };
2704
        self.year_names
6✔
2705
            .load_put(provider, req, length)
2706
            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
×
2707
            .map_err(|e| PatternLoadError::Data(e, error_field))?;
×
2708
        Ok(())
6✔
2709
    }
6✔
2710

2711
    pub(crate) fn load_month_names<P>(
7✔
2712
        &mut self,
2713
        provider: &P,
2714
        prefs: DateTimeFormatterPreferences,
2715
        length: MonthNameLength,
2716
        error_field: ErrorField,
2717
    ) -> Result<(), PatternLoadError>
2718
    where
2719
        P: BoundDataProvider<MonthNamesV1> + ?Sized,
2720
    {
2721
        let attributes = length.to_attributes();
7✔
2722
        let locale = provider
14✔
2723
            .bound_marker()
2724
            .make_locale(prefs.locale_preferences);
7✔
2725
        let req = DataRequest {
7✔
2726
            id: DataIdentifierBorrowed::for_marker_attributes_and_locale(attributes, &locale),
7✔
2727
            ..Default::default()
7✔
2728
        };
2729
        self.month_names
7✔
2730
            .load_put(provider, req, length)
2731
            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
×
2732
            .map_err(|e| PatternLoadError::Data(e, error_field))?;
×
2733
        Ok(())
7✔
2734
    }
7✔
2735

2736
    pub(crate) fn load_day_period_names<P>(
11✔
2737
        &mut self,
2738
        provider: &P,
2739
        prefs: DateTimeFormatterPreferences,
2740
        length: DayPeriodNameLength,
2741
        error_field: ErrorField,
2742
    ) -> Result<(), PatternLoadError>
2743
    where
2744
        P: BoundDataProvider<DayPeriodNamesV1> + ?Sized,
2745
    {
2746
        let attributes = length.to_attributes();
11✔
2747
        let locale = provider
22✔
2748
            .bound_marker()
2749
            .make_locale(prefs.locale_preferences);
11✔
2750
        let req = DataRequest {
11✔
2751
            id: DataIdentifierBorrowed::for_marker_attributes_and_locale(attributes, &locale),
11✔
2752
            ..Default::default()
11✔
2753
        };
2754
        self.dayperiod_names
11✔
2755
            .load_put(provider, req, length)
2756
            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
×
2757
            .map_err(|e| PatternLoadError::Data(e, error_field))?;
×
2758
        Ok(())
11✔
2759
    }
11✔
2760

2761
    pub(crate) fn load_weekday_names<P>(
15✔
2762
        &mut self,
2763
        provider: &P,
2764
        prefs: DateTimeFormatterPreferences,
2765
        length: WeekdayNameLength,
2766
        error_field: ErrorField,
2767
    ) -> Result<(), PatternLoadError>
2768
    where
2769
        P: BoundDataProvider<WeekdayNamesV1> + ?Sized,
2770
    {
2771
        let attributes = length.to_attributes();
15✔
2772
        let locale = provider
30✔
2773
            .bound_marker()
2774
            .make_locale(prefs.locale_preferences);
15✔
2775
        let req = DataRequest {
15✔
2776
            id: DataIdentifierBorrowed::for_marker_attributes_and_locale(attributes, &locale),
15✔
2777
            ..Default::default()
15✔
2778
        };
2779
        self.weekday_names
15✔
2780
            .load_put(provider, req, length)
2781
            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
×
2782
            .map_err(|e| PatternLoadError::Data(e, error_field))?;
×
2783
        Ok(())
15✔
2784
    }
15✔
2785

2786
    pub(crate) fn load_time_zone_essentials<P>(
×
2787
        &mut self,
2788
        provider: &P,
2789
        prefs: DateTimeFormatterPreferences,
2790
    ) -> Result<ErrorField, PatternLoadError>
2791
    where
2792
        P: BoundDataProvider<tz::EssentialsV1> + ?Sized,
2793
    {
2794
        let locale = provider
×
2795
            .bound_marker()
2796
            .make_locale(prefs.locale_preferences);
×
2797
        let error_field = ErrorField(fields::Field {
×
2798
            symbol: FieldSymbol::TimeZone(fields::TimeZone::LocalizedOffset),
×
2799
            length: FieldLength::Four,
×
2800
        });
2801
        let variables = ();
×
2802
        let req = DataRequest {
×
2803
            id: DataIdentifierBorrowed::for_locale(&locale),
×
2804
            ..Default::default()
×
2805
        };
2806
        self.zone_essentials
×
2807
            .load_put(provider, req, variables)
2808
            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
×
2809
            .map_err(|e| PatternLoadError::Data(e, error_field))?;
×
2810
        Ok(error_field)
×
2811
    }
×
2812

2813
    pub(crate) fn load_time_zone_location_names<P, P2>(
×
2814
        &mut self,
2815
        provider: &P,
2816
        root_provider: &P2,
2817
        prefs: DateTimeFormatterPreferences,
2818
    ) -> Result<ErrorField, PatternLoadError>
2819
    where
2820
        P: BoundDataProvider<tz::LocationsV1> + ?Sized,
2821
        P2: BoundDataProvider<tz::LocationsRootV1> + ?Sized,
2822
    {
2823
        let locale = provider
×
2824
            .bound_marker()
2825
            .make_locale(prefs.locale_preferences);
×
2826
        let error_field = ErrorField(fields::Field {
×
2827
            symbol: FieldSymbol::TimeZone(fields::TimeZone::Location),
×
2828
            length: FieldLength::Four,
×
2829
        });
2830
        let variables = ();
×
2831
        let req = DataRequest {
×
2832
            id: DataIdentifierBorrowed::for_locale(&locale),
×
2833
            ..Default::default()
×
2834
        };
2835
        self.locations_root
×
2836
            .load_put(root_provider, req, variables)
2837
            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
×
2838
            .map_err(|e| PatternLoadError::Data(e, error_field))?;
×
2839
        self.locations
×
2840
            .load_put(provider, req, variables)
2841
            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
×
2842
            .map_err(|e| PatternLoadError::Data(e, error_field))?;
×
2843
        Ok(error_field)
×
2844
    }
×
2845

2846
    pub(crate) fn load_time_zone_exemplar_city_names<P, P2>(
×
2847
        &mut self,
2848
        provider: &P,
2849
        root_provider: &P2,
2850
        prefs: DateTimeFormatterPreferences,
2851
    ) -> Result<ErrorField, PatternLoadError>
2852
    where
2853
        P: BoundDataProvider<tz::ExemplarCitiesV1> + ?Sized,
2854
        P2: BoundDataProvider<tz::ExemplarCitiesRootV1> + ?Sized,
2855
    {
2856
        let locale = provider
×
2857
            .bound_marker()
2858
            .make_locale(prefs.locale_preferences);
×
2859
        let error_field = ErrorField(fields::Field {
×
2860
            symbol: FieldSymbol::TimeZone(fields::TimeZone::Location),
×
2861
            length: FieldLength::Three,
×
2862
        });
2863
        let variables = ();
×
2864
        let req = DataRequest {
×
2865
            id: DataIdentifierBorrowed::for_locale(&locale),
×
2866
            ..Default::default()
×
2867
        };
2868
        self.exemplars_root
×
2869
            .load_put(root_provider, req, variables)
2870
            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
×
2871
            .map_err(|e| PatternLoadError::Data(e, error_field))?;
×
2872
        self.exemplars
×
2873
            .load_put(provider, req, variables)
2874
            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
×
2875
            .map_err(|e| PatternLoadError::Data(e, error_field))?;
×
2876
        Ok(error_field)
×
2877
    }
×
2878

2879
    pub(crate) fn load_time_zone_generic_long_names(
×
2880
        &mut self,
2881
        mz_generic_provider: &(impl BoundDataProvider<tz::MzGenericLongV1> + ?Sized),
2882
        mz_standard_provider: &(impl BoundDataProvider<tz::MzStandardLongV1> + ?Sized),
2883
        mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
2884
        prefs: DateTimeFormatterPreferences,
2885
    ) -> Result<ErrorField, PatternLoadError> {
2886
        let locale = mz_generic_provider
×
2887
            .bound_marker()
2888
            .make_locale(prefs.locale_preferences);
×
2889
        let error_field = ErrorField(fields::Field {
×
2890
            symbol: FieldSymbol::TimeZone(fields::TimeZone::GenericNonLocation),
×
2891
            length: FieldLength::Four,
×
2892
        });
2893
        let variables = ();
×
2894
        let req = DataRequest {
×
2895
            id: DataIdentifierBorrowed::for_locale(&locale),
×
2896
            ..Default::default()
×
2897
        };
2898
        let cs1 = self
×
2899
            .mz_generic_long
2900
            .load_put(mz_generic_provider, req, variables)
2901
            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
×
2902
            .map_err(|e| PatternLoadError::Data(e, error_field))?
×
2903
            .checksum;
2904
        let cs2 = self
×
2905
            .mz_standard_long
2906
            .load_put(mz_standard_provider, req, variables)
2907
            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
×
2908
            .map_err(|e| PatternLoadError::Data(e, error_field))?
×
2909
            .checksum;
2910
        let cs3 = self
×
2911
            .mz_periods
2912
            .load_put(mz_period_provider, Default::default(), ())
×
2913
            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
×
2914
            .map_err(|e| PatternLoadError::Data(e, error_field))?
×
2915
            .checksum;
2916
        if cs1 != cs2 || cs1 != cs3 {
×
2917
            return Err(PatternLoadError::Data(
×
2918
                DataErrorKind::InconsistentData(tz::MzPeriodV1::INFO)
×
2919
                    .with_req(tz::MzGenericLongV1::INFO, req),
2920
                error_field,
2921
            ));
2922
        }
2923
        Ok(error_field)
×
2924
    }
×
2925

2926
    pub(crate) fn load_time_zone_generic_short_names(
×
2927
        &mut self,
2928
        provider: &(impl BoundDataProvider<tz::MzGenericShortV1> + ?Sized),
2929
        mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
2930
        prefs: DateTimeFormatterPreferences,
2931
    ) -> Result<ErrorField, PatternLoadError> {
2932
        let locale = provider
×
2933
            .bound_marker()
2934
            .make_locale(prefs.locale_preferences);
×
2935
        let error_field = ErrorField(fields::Field {
×
2936
            symbol: FieldSymbol::TimeZone(fields::TimeZone::GenericNonLocation),
×
2937
            length: FieldLength::One,
×
2938
        });
2939
        let variables = ();
×
2940
        let req = DataRequest {
×
2941
            id: DataIdentifierBorrowed::for_locale(&locale),
×
2942
            ..Default::default()
×
2943
        };
2944
        let cs1 = self
×
2945
            .mz_generic_short
2946
            .load_put(provider, req, variables)
2947
            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
×
2948
            .map_err(|e| PatternLoadError::Data(e, error_field))?
×
2949
            .checksum;
2950
        let cs2 = self
×
2951
            .mz_periods
2952
            .load_put(mz_period_provider, Default::default(), ())
×
2953
            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
×
2954
            .map_err(|e| PatternLoadError::Data(e, error_field))?
×
2955
            .checksum;
2956
        if cs1 != cs2 {
×
2957
            return Err(PatternLoadError::Data(
×
2958
                DataErrorKind::InconsistentData(tz::MzPeriodV1::INFO)
×
2959
                    .with_req(tz::MzGenericShortV1::INFO, req),
2960
                error_field,
2961
            ));
2962
        }
2963
        Ok(error_field)
×
2964
    }
×
2965

2966
    pub(crate) fn load_time_zone_specific_long_names(
×
2967
        &mut self,
2968
        mz_specific_provider: &(impl BoundDataProvider<tz::MzSpecificLongV1> + ?Sized),
2969
        mz_standard_provider: &(impl BoundDataProvider<tz::MzStandardLongV1> + ?Sized),
2970
        mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
2971
        prefs: DateTimeFormatterPreferences,
2972
    ) -> Result<ErrorField, PatternLoadError> {
2973
        let locale = mz_specific_provider
×
2974
            .bound_marker()
2975
            .make_locale(prefs.locale_preferences);
×
2976
        let error_field = ErrorField(fields::Field {
×
2977
            symbol: FieldSymbol::TimeZone(fields::TimeZone::SpecificNonLocation),
×
2978
            length: FieldLength::Four,
×
2979
        });
2980
        let variables = ();
×
2981
        let req = DataRequest {
×
2982
            id: DataIdentifierBorrowed::for_locale(&locale),
×
2983
            ..Default::default()
×
2984
        };
2985
        let cs1 = self
×
2986
            .mz_specific_long
2987
            .load_put(mz_specific_provider, req, variables)
2988
            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
×
2989
            .map_err(|e| PatternLoadError::Data(e, error_field))?
×
2990
            .checksum;
2991
        let cs2 = self
×
2992
            .mz_standard_long
2993
            .load_put(mz_standard_provider, req, variables)
2994
            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
×
2995
            .map_err(|e| PatternLoadError::Data(e, error_field))?
×
2996
            .checksum;
2997
        let cs3 = self
×
2998
            .mz_periods
2999
            .load_put(mz_period_provider, Default::default(), ())
×
3000
            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
×
3001
            .map_err(|e| PatternLoadError::Data(e, error_field))?
×
3002
            .checksum;
3003
        if cs1 != cs2 || cs1 != cs3 {
×
3004
            return Err(PatternLoadError::Data(
×
3005
                DataErrorKind::InconsistentData(tz::MzPeriodV1::INFO)
×
3006
                    .with_req(tz::MzSpecificLongV1::INFO, req),
3007
                error_field,
3008
            ));
3009
        }
3010
        Ok(error_field)
×
3011
    }
×
3012

3013
    pub(crate) fn load_time_zone_specific_short_names(
×
3014
        &mut self,
3015
        provider: &(impl BoundDataProvider<tz::MzSpecificShortV1> + ?Sized),
3016
        mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3017
        prefs: DateTimeFormatterPreferences,
3018
    ) -> Result<ErrorField, PatternLoadError> {
3019
        let locale = provider
×
3020
            .bound_marker()
3021
            .make_locale(prefs.locale_preferences);
×
3022
        let error_field = ErrorField(fields::Field {
×
3023
            symbol: FieldSymbol::TimeZone(fields::TimeZone::SpecificNonLocation),
×
3024
            length: FieldLength::One,
×
3025
        });
3026
        let variables = ();
×
3027
        let req = DataRequest {
×
3028
            id: DataIdentifierBorrowed::for_locale(&locale),
×
3029
            ..Default::default()
×
3030
        };
3031
        let cs1 = self
×
3032
            .mz_specific_short
3033
            .load_put(provider, req, variables)
3034
            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
×
3035
            .map_err(|e| PatternLoadError::Data(e, error_field))?
×
3036
            .checksum;
3037
        let cs2 = self
×
3038
            .mz_periods
3039
            .load_put(mz_period_provider, Default::default(), ())
×
3040
            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
×
3041
            .map_err(|e| PatternLoadError::Data(e, error_field))?
×
3042
            .checksum;
3043
        if cs1 != cs2 {
×
3044
            return Err(PatternLoadError::Data(
×
3045
                DataErrorKind::InconsistentData(tz::MzPeriodV1::INFO)
×
3046
                    .with_req(tz::MzSpecificShortV1::INFO, req),
3047
                error_field,
3048
            ));
3049
        }
3050
        Ok(error_field)
×
3051
    }
×
3052

3053
    pub(crate) fn load_time_zone_field_z_except_decimals(
×
3054
        &mut self,
3055
        zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3056
        mz_specific_short_provider: &(impl BoundDataProvider<tz::MzSpecificShortV1> + ?Sized),
3057
        mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3058
        prefs: DateTimeFormatterPreferences,
3059
    ) -> Result<ErrorField, PatternLoadError> {
3060
        self.load_time_zone_essentials(zone_essentials_provider, prefs)?;
×
3061
        self.load_time_zone_specific_short_names(
×
3062
            mz_specific_short_provider,
3063
            mz_period_provider,
3064
            prefs,
3065
        )
3066
    }
×
3067

3068
    #[allow(clippy::too_many_arguments)]
3069
    pub(crate) fn load_time_zone_field_zzzz_except_decimals(
×
3070
        &mut self,
3071
        zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3072
        locations_provider: &(impl BoundDataProvider<tz::LocationsV1> + ?Sized),
3073
        locations_root_provider: &(impl BoundDataProvider<tz::LocationsRootV1> + ?Sized),
3074
        mz_standard_long_provider: &(impl BoundDataProvider<tz::MzStandardLongV1> + ?Sized),
3075
        mz_specific_long_provider: &(impl BoundDataProvider<tz::MzSpecificLongV1> + ?Sized),
3076
        mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3077
        prefs: DateTimeFormatterPreferences,
3078
    ) -> Result<ErrorField, PatternLoadError> {
3079
        self.load_time_zone_essentials(zone_essentials_provider, prefs)?;
×
3080
        self.load_time_zone_location_names(locations_provider, locations_root_provider, prefs)?;
×
3081
        self.load_time_zone_specific_long_names(
×
3082
            mz_specific_long_provider,
3083
            mz_standard_long_provider,
3084
            mz_period_provider,
3085
            prefs,
3086
        )
3087
    }
×
3088

3089
    pub(crate) fn load_time_zone_field_v_except_decimals(
×
3090
        &mut self,
3091
        zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3092
        locations_provider: &(impl BoundDataProvider<tz::LocationsV1> + ?Sized),
3093
        locations_root_provider: &(impl BoundDataProvider<tz::LocationsRootV1> + ?Sized),
3094
        mz_generic_short_provider: &(impl BoundDataProvider<tz::MzGenericShortV1> + ?Sized),
3095
        mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3096
        prefs: DateTimeFormatterPreferences,
3097
    ) -> Result<ErrorField, PatternLoadError> {
3098
        self.load_time_zone_essentials(zone_essentials_provider, prefs)?;
×
3099
        // For fallback:
3100
        self.load_time_zone_location_names(locations_provider, locations_root_provider, prefs)?;
×
3101
        self.load_time_zone_generic_short_names(
×
3102
            mz_generic_short_provider,
3103
            mz_period_provider,
3104
            prefs,
3105
        )
3106
    }
×
3107

3108
    #[allow(clippy::too_many_arguments)]
3109
    pub(crate) fn load_time_zone_field_vvvv_except_decimals(
×
3110
        &mut self,
3111
        zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3112
        locations_provider: &(impl BoundDataProvider<tz::LocationsV1> + ?Sized),
3113
        locations_root_provider: &(impl BoundDataProvider<tz::LocationsRootV1> + ?Sized),
3114
        mz_generic_long_provider: &(impl BoundDataProvider<tz::MzGenericLongV1> + ?Sized),
3115
        mz_standard_long_provider: &(impl BoundDataProvider<tz::MzStandardLongV1> + ?Sized),
3116
        mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3117
        prefs: DateTimeFormatterPreferences,
3118
    ) -> Result<ErrorField, PatternLoadError> {
3119
        self.load_time_zone_essentials(zone_essentials_provider, prefs)?;
×
3120
        // For fallback:
3121
        self.load_time_zone_location_names(locations_provider, locations_root_provider, prefs)?;
×
3122
        self.load_time_zone_generic_long_names(
×
3123
            mz_generic_long_provider,
3124
            mz_standard_long_provider,
3125
            mz_period_provider,
3126
            prefs,
3127
        )
3128
    }
×
3129

3130
    #[allow(non_snake_case)] // this is a private function named after the case-sensitive CLDR field
3131
    pub(crate) fn load_time_zone_field_V(
×
3132
        &mut self,
3133
        _prefs: DateTimeFormatterPreferences,
3134
    ) -> Result<(), PatternLoadError> {
3135
        // no data required
3136
        Ok(())
×
3137
    }
×
3138

3139
    #[allow(non_snake_case)] // this is a private function named after the case-sensitive CLDR field
3140
    pub(crate) fn load_time_zone_field_VVV(
×
3141
        &mut self,
3142
        locations_provider: &(impl BoundDataProvider<tz::LocationsV1> + ?Sized),
3143
        locations_root_provider: &(impl BoundDataProvider<tz::LocationsRootV1> + ?Sized),
3144
        exemplar_cities_provider: &(impl BoundDataProvider<tz::ExemplarCitiesV1> + ?Sized),
3145
        exemplar_cities_root_provider: &(impl BoundDataProvider<tz::ExemplarCitiesRootV1> + ?Sized),
3146
        prefs: DateTimeFormatterPreferences,
3147
    ) -> Result<ErrorField, PatternLoadError> {
3148
        self.load_time_zone_location_names(locations_provider, locations_root_provider, prefs)?;
×
3149
        self.load_time_zone_exemplar_city_names(
×
3150
            exemplar_cities_provider,
3151
            exemplar_cities_root_provider,
3152
            prefs,
3153
        )
3154
    }
×
3155

3156
    #[allow(non_snake_case)] // this is a private function named after the case-sensitive CLDR field
3157
    pub(crate) fn load_time_zone_field_VVVV_except_decimals(
×
3158
        &mut self,
3159
        zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3160
        locations_provider: &(impl BoundDataProvider<tz::LocationsV1> + ?Sized),
3161
        locations_root_provider: &(impl BoundDataProvider<tz::LocationsRootV1> + ?Sized),
3162
        prefs: DateTimeFormatterPreferences,
3163
    ) -> Result<ErrorField, PatternLoadError> {
3164
        self.load_time_zone_essentials(zone_essentials_provider, prefs)?;
×
3165
        self.load_time_zone_location_names(locations_provider, locations_root_provider, prefs)
×
3166
    }
×
3167

3168
    #[allow(non_snake_case)] // this is a private function named after the case-sensitive CLDR field
3169
    pub(crate) fn load_time_zone_field_O_except_decimals(
×
3170
        &mut self,
3171
        zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3172
        prefs: DateTimeFormatterPreferences,
3173
    ) -> Result<ErrorField, PatternLoadError> {
3174
        self.load_time_zone_essentials(zone_essentials_provider, prefs)
×
3175
    }
×
3176

3177
    #[allow(non_snake_case)] // this is a private function named after the case-sensitive CLDR field
3178
    pub(crate) fn load_time_zone_field_X(
×
3179
        &mut self,
3180
        _prefs: DateTimeFormatterPreferences,
3181
    ) -> Result<(), PatternLoadError> {
3182
        // no data required
3183
        Ok(())
×
3184
    }
×
3185

3186
    pub(crate) fn load_decimal_formatter(
35✔
3187
        &mut self,
3188
        loader: &impl DecimalFormatterLoader,
3189
        prefs: DateTimeFormatterPreferences,
3190
    ) -> Result<(), DataError> {
3191
        if self.decimal_formatter.is_some() {
35✔
3192
            return Ok(());
×
3193
        }
3194
        let mut options = DecimalFormatterOptions::default();
35✔
3195
        options.grouping_strategy = Some(GroupingStrategy::Never);
35✔
3196
        self.decimal_formatter = Some(DecimalFormatterLoader::load(
35✔
3197
            loader,
3198
            (&prefs).into(),
35✔
3199
            options,
35✔
3200
        )?);
×
3201
        Ok(())
35✔
3202
    }
35✔
3203

3204
    /// Loads all data required for formatting the given [`PatternItem`]s.
3205
    ///
3206
    /// This function has a lot of arguments because many of the arguments are generic,
3207
    /// and pulling them out to an options struct would be cumbersome.
3208
    #[allow(clippy::too_many_arguments)]
3209
    pub(crate) fn load_for_pattern(
×
3210
        &mut self,
3211
        year_provider: &(impl BoundDataProvider<YearNamesV1> + ?Sized),
3212
        month_provider: &(impl BoundDataProvider<MonthNamesV1> + ?Sized),
3213
        weekday_provider: &(impl BoundDataProvider<WeekdayNamesV1> + ?Sized),
3214
        dayperiod_provider: &(impl BoundDataProvider<DayPeriodNamesV1> + ?Sized),
3215
        zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3216
        locations_provider: &(impl BoundDataProvider<tz::LocationsV1> + ?Sized),
3217
        locations_root_provider: &(impl BoundDataProvider<tz::LocationsRootV1> + ?Sized),
3218
        exemplar_cities_provider: &(impl BoundDataProvider<tz::ExemplarCitiesV1> + ?Sized),
3219
        exemplar_cities_root_provider: &(impl BoundDataProvider<tz::ExemplarCitiesRootV1> + ?Sized),
3220
        mz_generic_long_provider: &(impl BoundDataProvider<tz::MzGenericLongV1> + ?Sized),
3221
        mz_generic_short_provider: &(impl BoundDataProvider<tz::MzGenericShortV1> + ?Sized),
3222
        mz_standard_long_provider: &(impl BoundDataProvider<tz::MzStandardLongV1> + ?Sized),
3223
        mz_specific_long_provider: &(impl BoundDataProvider<tz::MzSpecificLongV1> + ?Sized),
3224
        mz_specific_short_provider: &(impl BoundDataProvider<tz::MzSpecificShortV1> + ?Sized),
3225
        mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3226
        decimal_formatter_loader: &impl DecimalFormatterLoader,
3227
        prefs: DateTimeFormatterPreferences,
3228
        pattern_items: impl Iterator<Item = PatternItem>,
3229
    ) -> Result<(), PatternLoadError> {
3230
        let mut numeric_field = None;
×
3231

3232
        for item in pattern_items {
×
3233
            let PatternItem::Field(field) = item else {
×
3234
                continue;
3235
            };
3236
            let error_field = ErrorField(field);
×
3237

3238
            use crate::provider::fields::*;
3239
            use FieldLength::*;
3240
            use FieldSymbol as FS;
3241

3242
            match (field.symbol, field.length) {
×
3243
                ///// Textual symbols /////
3244

3245
                // G..GGGGG
3246
                (FS::Era, One | Two | Three | Four | Five) => {
3247
                    self.load_year_names(
×
3248
                        year_provider,
3249
                        prefs,
3250
                        YearNameLength::from_field_length(field.length)
×
3251
                            .ok_or(PatternLoadError::UnsupportedLength(error_field))?,
×
3252
                        error_field,
3253
                    )?;
×
3254
                }
3255

3256
                // U..UUUUU
3257
                (FS::Year(Year::Cyclic), One | Two | Three | Four | Five) => {
3258
                    numeric_field = Some(field);
×
3259
                    self.load_year_names(
×
3260
                        year_provider,
3261
                        prefs,
3262
                        YearNameLength::from_field_length(field.length)
×
3263
                            .ok_or(PatternLoadError::UnsupportedLength(error_field))?,
×
3264
                        error_field,
3265
                    )?;
×
3266
                }
3267

3268
                // MMM..MMMMM, LLL..LLLLL
3269
                (
3270
                    FS::Month(field_symbol @ Month::Format | field_symbol @ Month::StandAlone),
×
3271
                    Three | Four | Five,
3272
                ) => {
3273
                    self.load_month_names(
×
3274
                        month_provider,
3275
                        prefs,
3276
                        MonthNameLength::from_field(field_symbol, field.length)
×
3277
                            .ok_or(PatternLoadError::UnsupportedLength(error_field))?,
×
3278
                        error_field,
3279
                    )?;
×
3280
                }
3281

3282
                // e..ee, c..cc
3283
                (FS::Weekday(Weekday::Local | Weekday::StandAlone), One | Two) => {
3284
                    // TODO(#5643): Requires locale-aware day-of-week calculation
3285
                    return Err(PatternLoadError::UnsupportedLength(ErrorField(field)));
×
3286
                }
3287

3288
                // E..EEEEEE, eee..eeeeee, ccc..cccccc
3289
                (FS::Weekday(field_symbol), One | Two | Three | Four | Five | Six) => {
×
3290
                    self.load_weekday_names(
×
3291
                        weekday_provider,
3292
                        prefs,
3293
                        WeekdayNameLength::from_field(field_symbol, field.length)
×
3294
                            .ok_or(PatternLoadError::UnsupportedLength(error_field))?,
×
3295
                        error_field,
3296
                    )?;
×
3297
                }
3298

3299
                // a..aaaaa, b..bbbbb
3300
                (FS::DayPeriod(field_symbol), One | Two | Three | Four | Five) => {
×
3301
                    self.load_day_period_names(
×
3302
                        dayperiod_provider,
3303
                        prefs,
3304
                        DayPeriodNameLength::from_field(field_symbol, field.length)
×
3305
                            .ok_or(PatternLoadError::UnsupportedLength(error_field))?,
×
3306
                        error_field,
3307
                    )?;
×
3308
                }
3309

3310
                ///// Time zone symbols /////
3311

3312
                // z..zzz
3313
                (FS::TimeZone(TimeZone::SpecificNonLocation), One | Two | Three) => {
×
3314
                    self.load_time_zone_field_z_except_decimals(
×
3315
                        zone_essentials_provider,
3316
                        mz_specific_short_provider,
3317
                        mz_period_provider,
3318
                        prefs,
3319
                    )?;
×
3320
                    numeric_field = Some(field);
×
3321
                }
3322
                // zzzz
3323
                (FS::TimeZone(TimeZone::SpecificNonLocation), Four) => {
×
3324
                    self.load_time_zone_field_zzzz_except_decimals(
×
3325
                        zone_essentials_provider,
3326
                        locations_provider,
3327
                        locations_root_provider,
3328
                        mz_standard_long_provider,
3329
                        mz_specific_long_provider,
3330
                        mz_period_provider,
3331
                        prefs,
3332
                    )?;
×
3333
                    numeric_field = Some(field);
×
3334
                }
3335
                // v
3336
                (FS::TimeZone(TimeZone::GenericNonLocation), One) => {
×
3337
                    self.load_time_zone_field_v_except_decimals(
×
3338
                        zone_essentials_provider,
3339
                        locations_provider,
3340
                        locations_root_provider,
3341
                        mz_generic_short_provider,
3342
                        mz_period_provider,
3343
                        prefs,
3344
                    )?;
×
3345
                    numeric_field = Some(field);
×
3346
                }
3347
                // vvvv
3348
                (FS::TimeZone(TimeZone::GenericNonLocation), Four) => {
×
3349
                    self.load_time_zone_field_vvvv_except_decimals(
×
3350
                        zone_essentials_provider,
3351
                        locations_provider,
3352
                        locations_root_provider,
3353
                        mz_generic_long_provider,
3354
                        mz_standard_long_provider,
3355
                        mz_period_provider,
3356
                        prefs,
3357
                    )?;
×
3358
                    numeric_field = Some(field);
×
3359
                }
3360

3361
                // V
3362
                (FS::TimeZone(TimeZone::Location), One) => {
3363
                    self.load_time_zone_field_V(prefs)?;
×
3364
                }
3365
                // VVV
3366
                (FS::TimeZone(TimeZone::Location), Three) => {
×
3367
                    self.load_time_zone_field_VVV(
×
3368
                        locations_provider,
3369
                        locations_root_provider,
3370
                        exemplar_cities_provider,
3371
                        exemplar_cities_root_provider,
3372
                        prefs,
3373
                    )?;
×
3374
                }
3375
                // VVVV
3376
                (FS::TimeZone(TimeZone::Location), Four) => {
×
3377
                    self.load_time_zone_field_VVVV_except_decimals(
×
3378
                        zone_essentials_provider,
3379
                        locations_provider,
3380
                        locations_root_provider,
3381
                        prefs,
3382
                    )?;
×
3383
                    numeric_field = Some(field);
×
3384
                }
3385
                // O, OOOO
3386
                (FS::TimeZone(TimeZone::LocalizedOffset), One | Four) => {
×
3387
                    self.load_time_zone_field_O_except_decimals(zone_essentials_provider, prefs)?;
×
3388
                    numeric_field = Some(field);
×
3389
                }
3390
                // X..XXXXX, x..xxxxx
3391
                (
3392
                    FS::TimeZone(TimeZone::IsoWithZ | TimeZone::Iso),
3393
                    One | Two | Three | Four | Five,
3394
                ) => {
3395
                    self.load_time_zone_field_X(prefs)?;
×
3396
                }
3397

3398
                ///// Numeric symbols /////
3399

3400
                // y+
3401
                (FS::Year(Year::Calendar), _) => numeric_field = Some(field),
×
3402
                // r+
3403
                (FS::Year(Year::RelatedIso), _) => {
3404
                    // always formats as ASCII
3405
                }
3406

3407
                // M..MM, L..LL
3408
                (FS::Month(_), One | Two) => numeric_field = Some(field),
×
3409

3410
                // d..dd
3411
                (FS::Day(Day::DayOfMonth), One | Two) => numeric_field = Some(field),
×
3412
                // D..DDD
3413
                (FS::Day(Day::DayOfYear), One | Two | Three) => numeric_field = Some(field),
×
3414
                // F
3415
                (FS::Day(Day::DayOfWeekInMonth), One) => numeric_field = Some(field),
×
3416

3417
                // K..KK, h..hh, H..HH, k..kk
3418
                (FS::Hour(_), One | Two) => numeric_field = Some(field),
×
3419

3420
                // m..mm
3421
                (FS::Minute, One | Two) => numeric_field = Some(field),
×
3422

3423
                // s..ss
3424
                (FS::Second(Second::Second), One | Two) => numeric_field = Some(field),
×
3425

3426
                // A+
3427
                (FS::Second(Second::MillisInDay), _) => numeric_field = Some(field),
×
3428

3429
                // s.S+, ss.S+ (s is modelled by length, S+ by symbol)
3430
                (FS::DecimalSecond(_), One | Two) => numeric_field = Some(field),
×
3431

3432
                ///// Unsupported symbols /////
3433
                _ => {
3434
                    return Err(PatternLoadError::UnsupportedLength(ErrorField(field)));
×
3435
                }
3436
            }
3437
        }
×
3438

3439
        if let Some(field) = numeric_field {
×
3440
            self.load_decimal_formatter(decimal_formatter_loader, prefs)
×
3441
                .map_err(|e| PatternLoadError::Data(e, ErrorField(field)))?;
×
3442
        }
3443

3444
        Ok(())
×
3445
    }
×
3446
}
3447

3448
impl RawDateTimeNamesBorrowed<'_> {
3449
    pub(crate) fn get_name_for_month(
710✔
3450
        &self,
3451
        field_symbol: fields::Month,
3452
        field_length: FieldLength,
3453
        code: MonthCode,
3454
    ) -> Result<MonthPlaceholderValue, GetNameForMonthError> {
3455
        let month_name_length = MonthNameLength::from_field(field_symbol, field_length)
1,420✔
3456
            .ok_or(GetNameForMonthError::InvalidFieldLength)?;
710✔
3457
        let month_names = self
1,420✔
3458
            .month_names
3459
            .get_with_variables(month_name_length)
3460
            .ok_or(GetNameForMonthError::NotLoaded)?;
710✔
3461
        let Some((month_number, is_leap)) = code.parsed() else {
708✔
3462
            return Err(GetNameForMonthError::InvalidMonthCode);
×
3463
        };
3464
        let Some(month_index) = month_number.checked_sub(1) else {
708✔
3465
            return Err(GetNameForMonthError::InvalidMonthCode);
×
3466
        };
3467
        let month_index = usize::from(month_index);
708✔
3468
        let name = match month_names {
708✔
3469
            MonthNames::Linear(linear) => {
594✔
3470
                if is_leap {
594✔
3471
                    None
×
3472
                } else {
3473
                    linear.get(month_index)
594✔
3474
                }
3475
            }
3476
            MonthNames::LeapLinear(leap_linear) => {
114✔
3477
                let num_months = leap_linear.len() / 2;
114✔
3478
                if is_leap {
114✔
3479
                    leap_linear.get(month_index + num_months)
39✔
3480
                } else if month_index < num_months {
75✔
3481
                    leap_linear.get(month_index)
75✔
3482
                } else {
3483
                    None
×
3484
                }
3485
            }
3486
            MonthNames::LeapNumeric(leap_numeric) => {
×
3487
                if is_leap {
×
3488
                    return Ok(MonthPlaceholderValue::NumericPattern(leap_numeric));
×
3489
                } else {
3490
                    return Ok(MonthPlaceholderValue::Numeric);
×
3491
                }
3492
            }
3493
        };
3494
        // Note: Always return `false` for the second argument since neo MonthNames
3495
        // knows how to handle leap months and we don't need the fallback logic
3496
        name.map(MonthPlaceholderValue::PlainString)
1,416✔
3497
            .ok_or(GetNameForMonthError::InvalidMonthCode)
708✔
3498
    }
710✔
3499

3500
    pub(crate) fn get_name_for_weekday(
576✔
3501
        &self,
3502
        field_symbol: fields::Weekday,
3503
        field_length: FieldLength,
3504
        day: icu_calendar::types::Weekday,
3505
    ) -> Result<&str, GetNameForWeekdayError> {
3506
        let weekday_name_length = WeekdayNameLength::from_field(field_symbol, field_length)
1,152✔
3507
            .ok_or(GetNameForWeekdayError::InvalidFieldLength)?;
576✔
3508
        let weekday_names = self
1,152✔
3509
            .weekday_names
3510
            .get_with_variables(weekday_name_length)
3511
            .ok_or(GetNameForWeekdayError::NotLoaded)?;
576✔
3512
        weekday_names
1,722✔
3513
            .names
3514
            .get((day as usize) % 7)
574✔
3515
            // TODO: make weekday_names length 7 in the type system
3516
            .ok_or(GetNameForWeekdayError::NotLoaded)
574✔
3517
    }
576✔
3518

3519
    /// Gets the era symbol, or `None` if data is loaded but symbol isn't found.
3520
    ///
3521
    /// `None` should fall back to the era code directly, if, for example,
3522
    /// a japanext datetime is formatted with a `DateTimeFormat<Japanese>`
3523
    pub(crate) fn get_name_for_era(
461✔
3524
        &self,
3525
        field_length: FieldLength,
3526
        era: FormattingEra,
3527
    ) -> Result<&str, GetNameForEraError> {
3528
        let year_name_length = YearNameLength::from_field_length(field_length)
922✔
3529
            .ok_or(GetNameForEraError::InvalidFieldLength)?;
461✔
3530
        let year_names = self
922✔
3531
            .year_names
3532
            .get_with_variables(year_name_length)
3533
            .ok_or(GetNameForEraError::NotLoaded)?;
461✔
3534

3535
        match (year_names, era) {
459✔
3536
            (YearNames::VariableEras(era_names), FormattingEra::Code(era_code)) => {
18✔
3537
                crate::provider::neo::get_year_name_from_map(era_names, era_code.0.as_str().into())
36✔
3538
                    .ok_or(GetNameForEraError::InvalidEraCode)
18✔
3539
            }
3540
            (YearNames::FixedEras(era_names), FormattingEra::Index(index, _fallback)) => era_names
1,323✔
3541
                .get(index.into())
441✔
3542
                .ok_or(GetNameForEraError::InvalidEraCode),
441✔
3543
            _ => Err(GetNameForEraError::InvalidEraCode),
×
3544
        }
3545
    }
461✔
3546

3547
    pub(crate) fn get_name_for_cyclic(
63✔
3548
        &self,
3549
        field_length: FieldLength,
3550
        cyclic: NonZeroU8,
3551
    ) -> Result<&str, GetNameForCyclicYearError> {
3552
        let year_name_length = YearNameLength::from_field_length(field_length)
126✔
3553
            .ok_or(GetNameForCyclicYearError::InvalidFieldLength)?;
63✔
3554
        let year_names = self
126✔
3555
            .year_names
3556
            .get_with_variables(year_name_length)
3557
            .ok_or(GetNameForCyclicYearError::NotLoaded)?;
63✔
3558

3559
        let YearNames::Cyclic(cyclics) = year_names else {
63✔
3560
            return Err(GetNameForCyclicYearError::InvalidYearNumber { max: 0 });
×
3561
        };
3562

3563
        cyclics.get((cyclic.get() as usize) - 1).ok_or(
126✔
3564
            GetNameForCyclicYearError::InvalidYearNumber {
63✔
3565
                max: cyclics.len() + 1,
63✔
3566
            },
3567
        )
3568
    }
63✔
3569

3570
    pub(crate) fn get_name_for_day_period(
619✔
3571
        &self,
3572
        field_symbol: fields::DayPeriod,
3573
        field_length: FieldLength,
3574
        hour: icu_time::Hour,
3575
        is_top_of_hour: bool,
3576
    ) -> Result<&str, GetNameForDayPeriodError> {
3577
        use fields::DayPeriod::NoonMidnight;
3578
        let day_period_name_length = DayPeriodNameLength::from_field(field_symbol, field_length)
1,238✔
3579
            .ok_or(GetNameForDayPeriodError::InvalidFieldLength)?;
619✔
3580
        let dayperiod_names = self
1,238✔
3581
            .dayperiod_names
3582
            .get_with_variables(day_period_name_length)
3583
            .ok_or(GetNameForDayPeriodError::NotLoaded)?;
619✔
3584
        let option_value: Option<&str> = match (field_symbol, u8::from(hour), is_top_of_hour) {
617✔
3585
            (NoonMidnight, 00, true) => dayperiod_names.midnight().or_else(|| dayperiod_names.am()),
64✔
3586
            (NoonMidnight, 12, true) => dayperiod_names.noon().or_else(|| dayperiod_names.pm()),
74✔
3587
            (_, hour, _) if hour < 12 => dayperiod_names.am(),
499✔
3588
            _ => dayperiod_names.pm(),
241✔
3589
        };
3590
        option_value.ok_or(GetNameForDayPeriodError::NotLoaded)
617✔
3591
    }
619✔
3592
}
3593

3594
/// A container contains all data payloads for time zone formatting (borrowed version).
3595
#[derive(Debug, Copy, Clone, Default)]
×
3596
pub(crate) struct TimeZoneDataPayloadsBorrowed<'a> {
3597
    /// The data that contains meta information about how to display content.
3598
    pub(crate) essentials: Option<&'a tz::Essentials<'a>>,
×
3599
    /// The root location names, e.g. Italy
3600
    pub(crate) locations_root: Option<&'a tz::Locations<'a>>,
×
3601
    /// The language specific location names, e.g. Italia
3602
    pub(crate) locations: Option<&'a tz::Locations<'a>>,
×
3603
    /// The root exemplar city names, e.g. Rome
3604
    pub(crate) exemplars_root: Option<&'a tz::ExemplarCities<'a>>,
×
3605
    /// The language specific exemplar names, e.g. Roma
3606
    pub(crate) exemplars: Option<&'a tz::ExemplarCities<'a>>,
×
3607
    /// The generic long metazone names, e.g. Pacific Time
3608
    pub(crate) mz_generic_long: Option<&'a tz::MzGeneric<'a>>,
×
3609
    /// The long metazone names shared between generic and standard, e.g. Gulf Standard Time
3610
    pub(crate) mz_standard_long: Option<&'a tz::MzGeneric<'a>>,
×
3611
    /// The generic short metazone names, e.g. PT
3612
    pub(crate) mz_generic_short: Option<&'a tz::MzGeneric<'a>>,
×
3613
    /// The specific long metazone names, e.g. Pacific Daylight Time
3614
    pub(crate) mz_specific_long: Option<&'a tz::MzSpecific<'a>>,
×
3615
    /// The specific short metazone names, e.g. Pacific Daylight Time
3616
    pub(crate) mz_specific_short: Option<&'a tz::MzSpecific<'a>>,
×
3617
    /// The metazone lookup
3618
    pub(crate) mz_periods: Option<&'a tz::MzPeriod<'a>>,
×
3619
}
3620

3621
impl<'data> RawDateTimeNamesBorrowed<'data> {
3622
    pub(crate) fn get_payloads(&self) -> TimeZoneDataPayloadsBorrowed<'data> {
799✔
3623
        TimeZoneDataPayloadsBorrowed {
799✔
3624
            essentials: self.zone_essentials.get_option(),
799✔
3625
            locations_root: self.locations_root.get_option(),
799✔
3626
            locations: self.locations.get_option(),
799✔
3627
            exemplars: self.exemplars.get_option(),
799✔
3628
            exemplars_root: self.exemplars_root.get_option(),
799✔
3629
            mz_generic_long: self.mz_generic_long.get_option(),
799✔
3630
            mz_standard_long: self.mz_standard_long.get_option(),
799✔
3631
            mz_generic_short: self.mz_generic_short.get_option(),
799✔
3632
            mz_specific_long: self.mz_specific_long.get_option(),
799✔
3633
            mz_specific_short: self.mz_specific_short.get_option(),
799✔
3634
            mz_periods: self.mz_periods.get_option(),
799✔
3635
        }
3636
    }
799✔
3637
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc