icu_datetime/
fieldsets.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//! All available field sets for datetime formatting.
6//!
7//! Each field set is a struct containing options specified to that field set.
8//! The fields can either be set directly or via helper functions.
9//!
10//! This module contains _static_ field sets, which deliver the smallest binary size.
11//! If the field set is not known until runtime, use a _dynamic_ field set: [`enums`]
12//!
13//! # What is a Field Set?
14//!
15//! A field set determines what datetime fields should be printed in the localized output.
16//!
17//! Examples of field sets include:
18//!
19//! 1. Year, month, and day ([`YMD`])
20//! 2. Weekday and time ([`ET`])
21//!
22//! Field sets fit into four categories:
23//!
24//! 1. Date: fields that specify a particular day in time.
25//! 2. Calendar period: fields that specify a span of time greater than a day.
26//! 3. Time: fields that specify a time within a day.
27//! 4. Zone: fields that specify a time zone or offset from UTC.
28//!
29//! Certain combinations of field sets are allowed, too. See [`Combo`].
30//!
31//! # Examples
32//!
33//! There are two ways to configure the same field set:
34//!
35//! ```
36//! use icu::datetime::fieldsets::YMDT;
37//! use icu::datetime::options::{Alignment, TimePrecision, YearStyle};
38//!
39//! let field_set_1 = YMDT::long()
40//!     .with_year_style(YearStyle::Full)
41//!     .with_alignment(Alignment::Column)
42//!     .with_time_precision(TimePrecision::Minute);
43//!
44//! let mut field_set_2 = YMDT::long();
45//! field_set_2.year_style = Some(YearStyle::Full);
46//! field_set_2.alignment = Some(Alignment::Column);
47//! field_set_2.time_precision = Some(TimePrecision::Minute);
48//!
49//! assert_eq!(field_set_1, field_set_2);
50//! ```
51
52#[path = "builder.rs"]
53pub mod builder;
54#[path = "dynamic.rs"]
55pub mod enums;
56
57pub use crate::combo::Combo;
58
59use crate::{
60    options::*,
61    provider::{neo::*, time_zones::tz, *},
62    raw::neo::RawOptions,
63    scaffold::*,
64};
65use enums::*;
66use icu_calendar::types::{DayOfMonth, MonthInfo, Weekday, YearInfo};
67use icu_provider::marker::NeverMarker;
68use icu_time::{
69    zone::{UtcOffset, ZoneNameTimestamp},
70    Hour, Minute, Nanosecond, Second, TimeZone,
71};
72
73#[cfg(doc)]
74use icu_time::TimeZoneInfo;
75
76/// Maps the token `yes` to the given ident
77macro_rules! yes_to {
78    ($any:expr, $nonempty:expr) => {
79        $any
80    };
81}
82
83macro_rules! yes_or {
84    ($fallback:expr, $actual:expr) => {
85        $actual
86    };
87    ($fallback:expr,) => {
88        $fallback
89    };
90}
91
92macro_rules! ternary {
93    ($present:expr, $missing:expr, yes) => {
94        $present
95    };
96    ($present:expr, $missing:expr, $any:literal) => {
97        $present
98    };
99    ($present:expr, $missing:expr,) => {
100        $missing
101    };
102}
103
104/// Generates the options argument passed into the docs test constructor
105macro_rules! length_option_helper {
106    ($type:ty, $length:ident) => {
107        concat!(stringify!($type), "::", stringify!($length), "()")
108    };
109}
110
111macro_rules! impl_composite {
112    ($type:ident, $variant:ident, $enum:ident) => {
113        impl $type {
114            #[inline]
115            pub(crate) fn to_enum(self) -> $enum {
116                $enum::$type(self)
117            }
118        }
119        impl GetField<CompositeFieldSet> for $type {
120            #[inline]
121            fn get_field(&self) -> CompositeFieldSet {
122                CompositeFieldSet::$variant(self.to_enum())
123            }
124        }
125    };
126}
127
128macro_rules! impl_marker_length_constructors {
129    (
130        $type:ident,
131        $(alignment: $alignment_yes:ident,)?
132        $(year_style: $yearstyle_yes:ident,)?
133        $(time_precision: $timeprecision_yes:ident,)?
134    ) => {
135        impl $type {
136            #[doc = concat!("Creates a ", stringify!($type), " skeleton with the given formatting length.")]
137            pub const fn for_length(length: Length) -> Self {
138                Self {
139                    length,
140                    $(
141                        alignment: yes_to!(None, $alignment_yes),
142                    )?
143                    $(
144                        year_style: yes_to!(None, $yearstyle_yes),
145                    )?
146                    $(
147                        time_precision: yes_to!(None, $timeprecision_yes),
148                    )?
149                }
150            }
151            #[doc = concat!("Creates a ", stringify!($type), " skeleton with a long length.")]
152            pub const fn long() -> Self {
153                Self::for_length(Length::Long)
154            }
155            #[doc = concat!("Creates a ", stringify!($type), " skeleton with a medium length.")]
156            pub const fn medium() -> Self {
157                Self::for_length(Length::Medium)
158            }
159            #[doc = concat!("Creates a ", stringify!($type), " skeleton with a short length.")]
160            pub const fn short() -> Self {
161                Self::for_length(Length::Short)
162            }
163        }
164    };
165}
166
167macro_rules! impl_time_precision_constructors {
168    (
169        $time_type:ident,
170    ) => {
171        impl $time_type {
172            #[doc = concat!("Creates a ", stringify!($type), " that formats hours and minutes with the default length.")]
173            pub fn hm() -> Self {
174                Self::for_length(Default::default()).with_time_precision(TimePrecision::Minute)
175            }
176            #[doc = concat!("Creates a ", stringify!($type), " that formats hours, minutes, and seconds with the default length.")]
177            pub fn hms() -> Self {
178                Self::for_length(Default::default()).with_time_precision(TimePrecision::Second)
179            }
180            #[doc = concat!("Creates a ", stringify!($type), " that formats hours, minutes, seconds, and subseconds with the default length.")]
181            pub fn hmss(subsecond_digits: SubsecondDigits) -> Self {
182                Self::for_length(Default::default()).with_time_precision(TimePrecision::Subsecond(subsecond_digits))
183            }
184        }
185    };
186}
187
188macro_rules! impl_marker_with_options {
189    (
190        $(#[$attr:meta])*
191        $type:ident,
192        $(sample_length: $sample_length:ident,)?
193        $(date_fields: $date_fields:expr,)?
194        $(alignment: $alignment_yes:ident,)?
195        $(year_style: $yearstyle_yes:ident,)?
196        $(time_precision: $timeprecision_yes:ident,)?
197        $(length_override: $length_override:ident,)?
198    ) => {
199        $(#[$attr])*
200        #[derive(Debug, Copy, Clone, PartialEq, Eq)]
201        #[non_exhaustive]
202        pub struct $type {
203            $(
204                /// The desired length of the formatted string.
205                ///
206                /// See: [`Length`]
207                pub length: datetime_marker_helper!(@option/length, $sample_length),
208            )?
209            $(
210                /// Whether fields should be aligned for a column-like layout.
211                ///
212                /// See: [`Alignment`]
213                pub alignment: datetime_marker_helper!(@option/alignment, $alignment_yes),
214            )?
215            $(
216                /// When to display the era field in the formatted string.
217                ///
218                /// See: [`YearStyle`]
219                pub year_style: datetime_marker_helper!(@option/yearstyle, $yearstyle_yes),
220            )?
221            $(
222                /// How precisely to display the time of day
223                ///
224                /// See: [`TimePrecision`]
225                pub time_precision: datetime_marker_helper!(@option/timeprecision, $timeprecision_yes),
226            )?
227        }
228        impl $type {
229            pub(crate) fn to_raw_options(self) -> RawOptions {
230                RawOptions {
231                    length: yes_or!(Some(self.length), $(Some(Length::$length_override))?),
232                    date_fields: yes_or!(None, $($date_fields)?),
233                    alignment: ternary!(self.alignment, None, $($alignment_yes)?),
234                    year_style: ternary!(self.year_style, None, $($yearstyle_yes)?),
235                    time_precision: ternary!(self.time_precision, None, $($timeprecision_yes)?),
236                }
237            }
238            /// Builds this field set, removing the needed options from the builder.
239            pub(crate) fn take_from_builder(
240                options: &mut builder::FieldSetBuilder
241            ) -> Self {
242                Self {
243                    $(length: yes_to!(options.length.take().unwrap_or_default(), $sample_length),)?
244                    $(alignment: yes_to!(options.alignment.take(), $alignment_yes),)?
245                    $(year_style: yes_to!(options.year_style.take(), $yearstyle_yes),)?
246                    $(time_precision: yes_to!(options.time_precision.take(), $timeprecision_yes),)?
247                }
248            }
249        }
250        $(
251            impl $type {
252                /// Sets the length option.
253                pub const fn with_length(mut self, length: Length) -> Self {
254                    self.length = yes_to!(length, $sample_length);
255                    self
256                }
257            }
258        )?
259        $(
260            impl $type {
261                /// Sets the alignment option.
262                pub const fn with_alignment(mut self, alignment: Alignment) -> Self {
263                    self.alignment = Some(yes_to!(alignment, $alignment_yes));
264                    self
265                }
266            }
267        )?
268        $(
269            impl $type {
270                /// Sets the year style option.
271                pub const fn with_year_style(mut self, year_style: YearStyle) -> Self {
272                    self.year_style = Some(yes_to!(year_style, $yearstyle_yes));
273                    self
274                }
275            }
276        )?
277        $(
278            impl $type {
279                /// Sets the time precision option.
280                pub const fn with_time_precision(mut self, time_precision: TimePrecision) -> Self {
281                    self.time_precision = Some(yes_to!(time_precision, $timeprecision_yes));
282                    self
283                }
284            }
285        )?
286    };
287}
288
289macro_rules! impl_date_to_time_helpers {
290    (
291        $type:ident,
292        $type_time:ident,
293        $(alignment = $alignment_yes:ident,)?
294        $(year_style = $yearstyle_yes:ident,)?
295    ) => {
296        impl $type {
297            /// Associates this field set with a time precision.
298            pub fn with_time(self, time_precision: TimePrecision) -> $type_time {
299                $type_time {
300                    length: self.length,
301                    time_precision: Some(time_precision),
302                    alignment: ternary!(self.alignment, Default::default(), $($alignment_yes)?),
303                    $(year_style: yes_to!(self.year_style, $yearstyle_yes),)?
304                }
305            }
306            /// Shorthand to associate this field set with [`TimePrecision::Minute`].
307            ///
308            /// # Examples
309            ///
310            /// ```
311            #[doc = concat!("use icu::datetime::fieldsets::", stringify!($type), ";")]
312            /// use icu::datetime::options::TimePrecision;
313            ///
314            #[doc = concat!("let fs1 = ", stringify!($type), "::medium().with_time(TimePrecision::Minute);")]
315            #[doc = concat!("let fs2 = ", stringify!($type), "::medium().with_time_hm();")]
316            /// assert_eq!(fs1, fs2);
317            /// ```
318            pub fn with_time_hm(self) -> $type_time {
319                $type_time {
320                    length: self.length,
321                    time_precision: Some(TimePrecision::Minute),
322                    alignment: ternary!(self.alignment, Default::default(), $($alignment_yes)?),
323                    $(year_style: yes_to!(self.year_style, $yearstyle_yes),)?
324                }
325            }
326            /// Shorthand to associate this field set with [`TimePrecision::Second`].
327            ///
328            /// # Examples
329            ///
330            /// ```
331            #[doc = concat!("use icu::datetime::fieldsets::", stringify!($type), ";")]
332            /// use icu::datetime::options::TimePrecision;
333            ///
334            #[doc = concat!("let fs1 = ", stringify!($type), "::medium().with_time(TimePrecision::Second);")]
335            #[doc = concat!("let fs2 = ", stringify!($type), "::medium().with_time_hms();")]
336            /// assert_eq!(fs1, fs2);
337            /// ```
338            pub fn with_time_hms(self) -> $type_time {
339                $type_time {
340                    length: self.length,
341                    time_precision: Some(TimePrecision::Second),
342                    alignment: ternary!(self.alignment, Default::default(), $($alignment_yes)?),
343                    $(year_style: yes_to!(self.year_style, $yearstyle_yes),)?
344                }
345            }
346            /// Shorthand to associate this field set with [`TimePrecision::Subsecond`].
347            ///
348            /// # Examples
349            ///
350            /// ```
351            #[doc = concat!("use icu::datetime::fieldsets::", stringify!($type), ";")]
352            /// use icu::datetime::options::TimePrecision;
353            /// use icu::datetime::options::SubsecondDigits::S2;
354            ///
355            #[doc = concat!("let fs1 = ", stringify!($type), "::medium().with_time(TimePrecision::Subsecond(S2));")]
356            #[doc = concat!("let fs2 = ", stringify!($type), "::medium().with_time_hmss(S2);")]
357            /// assert_eq!(fs1, fs2);
358            /// ```
359            pub fn with_time_hmss(self, subsecond_digits: SubsecondDigits) -> $type_time {
360                $type_time {
361                    length: self.length,
362                    time_precision: Some(TimePrecision::Subsecond(subsecond_digits)),
363                    alignment: ternary!(self.alignment, Default::default(), $($alignment_yes)?),
364                    $(year_style: yes_to!(self.year_style, $yearstyle_yes),)?
365                }
366            }
367        }
368    };
369}
370
371macro_rules! impl_combo_get_field {
372    ($type:ident, $composite:ident, $enum:ident, $variant:path) => {
373        impl GetField<CompositeFieldSet> for Combo<$type, $variant> {
374            #[inline]
375            fn get_field(&self) -> CompositeFieldSet {
376                CompositeFieldSet::$composite(Combo::new(self.dt().to_enum(), self.z().to_enum()))
377            }
378        }
379        impl Combo<$type, $variant> {
380            /// Convert this specific [`Combo`] into a more general [`Combo`].
381            /// Useful when adding to the field of a [`CompositeFieldSet`].
382            ///
383            /// [`CompositeFieldSet`]: enums::CompositeFieldSet
384            pub fn into_enums(self) -> Combo<$enum, ZoneFieldSet> {
385                Combo::new(self.dt().to_enum(), self.z().to_enum())
386            }
387        }
388    };
389}
390
391macro_rules! impl_zone_combo_helpers {
392    (
393        $type:ident,
394        $composite:ident,
395        $enum:ident
396    ) => {
397        impl $type {
398            #[inline]
399            /// Associates this field set with a time zone field set.
400            pub fn with_zone<Z: ZoneMarkers>(self, zone: Z) -> Combo<Self, Z> {
401                Combo::new(self, zone)
402            }
403        }
404        impl_combo_get_field!($type, $composite, $enum, zone::SpecificLong);
405        impl_combo_get_field!($type, $composite, $enum, zone::SpecificShort);
406        impl_combo_get_field!($type, $composite, $enum, zone::LocalizedOffsetLong);
407        impl_combo_get_field!($type, $composite, $enum, zone::LocalizedOffsetShort);
408        impl_combo_get_field!($type, $composite, $enum, zone::GenericLong);
409        impl_combo_get_field!($type, $composite, $enum, zone::GenericShort);
410        impl_combo_get_field!($type, $composite, $enum, zone::Location);
411        impl_combo_get_field!($type, $composite, $enum, zone::ExemplarCity);
412        impl_combo_get_field!($type, $composite, $enum, ZoneFieldSet);
413    };
414}
415
416/// Internal helper macro used by [`impl_date_marker`] and [`impl_calendar_period_marker`]
417macro_rules! impl_date_or_calendar_period_marker {
418    (
419        $(#[$attr:meta])*
420        // The name of the type being created.
421        $type:ident,
422        // A plain language description of the field set for documentation.
423        description = $description:literal,
424        // Length of the sample string below.
425        sample_length = $sample_length:ident,
426        // A sample string. A docs test will be generated!
427        sample = $sample:literal,
428        // Whether years can occur.
429        $(years = $years_yes:ident,)?
430        // Whether months can occur.
431        $(months = $months_yes:ident,)?
432        // Whether weekdays can occur.
433        $(weekdays = $weekdays_yes:ident,)?
434        // Whether the input should contain years.
435        $(input_year = $year_yes:ident,)?
436        // Whether the input should contain months.
437        $(input_month = $month_yes:ident,)?
438        // Whether the input should contain the day of the month.
439        $(input_day_of_month = $day_of_month_yes:ident,)?
440        // Whether the input should contain the day of the week.
441        $(input_day_of_week = $day_of_week_yes:ident,)?
442        // Whether the input should contain the day of the year.
443        $(input_day_of_year = $day_of_year_yes:ident,)?
444        // Whether the input should contain the rata die.
445        $(input_rata_die = $rata_die_yes:ident,)?
446        // Whether the input should declare its calendar kind.
447        $(input_any_calendar_kind = $any_calendar_kind_yes:ident,)?
448        // Whether the alignment option should be available.
449        // According to UTS 35, it should be available with years, months, and days.
450        $(option_alignment = $option_alignment_yes:ident,)?
451    ) => {
452        impl_marker_with_options!(
453            #[doc = concat!("**“", $sample, "**” ⇒ ", $description)]
454            ///
455            /// This is a field set marker. For more information, see [`fieldsets`](crate::fieldsets).
456            ///
457            /// # Examples
458            ///
459            /// In [`DateTimeFormatter`](crate::neo::DateTimeFormatter):
460            ///
461            /// ```
462            /// use icu::datetime::input::Date;
463            /// use icu::datetime::DateTimeFormatter;
464            #[doc = concat!("use icu::datetime::fieldsets::", stringify!($type), ";")]
465            /// use icu::locale::locale;
466            /// use writeable::assert_writeable_eq;
467            #[doc = concat!("let fmt = DateTimeFormatter::<", stringify!($type), ">::try_new(")]
468            ///     locale!("en").into(),
469            #[doc = concat!("    ", length_option_helper!($type, $sample_length), ",")]
470            /// )
471            /// .unwrap();
472            /// let dt = Date::try_new_iso(2024, 5, 17).unwrap();
473            ///
474            /// assert_writeable_eq!(
475            ///     fmt.format(&dt),
476            #[doc = concat!("    \"", $sample, "\"")]
477            /// );
478            /// ```
479            ///
480            /// In [`FixedCalendarDateTimeFormatter`](crate::neo::FixedCalendarDateTimeFormatter):
481            ///
482            /// ```
483            /// use icu::datetime::input::Date;
484            /// use icu::calendar::Gregorian;
485            /// use icu::datetime::FixedCalendarDateTimeFormatter;
486            #[doc = concat!("use icu::datetime::fieldsets::", stringify!($type), ";")]
487            /// use icu::locale::locale;
488            /// use writeable::assert_writeable_eq;
489            ///
490            #[doc = concat!("let fmt = FixedCalendarDateTimeFormatter::<Gregorian, ", stringify!($type), ">::try_new(")]
491            ///     locale!("en").into(),
492            #[doc = concat!("    ", length_option_helper!($type, $sample_length), ",")]
493            /// )
494            /// .unwrap();
495            /// let dt = Date::try_new_gregorian(2024, 5, 17).unwrap();
496            ///
497            /// assert_writeable_eq!(
498            ///     fmt.format(&dt),
499            #[doc = concat!("    \"", $sample, "\"")]
500            /// );
501            /// ```
502            $(#[$attr])*
503            $type,
504            sample_length: $sample_length,
505            date_fields: Some(builder::DateFields::$type),
506            $(alignment: $option_alignment_yes,)?
507            $(year_style: $year_yes,)?
508        );
509        impl_marker_length_constructors!(
510            $type,
511            $(alignment: $option_alignment_yes,)?
512            $(year_style: $year_yes,)?
513        );
514        impl UnstableSealed for $type {}
515        impl DateTimeNamesMarker for $type {
516            type YearNames = datetime_marker_helper!(@names/year, $($years_yes)?);
517            type MonthNames = datetime_marker_helper!(@names/month, $($months_yes)?);
518            type WeekdayNames = datetime_marker_helper!(@names/weekday, $($weekdays_yes)?);
519            type DayPeriodNames = datetime_marker_helper!(@names/dayperiod,);
520            type ZoneEssentials = datetime_marker_helper!(@names/zone/essentials,);
521            type ZoneLocations = datetime_marker_helper!(@names/zone/locations,);
522            type ZoneLocationsRoot = datetime_marker_helper!(@names/zone/locations_root,);
523            type ZoneExemplars = datetime_marker_helper!(@names/zone/exemplar,);
524            type ZoneExemplarsRoot = datetime_marker_helper!(@names/zone/exemplar_root,);
525            type ZoneGenericLong = datetime_marker_helper!(@names/zone/generic_long,);
526            type ZoneGenericShort = datetime_marker_helper!(@names/zone/generic_short,);
527            type ZoneStandardLong = datetime_marker_helper!(@names/zone/standard_long,);
528            type ZoneSpecificLong = datetime_marker_helper!(@names/zone/specific_long,);
529            type ZoneSpecificShort = datetime_marker_helper!(@names/zone/specific_short,);
530            type MetazoneLookup = datetime_marker_helper!(@names/zone/metazone_periods,);
531        }
532        impl DateInputMarkers for $type {
533            type YearInput = datetime_marker_helper!(@input/year, $($year_yes)?);
534            type MonthInput = datetime_marker_helper!(@input/month, $($month_yes)?);
535            type DayOfMonthInput = datetime_marker_helper!(@input/day_of_month, $($day_of_month_yes)?);
536            type DayOfYearInput = datetime_marker_helper!(@input/day_of_year, $($day_of_year_yes)?);
537            type RataDieInput = datetime_marker_helper!(@input/rata_die, $($rata_die_yes)?);
538            type DayOfWeekInput = datetime_marker_helper!(@input/day_of_week, $($day_of_week_yes)?);
539        }
540        impl<C: CldrCalendar> TypedDateDataMarkers<C> for $type {
541            type DateSkeletonPatternsV1 = datetime_marker_helper!(@dates/typed, yes);
542            type YearNamesV1 = datetime_marker_helper!(@years/typed, $($years_yes)?);
543            type MonthNamesV1 = datetime_marker_helper!(@months/typed, $($months_yes)?);
544            type WeekdayNamesV1 = datetime_marker_helper!(@weekdays, $($weekdays_yes)?);
545        }
546        impl DateDataMarkers for $type {
547            type Skel = datetime_marker_helper!(@calmarkers, yes);
548            type Year = datetime_marker_helper!(@calmarkers, $($years_yes)?);
549            type Month = datetime_marker_helper!(@calmarkers, $($months_yes)?);
550            type WeekdayNamesV1 = datetime_marker_helper!(@weekdays, $($weekdays_yes)?);
551        }
552        impl DateTimeMarkers for $type {
553            type D = Self;
554            type T = ();
555            type Z = ();
556            type GluePatternV1 = datetime_marker_helper!(@glue,);
557        }
558    };
559}
560
561/// Implements a field set of date fields.
562///
563/// Several arguments to this macro are required, and the rest are optional.
564/// The optional arguments should be written as `key = yes,` if that parameter
565/// should be included.
566///
567/// See [`impl_date_marker`].
568macro_rules! impl_date_marker {
569    (
570        $(#[$attr:meta])*
571        $type:ident,
572        $type_time:ident,
573        description = $description:literal,
574        sample_length = $sample_length:ident,
575        sample = $sample:literal,
576        sample_time = $sample_time:literal,
577        $(years = $years_yes:ident,)?
578        $(months = $months_yes:ident,)?
579        $(dates = $dates_yes:ident,)?
580        $(weekdays = $weekdays_yes:ident,)?
581        $(input_year = $year_yes:ident,)?
582        $(input_month = $month_yes:ident,)?
583        $(input_day_of_month = $day_of_month_yes:ident,)?
584        $(input_day_of_week = $day_of_week_yes:ident,)?
585        $(input_day_of_year = $day_of_year_yes:ident,)?
586        $(input_rata_die = $rata_die_yes:ident,)?
587        $(input_any_calendar_kind = $any_calendar_kind_yes:ident,)?
588        $(option_alignment = $option_alignment_yes:ident,)?
589    ) => {
590        impl_date_or_calendar_period_marker!(
591            $(#[$attr])*
592            $type,
593            description = $description,
594            sample_length = $sample_length,
595            sample = $sample,
596            $(years = $years_yes,)?
597            $(months = $months_yes,)?
598            $(dates = $dates_yes,)?
599            $(weekdays = $weekdays_yes,)?
600            $(input_year = $year_yes,)?
601            $(input_month = $month_yes,)?
602            $(input_day_of_month = $day_of_month_yes,)?
603            $(input_day_of_week = $day_of_week_yes,)?
604            $(input_day_of_year = $day_of_year_yes,)?
605            $(input_rata_die = $rata_die_yes,)?
606            $(input_any_calendar_kind = $any_calendar_kind_yes,)?
607            $(option_alignment = $option_alignment_yes,)?
608        );
609        impl_zone_combo_helpers!($type, DateZone, DateFieldSet);
610        impl_composite!($type, Date, DateFieldSet);
611        impl_date_to_time_helpers!($type, $type_time, $(alignment = $option_alignment_yes,)? $(year_style = $year_yes,)?);
612        impl_marker_with_options!(
613            #[doc = concat!("**“", $sample_time, "**” ⇒ ", $description, " with time")]
614            ///
615            /// # Examples
616            ///
617            /// In [`DateTimeFormatter`](crate::neo::DateTimeFormatter):
618            ///
619            /// ```
620            /// use icu::datetime::input::Date;
621            /// use icu::datetime::DateTimeFormatter;
622            #[doc = concat!("use icu::datetime::fieldsets::", stringify!($type_time), ";")]
623            /// use icu::locale::locale;
624            /// use icu::datetime::input::{DateTime, Time};
625            /// use writeable::assert_writeable_eq;
626            ///
627            #[doc = concat!("let fmt = DateTimeFormatter::try_new(")]
628            ///     locale!("en").into(),
629            #[doc = concat!("    ", length_option_helper!($type_time, $sample_length), ",")]
630            /// )
631            /// .unwrap();
632            /// let dt = DateTime { date: Date::try_new_iso(2024, 5, 17).unwrap(), time: Time::try_new(15, 47, 50, 0).unwrap() };
633            ///
634            /// assert_writeable_eq!(
635            ///     fmt.format(&dt),
636            #[doc = concat!("    \"", $sample_time, "\"")]
637            /// );
638            /// ```
639            ///
640            /// In [`FixedCalendarDateTimeFormatter`](crate::neo::FixedCalendarDateTimeFormatter):
641            ///
642            /// ```
643            /// use icu::datetime::input::Date;
644            /// use icu::calendar::Gregorian;
645            /// use icu::datetime::FixedCalendarDateTimeFormatter;
646            #[doc = concat!("use icu::datetime::fieldsets::", stringify!($type_time), ";")]
647            /// use icu::locale::locale;
648            /// use icu::datetime::input::{DateTime, Time};
649            /// use writeable::assert_writeable_eq;
650            ///
651            #[doc = concat!("let fmt = FixedCalendarDateTimeFormatter::try_new(")]
652            ///     locale!("en").into(),
653            #[doc = concat!("    ", length_option_helper!($type_time, $sample_length), ",")]
654            /// )
655            /// .unwrap();
656            /// let dt = DateTime { date: Date::try_new_gregorian(2024, 5, 17).unwrap(), time: Time::try_new(15, 47, 50, 0).unwrap() };
657            ///
658            /// assert_writeable_eq!(
659            ///     fmt.format(&dt),
660            #[doc = concat!("    \"", $sample_time, "\"")]
661            /// );
662            /// ```
663            $(#[$attr])*
664            $type_time,
665            sample_length: $sample_length,
666            date_fields: Some(builder::DateFields::$type),
667            alignment: yes,
668            $(year_style: $year_yes,)?
669            time_precision: yes,
670        );
671        impl_marker_length_constructors!(
672            $type_time,
673            alignment: yes,
674            $(year_style: $year_yes,)?
675            time_precision: yes,
676        );
677        impl_zone_combo_helpers!($type_time, DateTimeZone, DateAndTimeFieldSet);
678        impl UnstableSealed for $type_time {}
679        impl DateTimeNamesMarker for $type_time {
680            type YearNames = datetime_marker_helper!(@names/year, $($years_yes)?);
681            type MonthNames = datetime_marker_helper!(@names/month, $($months_yes)?);
682            type WeekdayNames = datetime_marker_helper!(@names/weekday, $($weekdays_yes)?);
683            type DayPeriodNames = datetime_marker_helper!(@names/dayperiod, yes);
684            type ZoneEssentials = datetime_marker_helper!(@names/zone/essentials,);
685            type ZoneLocations = datetime_marker_helper!(@names/zone/locations,);
686            type ZoneLocationsRoot = datetime_marker_helper!(@names/zone/locations_root,);
687            type ZoneExemplars = datetime_marker_helper!(@names/zone/exemplar,);
688            type ZoneExemplarsRoot = datetime_marker_helper!(@names/zone/exemplar_root,);
689            type ZoneGenericLong = datetime_marker_helper!(@names/zone/generic_long,);
690            type ZoneGenericShort = datetime_marker_helper!(@names/zone/generic_short,);
691            type ZoneStandardLong = datetime_marker_helper!(@names/zone/standard_long,);
692            type ZoneSpecificLong = datetime_marker_helper!(@names/zone/specific_long,);
693            type ZoneSpecificShort = datetime_marker_helper!(@names/zone/specific_short,);
694            type MetazoneLookup = datetime_marker_helper!(@names/zone/metazone_periods,);
695        }
696        impl DateInputMarkers for $type_time {
697            type YearInput = datetime_marker_helper!(@input/year, $($year_yes)?);
698            type MonthInput = datetime_marker_helper!(@input/month, $($month_yes)?);
699            type DayOfMonthInput = datetime_marker_helper!(@input/day_of_month, $($day_of_month_yes)?);
700            type DayOfYearInput = datetime_marker_helper!(@input/day_of_year, $($day_of_year_yes)?);
701            type RataDieInput = datetime_marker_helper!(@input/rata_die, $($rata_die_yes)?);
702            type DayOfWeekInput = datetime_marker_helper!(@input/day_of_week, $($day_of_week_yes)?);
703        }
704        impl<C: CldrCalendar> TypedDateDataMarkers<C> for $type_time {
705            type DateSkeletonPatternsV1 = datetime_marker_helper!(@dates/typed, yes);
706            type YearNamesV1 = datetime_marker_helper!(@years/typed, $($years_yes)?);
707            type MonthNamesV1 = datetime_marker_helper!(@months/typed, $($months_yes)?);
708            type WeekdayNamesV1 = datetime_marker_helper!(@weekdays, $($weekdays_yes)?);
709        }
710        impl DateDataMarkers for $type_time {
711            type Skel = datetime_marker_helper!(@calmarkers, yes);
712            type Year = datetime_marker_helper!(@calmarkers, $($years_yes)?);
713            type Month = datetime_marker_helper!(@calmarkers, $($months_yes)?);
714            type WeekdayNamesV1 = datetime_marker_helper!(@weekdays, $($weekdays_yes)?);
715        }
716        impl TimeMarkers for $type_time {
717            // TODO(#6497): Consider making dayperiods optional
718            type DayPeriodNamesV1 = datetime_marker_helper!(@dayperiods, yes);
719            type TimeSkeletonPatternsV1 = datetime_marker_helper!(@times, yes);
720            type HourInput = datetime_marker_helper!(@input/hour, yes);
721            type MinuteInput = datetime_marker_helper!(@input/minute, yes);
722            type SecondInput = datetime_marker_helper!(@input/second, yes);
723            type NanosecondInput = datetime_marker_helper!(@input/Nanosecond, yes);
724        }
725        impl DateTimeMarkers for $type_time {
726            type D = Self;
727            type T = Self;
728            type Z = ();
729            type GluePatternV1 = datetime_marker_helper!(@glue, yes);
730        }
731        impl_composite!($type_time, DateTime, DateAndTimeFieldSet);
732        impl $type_time {
733            pub(crate) fn to_date_field_set(self) -> $type {
734                $type {
735                    length: self.length,
736                    $(alignment: yes_to!(self.alignment, $option_alignment_yes),)?
737                    $(year_style: yes_to!(self.year_style, $years_yes),)?
738                }
739            }
740        }
741    };
742}
743
744/// Implements a field set of calendar period fields.
745///
746/// Several arguments to this macro are required, and the rest are optional.
747/// The optional arguments should be written as `key = yes,` if that parameter
748/// should be included.
749///
750/// See [`impl_date_marker`].
751macro_rules! impl_calendar_period_marker {
752    (
753        $(#[$attr:meta])*
754        $type:ident,
755        description = $description:literal,
756        sample_length = $sample_length:ident,
757        sample = $sample:literal,
758        $(years = $years_yes:ident,)?
759        $(months = $months_yes:ident,)?
760        $(dates = $dates_yes:ident,)?
761        $(input_year = $year_yes:ident,)?
762        $(input_month = $month_yes:ident,)?
763        $(input_any_calendar_kind = $any_calendar_kind_yes:ident,)?
764        $(option_alignment = $option_alignment_yes:ident,)?
765    ) => {
766        impl_date_or_calendar_period_marker!(
767            $(#[$attr])*
768            $type,
769            description = $description,
770            sample_length = $sample_length,
771            sample = $sample,
772            $(years = $years_yes,)?
773            $(months = $months_yes,)?
774            $(dates = $dates_yes,)?
775            $(input_year = $year_yes,)?
776            $(input_month = $month_yes,)?
777            $(input_any_calendar_kind = $any_calendar_kind_yes,)?
778            $(option_alignment = $option_alignment_yes,)?
779        );
780        impl_composite!($type, CalendarPeriod, CalendarPeriodFieldSet);
781    };
782}
783
784/// Implements a field set of time fields.
785///
786/// Several arguments to this macro are required, and the rest are optional.
787/// The optional arguments should be written as `key = yes,` if that parameter
788/// should be included.
789///
790/// Documentation for each option is shown inline below.
791macro_rules! impl_time_marker {
792    (
793        $(#[$attr:meta])*
794        // The name of the type being created.
795        $type:ident,
796        // A plain language description of the field set for documentation.
797        description = $description:literal,
798        // Length of the sample string below.
799        sample_length = $sample_length:ident,
800        // A sample string. A docs test will be generated!
801        sample = $sample:literal,
802        // Whether day periods can occur.
803        $(dayperiods = $dayperiods_yes:ident,)?
804        // Whether the input should include hours.
805        $(input_hour = $hour_yes:ident,)?
806        // Whether the input should contain minutes.
807        $(input_minute = $minute_yes:ident,)?
808        // Whether the input should contain seconds.
809        $(input_second = $second_yes:ident,)?
810        // Whether the input should contain fractional seconds.
811        $(input_subsecond = $Nanosecond_yes:ident,)?
812    ) => {
813        impl_marker_with_options!(
814            #[doc = concat!("**“", $sample, "**” ⇒ ", $description)]
815            ///
816            /// # Examples
817            ///
818            /// ```
819            /// use icu::datetime::input::Time;
820            /// use icu::datetime::NoCalendarFormatter;
821            #[doc = concat!("use icu::datetime::fieldsets::", stringify!($type), ";")]
822            /// use icu::locale::locale;
823            /// use writeable::assert_writeable_eq;
824            ///
825            #[doc = concat!("let fmt = NoCalendarFormatter::try_new(")]
826            ///     locale!("en").into(),
827            #[doc = concat!("    ", length_option_helper!($type, $sample_length), ",")]
828            /// )
829            /// .unwrap();
830            /// let time = Time::try_new(15, 47, 50, 0).unwrap();
831            ///
832            /// assert_writeable_eq!(
833            ///     fmt.format(&time),
834            #[doc = concat!("    \"", $sample, "\"")]
835            /// );
836            /// ```
837            $(#[$attr])*
838            $type,
839            sample_length: $sample_length,
840            alignment: yes,
841            time_precision: yes,
842        );
843        impl_marker_length_constructors!(
844            $type,
845            alignment: yes,
846            time_precision: yes,
847        );
848        impl_time_precision_constructors!(
849            $type,
850        );
851        impl_zone_combo_helpers!($type, TimeZone, TimeFieldSet);
852        impl UnstableSealed for $type {}
853        impl DateTimeNamesMarker for $type {
854            type YearNames = datetime_marker_helper!(@names/year,);
855            type MonthNames = datetime_marker_helper!(@names/month,);
856            type WeekdayNames = datetime_marker_helper!(@names/weekday,);
857            type DayPeriodNames = datetime_marker_helper!(@names/dayperiod, $($dayperiods_yes)?);
858            type ZoneEssentials = datetime_marker_helper!(@names/zone/essentials,);
859            type ZoneLocations = datetime_marker_helper!(@names/zone/locations,);
860            type ZoneLocationsRoot = datetime_marker_helper!(@names/zone/locations_root,);
861            type ZoneExemplars = datetime_marker_helper!(@names/zone/exemplar,);
862            type ZoneExemplarsRoot = datetime_marker_helper!(@names/zone/exemplar_root,);
863            type ZoneGenericLong = datetime_marker_helper!(@names/zone/generic_long,);
864            type ZoneGenericShort = datetime_marker_helper!(@names/zone/generic_short,);
865            type ZoneStandardLong = datetime_marker_helper!(@names/zone/standard_long,);
866            type ZoneSpecificLong = datetime_marker_helper!(@names/zone/specific_long,);
867            type ZoneSpecificShort = datetime_marker_helper!(@names/zone/specific_short,);
868            type MetazoneLookup = datetime_marker_helper!(@names/zone/metazone_periods,);
869        }
870        impl TimeMarkers for $type {
871            type DayPeriodNamesV1 = datetime_marker_helper!(@dayperiods, $($dayperiods_yes)?);
872            type TimeSkeletonPatternsV1 = datetime_marker_helper!(@times, yes);
873            type HourInput = datetime_marker_helper!(@input/hour, $($hour_yes)?);
874            type MinuteInput = datetime_marker_helper!(@input/minute, $($minute_yes)?);
875            type SecondInput = datetime_marker_helper!(@input/second, $($second_yes)?);
876            type NanosecondInput = datetime_marker_helper!(@input/Nanosecond, $($Nanosecond_yes)?);
877        }
878        impl DateTimeMarkers for $type {
879            type D = ();
880            type T = Self;
881            type Z = ();
882            type GluePatternV1 = datetime_marker_helper!(@glue,);
883        }
884        impl_composite!($type, Time, TimeFieldSet);
885    };
886}
887
888/// Implements a field set of time zone fields.
889///
890/// Several arguments to this macro are required, and the rest are optional.
891/// The optional arguments should be written as `key = yes,` if that parameter
892/// should be included.
893///
894/// Documentation for each option is shown inline below.
895macro_rules! impl_zone_marker {
896    (
897        $(#[$attr:meta])*
898        // The name of the type being created.
899        $type:ident,
900        // A plain language description of the field set for documentation.
901        description = $description:literal,
902        // Length of the skeleton if this is the only field.
903        length_override = $length_override:ident,
904        // A sample string. A docs test will be generated!
905        sample = $sample:literal,
906        // The field symbol and field length.
907        field = $field:expr,
908        // The type in ZoneFieldSet for this field set
909        // Whether zone-essentials should be loaded.
910        $(zone_essentials = $zone_essentials_yes:ident,)?
911        // Whether locations names are needed.
912        $(zone_locations = $zone_locations_yes:ident,)?
913        // Whether exemplar city names are needed.
914        $(zone_exemplars = $zone_exemplars_yes:ident,)?
915        // Whether generic long names are needed.
916        $(zone_generic_long = $zone_generic_long_yes:ident,)?
917        // Whether generic short names are needed.
918        $(zone_generic_short = $zone_generic_short_yes:ident,)?
919        // Whether standard long names are needed.
920        $(zone_standard_long = $zone_standard_long_yes:ident,)?
921        // Whether specific long names are needed.
922        $(zone_specific_long = $zone_specific_long_yes:ident,)?
923        // Whether specific short names are needed.
924        $(zone_specific_short = $zone_specific_short_yes:ident,)?
925        // Whether metazone periods are needed
926        $(metazone_periods = $metazone_periods_yes:ident,)?
927        // Whether to require the TimeZone
928        $(input_tzid = $tzid_input_yes:ident,)?
929        // Whether to require the Timestamp
930        $(input_timestamp = $timestamp_input_yes:ident,)?
931    ) => {
932        #[doc = concat!("**“", $sample, "**” ⇒ ", $description)]
933        ///
934        /// # Examples
935        ///
936        /// ```
937        /// use icu::datetime::input::{Date, DateTime, Time, TimeZone, TimeZoneInfo, UtcOffset};
938        /// use icu::datetime::NoCalendarFormatter;
939        #[doc = concat!("use icu::datetime::fieldsets::zone::", stringify!($type), ";")]
940        /// use icu::locale::{locale, subtags::subtag};
941        /// use writeable::assert_writeable_eq;
942        ///
943        /// let fmt = NoCalendarFormatter::try_new(
944        ///     locale!("en").into(),
945        #[doc = concat!("    ", stringify!($type))]
946        /// )
947        /// .unwrap();
948        ///
949        /// // Time zone info for America/Chicago in the summer
950        /// let zone = TimeZone(subtag!("uschi"))
951        ///     .with_offset("-05".parse().ok())
952        ///     .at_date_time_iso(DateTime{ date: Date::try_new_iso(2022, 8, 29).unwrap(), time: Time::start_of_day() });
953        ///
954        /// assert_writeable_eq!(
955        ///     fmt.format(&zone),
956        #[doc = concat!("    \"", $sample, "\"")]
957        /// );
958        /// ```
959        $(#[$attr])*
960        #[derive(Debug, Copy, Clone, PartialEq, Eq)]
961        #[allow(clippy::exhaustive_structs)] // singleton marker
962        pub struct $type;
963        impl UnstableSealed for $type {}
964        impl DateTimeNamesMarker for $type {
965            type YearNames = datetime_marker_helper!(@names/year,);
966            type MonthNames = datetime_marker_helper!(@names/month,);
967            type WeekdayNames = datetime_marker_helper!(@names/weekday,);
968            type DayPeriodNames = datetime_marker_helper!(@names/dayperiod,);
969            type ZoneEssentials = datetime_marker_helper!(@names/zone/essentials, $($zone_essentials_yes)?);
970            type ZoneLocations = datetime_marker_helper!(@names/zone/locations, $($zone_locations_yes)?);
971            type ZoneLocationsRoot = datetime_marker_helper!(@names/zone/locations_root, $($zone_locations_yes)?);
972            type ZoneExemplars = datetime_marker_helper!(@names/zone/exemplars, $($zone_exemplars_yes)?);
973            type ZoneExemplarsRoot = datetime_marker_helper!(@names/zone/exemplars_root, $($zone_exemplars_yes)?);
974            type ZoneGenericLong = datetime_marker_helper!(@names/zone/generic_long, $($zone_generic_long_yes)?);
975            type ZoneGenericShort = datetime_marker_helper!(@names/zone/generic_short, $($zone_generic_short_yes)?);
976            type ZoneStandardLong = datetime_marker_helper!(@names/zone/standard_long, $($zone_standard_long_yes)?);
977            type ZoneSpecificLong = datetime_marker_helper!(@names/zone/specific_long, $($zone_specific_long_yes)?);
978            type ZoneSpecificShort = datetime_marker_helper!(@names/zone/specific_short, $($zone_specific_short_yes)?);
979            type MetazoneLookup = datetime_marker_helper!(@names/zone/metazone_periods, $($metazone_periods_yes)?);
980        }
981        impl ZoneMarkers for $type {
982            type TimeZoneIdInput = datetime_marker_helper!(@input/timezone/id, $($tzid_input_yes)?);
983            type TimeZoneOffsetInput = datetime_marker_helper!(@input/timezone/offset, yes);
984            type TimeZoneNameTimestampInput = datetime_marker_helper!(@input/timezone/timestamp, $($timestamp_input_yes)?);
985            type EssentialsV1 = datetime_marker_helper!(@data/zone/essentials, $($zone_essentials_yes)?);
986            type LocationsV1 = datetime_marker_helper!(@data/zone/locations, $($zone_locations_yes)?);
987            type LocationsRootV1 = datetime_marker_helper!(@data/zone/locations_root, $($zone_locations_yes)?);
988            type ExemplarCitiesV1 = datetime_marker_helper!(@data/zone/exemplars, $($zone_exemplars_yes)?);
989            type ExemplarCitiesRootV1 = datetime_marker_helper!(@data/zone/exemplars_root, $($zone_exemplars_yes)?);
990            type GenericLongV1 = datetime_marker_helper!(@data/zone/generic_long, $($zone_generic_long_yes)?);
991            type GenericShortV1 = datetime_marker_helper!(@data/zone/generic_short, $($zone_generic_short_yes)?);
992            type StandardLongV1 = datetime_marker_helper!(@data/zone/standard_long, $($zone_standard_long_yes)?);
993            type SpecificLongV1 = datetime_marker_helper!(@data/zone/specific_long, $($zone_specific_long_yes)?);
994            type SpecificShortV1 = datetime_marker_helper!(@data/zone/specific_short, $($zone_specific_short_yes)?);
995            type MetazonePeriodV1 = datetime_marker_helper!(@data/zone/metazone_periods, $($metazone_periods_yes)?);
996        }
997        impl DateTimeMarkers for $type {
998            type D = ();
999            type T = ();
1000            type Z = Self;
1001            type GluePatternV1 = datetime_marker_helper!(@glue,);
1002        }
1003        impl_composite!($type, Zone, ZoneFieldSet);
1004        impl $type {
1005            pub(crate) fn to_field(self) -> (fields::TimeZone, fields::FieldLength) {
1006                $field
1007            }
1008        }
1009    };
1010}
1011
1012impl_date_marker!(
1013    /// This format may use ordinal formatting, such as "the 17th",
1014    /// in the future. See CLDR-18040.
1015    D,
1016    DT,
1017    description = "day of month (standalone)",
1018    sample_length = short,
1019    sample = "17",
1020    sample_time = "17, 3:47:50 PM",
1021    input_day_of_month = yes,
1022    input_any_calendar_kind = yes,
1023    option_alignment = yes,
1024);
1025
1026impl_date_marker!(
1027    E,
1028    ET,
1029    description = "weekday (standalone)",
1030    sample_length = long,
1031    sample = "Friday",
1032    sample_time = "Friday 3:47:50 PM",
1033    weekdays = yes,
1034    input_day_of_week = yes,
1035);
1036
1037impl_date_marker!(
1038    /// This format may use ordinal formatting, such as "Friday the 17th",
1039    /// in the future. See CLDR-18040.
1040    DE,
1041    DET,
1042    description = "day of month and weekday",
1043    sample_length = long,
1044    sample = "17 Friday",
1045    sample_time = "17 Friday at 3:47:50 PM",
1046    weekdays = yes,
1047    input_day_of_month = yes,
1048    input_day_of_week = yes,
1049    option_alignment = yes,
1050);
1051
1052impl_date_marker!(
1053    MD,
1054    MDT,
1055    description = "month and day",
1056    sample_length = medium,
1057    sample = "May 17",
1058    sample_time = "May 17, 3:47:50 PM",
1059    months = yes,
1060    input_month = yes,
1061    input_day_of_month = yes,
1062    input_any_calendar_kind = yes,
1063    option_alignment = yes,
1064);
1065
1066impl_date_marker!(
1067    /// See CLDR-18040 for progress on improving this format.
1068    MDE,
1069    MDET,
1070    description = "month, day, and weekday",
1071    sample_length = medium,
1072    sample = "Fri, May 17",
1073    sample_time = "Fri, May 17, 3:47:50 PM",
1074    months = yes,
1075    weekdays = yes,
1076    input_month = yes,
1077    input_day_of_month = yes,
1078    input_day_of_week = yes,
1079    input_any_calendar_kind = yes,
1080    option_alignment = yes,
1081);
1082
1083impl_date_marker!(
1084    YMD,
1085    YMDT,
1086    description = "year, month, and day",
1087    sample_length = short,
1088    sample = "5/17/24",
1089    sample_time = "5/17/24, 3:47:50 PM",
1090    years = yes,
1091    months = yes,
1092    input_year = yes,
1093    input_month = yes,
1094    input_day_of_month = yes,
1095    input_any_calendar_kind = yes,
1096    option_alignment = yes,
1097);
1098
1099impl_date_marker!(
1100    YMDE,
1101    YMDET,
1102    description = "year, month, day, and weekday",
1103    sample_length = short,
1104    sample = "Fri, 5/17/24",
1105    sample_time = "Fri, 5/17/24, 3:47:50 PM",
1106    years = yes,
1107    months = yes,
1108    weekdays = yes,
1109    input_year = yes,
1110    input_month = yes,
1111    input_day_of_month = yes,
1112    input_day_of_week = yes,
1113    input_any_calendar_kind = yes,
1114    option_alignment = yes,
1115);
1116
1117impl_calendar_period_marker!(
1118    Y,
1119    description = "year (standalone)",
1120    sample_length = medium,
1121    sample = "2024",
1122    years = yes,
1123    input_year = yes,
1124    input_any_calendar_kind = yes,
1125    option_alignment = yes,
1126);
1127
1128impl_calendar_period_marker!(
1129    M,
1130    description = "month (standalone)",
1131    sample_length = long,
1132    sample = "May",
1133    months = yes,
1134    input_month = yes,
1135    input_any_calendar_kind = yes,
1136    option_alignment = yes,
1137);
1138
1139impl_calendar_period_marker!(
1140    YM,
1141    description = "year and month",
1142    sample_length = medium,
1143    sample = "May 2024",
1144    years = yes,
1145    months = yes,
1146    input_year = yes,
1147    input_month = yes,
1148    input_any_calendar_kind = yes,
1149    option_alignment = yes,
1150);
1151
1152impl_time_marker!(
1153    /// Hours can be switched between 12-hour and 24-hour time via the `u-hc` locale keyword
1154    /// or [`DateTimeFormatterPreferences`].
1155    ///
1156    /// ```
1157    /// use icu::datetime::input::Time;
1158    /// use icu::datetime::fieldsets::T;
1159    /// use icu::datetime::NoCalendarFormatter;
1160    /// use icu::locale::locale;
1161    /// use writeable::assert_writeable_eq;
1162    ///
1163    /// // By default, en-US uses 12-hour time and fr-FR uses 24-hour time,
1164    /// // but we can set overrides.
1165    ///
1166    /// let formatter = NoCalendarFormatter::try_new(
1167    ///     locale!("en-US-u-hc-h12").into(),
1168    ///     T::hm(),
1169    /// )
1170    /// .unwrap();
1171    /// assert_writeable_eq!(
1172    ///     formatter.format(&Time::try_new(16, 12, 20, 0).unwrap()),
1173    ///     "4:12 PM"
1174    /// );
1175    ///
1176    /// let formatter = NoCalendarFormatter::try_new(
1177    ///     locale!("en-US-u-hc-h23").into(),
1178    ///     T::hm(),
1179    /// )
1180    /// .unwrap();
1181    /// assert_writeable_eq!(
1182    ///     formatter.format(&Time::try_new(16, 12, 20, 0).unwrap()),
1183    ///     "16:12"
1184    /// );
1185    ///
1186    /// let formatter = NoCalendarFormatter::try_new(
1187    ///     locale!("fr-FR-u-hc-h12").into(),
1188    ///     T::hm(),
1189    /// )
1190    /// .unwrap();
1191    /// assert_writeable_eq!(
1192    ///     formatter.format(&Time::try_new(16, 12, 20, 0).unwrap()),
1193    ///     "4:12 PM"
1194    /// );
1195    ///
1196    /// let formatter = NoCalendarFormatter::try_new(
1197    ///     locale!("fr-FR-u-hc-h23").into(),
1198    ///     T::hm(),
1199    /// )
1200    /// .unwrap();
1201    /// assert_writeable_eq!(
1202    ///     formatter.format(&Time::try_new(16, 12, 20, 0).unwrap()),
1203    ///     "16:12"
1204    /// );
1205    /// ```
1206    ///
1207    /// Hour cycles `h11` and `h24` are supported, too:
1208    ///
1209    /// ```
1210    /// use icu::datetime::input::Time;
1211    /// use icu::datetime::fieldsets::T;
1212    /// use icu::datetime::NoCalendarFormatter;
1213    /// use icu::locale::locale;
1214    /// use writeable::assert_writeable_eq;
1215    ///
1216    /// let formatter = NoCalendarFormatter::try_new(
1217    ///     locale!("und-u-hc-h11").into(),
1218    ///     T::hm(),
1219    /// )
1220    /// .unwrap();
1221    ///
1222    /// assert_writeable_eq!(
1223    ///     formatter.format(&Time::try_new(0, 0, 0, 0).unwrap()),
1224    ///     "0:00 AM"
1225    /// );
1226    ///
1227    /// let formatter = NoCalendarFormatter::try_new(
1228    ///     locale!("und-u-hc-h23").into(),
1229    ///     T::hm(),
1230    /// )
1231    /// .unwrap();
1232    ///
1233    /// assert_writeable_eq!(
1234    ///     formatter.format(&Time::try_new(0, 0, 0, 0).unwrap()),
1235    ///     "00:00"
1236    /// );
1237    /// ```
1238    ///
1239    /// Conveniently construct a time formatter with subseconds:
1240    ///
1241    /// ```
1242    /// use icu::datetime::input::Time;
1243    /// use icu::datetime::fieldsets::T;
1244    /// use icu::datetime::options::SubsecondDigits;
1245    /// use icu::datetime::NoCalendarFormatter;
1246    /// use icu::locale::locale;
1247    /// use writeable::assert_writeable_eq;
1248    ///
1249    /// let formatter = NoCalendarFormatter::try_new(
1250    ///     locale!("en").into(),
1251    ///     T::hmss(SubsecondDigits::S4),
1252    /// )
1253    /// .unwrap();
1254    ///
1255    /// assert_writeable_eq!(
1256    ///     formatter.format(&Time::try_new(18, 24, 36, 987654321).unwrap()),
1257    ///     "6:24:36.9876 PM"
1258    /// );
1259    /// ```
1260    ///
1261    /// [`DateTimeFormatterPreferences`]: crate::DateTimeFormatterPreferences
1262    T,
1263    description = "time (locale-dependent hour cycle)",
1264    sample_length = medium,
1265    sample = "3:47:50 PM",
1266    dayperiods = yes,
1267    input_hour = yes,
1268    input_minute = yes,
1269    input_second = yes,
1270    input_subsecond = yes,
1271);
1272
1273/// Time zone field sets
1274pub mod zone {
1275    use super::*;
1276    impl_zone_marker!(
1277        /// If a non-location name is not defined, falls back to the specific location format:
1278        ///
1279        /// ```
1280        /// use icu::datetime::input::{Date, DateTime, Time, TimeZone, TimeZoneInfo, UtcOffset};
1281        /// use icu::datetime::NoCalendarFormatter;
1282        /// use icu::datetime::fieldsets::zone::SpecificLong;
1283        /// use icu::locale::{locale, subtags::subtag};
1284        /// use writeable::assert_writeable_eq;
1285        ///
1286        /// // Time zone info for Europe/Istanbul in the winter
1287        /// let zone = TimeZone(subtag!("trist"))
1288        ///     .with_offset("+03".parse().ok())
1289        ///     .at_date_time_iso(DateTime{ date: Date::try_new_iso(2022, 1, 29).unwrap(), time: Time::start_of_day() });
1290        ///
1291        /// let fmt = NoCalendarFormatter::try_new(
1292        ///     locale!("en").into(),
1293        ///     SpecificLong,
1294        /// )
1295        /// .unwrap();
1296        ///
1297        /// assert_writeable_eq!(
1298        ///     fmt.format(&zone),
1299        ///     "Türkiye Standard Time"
1300        /// );
1301        /// ```
1302        ///
1303        /// If the offset doesn't match one of the valid offsets for the zone, falls back to the localized offset format:
1304        /// ```
1305        /// use icu::datetime::input::{Date, DateTime, Time, TimeZone, TimeZoneInfo, UtcOffset};
1306        /// use icu::datetime::NoCalendarFormatter;
1307        /// use icu::datetime::fieldsets::zone::SpecificLong;
1308        /// use icu::locale::{locale, subtags::subtag};
1309        /// use writeable::assert_writeable_eq;
1310        ///
1311        /// // Time zone info for America/Chicago with a wrong offset
1312        /// let wrong_offset = TimeZone(subtag!("uschi"))
1313        ///     .with_offset("-04".parse().ok())
1314        ///     .at_date_time_iso(DateTime{ date: Date::try_new_iso(2022, 8, 29).unwrap(), time: Time::start_of_day() });
1315        ///
1316        /// let fmt = NoCalendarFormatter::try_new(
1317        ///     locale!("en").into(),
1318        ///     SpecificLong,
1319        /// )
1320        /// .unwrap();
1321        ///
1322        /// assert_writeable_eq!(
1323        ///     fmt.format(&wrong_offset),
1324        ///     "GMT-04:00"
1325        /// );
1326        ///
1327        /// // This of course always happens for the unknown time zone
1328        /// let unk = TimeZone::UNKNOWN.with_offset(wrong_offset.offset()).with_zone_name_timestamp(wrong_offset.zone_name_timestamp());
1329        ///
1330        /// assert_writeable_eq!(
1331        ///     fmt.format(&unk),
1332        ///     "GMT-04:00"
1333        /// );
1334        /// ```
1335        ///
1336        /// Since non-location names might change over time,
1337        /// this time zone style requires a reference time.
1338        ///
1339        /// ```compile_fail,E0271
1340        /// use icu::datetime::NoCalendarFormatter;
1341        /// use icu::datetime::fieldsets::zone::SpecificLong;
1342        /// use icu::locale::{locale, subtags::subtag};
1343        /// use icu::datetime::input::{TimeZone, UtcOffset};
1344        ///
1345        /// let time_zone_basic = TimeZone(subtag!("uschi")).without_offset();
1346        ///
1347        /// let formatter = NoCalendarFormatter::try_new(
1348        ///     locale!("en-US").into(),
1349        ///     SpecificLong,
1350        /// )
1351        /// .unwrap();
1352        ///
1353        /// // error[E0271]: type mismatch resolving `<Base as TimeZoneModel>::ZoneNameTimestamp == ZoneNameTimestamp`
1354        /// formatter.format(&time_zone_basic);
1355        /// ```
1356        SpecificLong,
1357        description = "time zone in specific non-location format, long length",
1358        length_override = Long,
1359        sample = "Central Daylight Time",
1360        field = (fields::TimeZone::SpecificNonLocation, fields::FieldLength::Four),
1361        zone_essentials = yes,
1362        zone_locations = yes,
1363        zone_standard_long = yes,
1364        zone_specific_long = yes,
1365        metazone_periods = yes,
1366        input_tzid = yes,
1367        input_timestamp = yes,
1368    );
1369
1370    impl_zone_marker!(
1371        /// If a non-location name is not defined, falls back to the localized offset format.
1372        /// This is the case for most zones, as each locale only contains the short names that are
1373        /// used locally and generally understood:
1374        ///
1375        /// ```
1376        /// use icu::datetime::input::{Date, DateTime, Time, TimeZone, TimeZoneInfo, UtcOffset};
1377        /// use icu::datetime::NoCalendarFormatter;
1378        /// use icu::datetime::fieldsets::zone::SpecificShort;
1379        /// use icu::locale::{locale, subtags::subtag};
1380        /// use writeable::assert_writeable_eq;
1381        ///
1382        /// // Time zone info for Asia/Tokyo
1383        /// let zone = TimeZone(subtag!("jptyo"))
1384        ///     .with_offset("+09".parse().ok())
1385        ///     .at_date_time_iso(DateTime{ date: Date::try_new_iso(2022, 1, 29).unwrap(), time: Time::start_of_day() });
1386        ///
1387        /// let fmt = NoCalendarFormatter::try_new(
1388        ///     locale!("en").into(),
1389        ///     SpecificShort,
1390        /// )
1391        /// .unwrap();
1392        ///
1393        /// // "JST" is not generally known in American English
1394        /// assert_writeable_eq!(
1395        ///     fmt.format(&zone),
1396        ///     "GMT+9"
1397        /// );
1398        /// ```
1399        ///
1400        /// If the offset doesn't match one of the valid offsets for the zone, falls back to the localized offset format:
1401        /// ```
1402        /// use icu::datetime::input::{Date, DateTime, Time, TimeZone, TimeZoneInfo, UtcOffset};
1403        /// use icu::datetime::NoCalendarFormatter;
1404        /// use icu::datetime::fieldsets::zone::SpecificShort;
1405        /// use icu::locale::{locale, subtags::subtag};
1406        /// use writeable::assert_writeable_eq;
1407        ///
1408        /// // Time zone info for America/Chicago with a wrong offset
1409        /// let wrong_offset = TimeZone(subtag!("uschi"))
1410        ///     .with_offset("-04".parse().ok())
1411        ///     .at_date_time_iso(DateTime{ date: Date::try_new_iso(2022, 8, 29).unwrap(), time: Time::start_of_day() });
1412        ///
1413        /// let fmt = NoCalendarFormatter::try_new(
1414        ///     locale!("en").into(),
1415        ///     SpecificShort,
1416        /// )
1417        /// .unwrap();
1418        ///
1419        /// assert_writeable_eq!(
1420        ///     fmt.format(&wrong_offset),
1421        ///     "GMT-4"
1422        /// );
1423        ///
1424        /// // This of course always happens for the unknown time zone
1425        /// let unk = TimeZone::UNKNOWN.with_offset(wrong_offset.offset()).with_zone_name_timestamp(wrong_offset.zone_name_timestamp());
1426        ///
1427        /// assert_writeable_eq!(
1428        ///     fmt.format(&unk),
1429        ///     "GMT-4"
1430        /// );
1431        /// ```
1432        ///
1433        /// Since non-location names might change over time,
1434        /// this time zone style requires a reference time.
1435        ///
1436        /// ```compile_fail,E0271
1437        /// use icu::datetime::NoCalendarFormatter;
1438        /// use icu::datetime::fieldsets::zone::SpecificShort;
1439        /// use icu::datetime::input::TimeZone;
1440        /// use icu::locale::{locale, subtags::subtag};
1441        ///
1442        /// let time_zone_basic = TimeZone(subtag!("uschi")).without_offset();
1443        ///
1444        /// let formatter = NoCalendarFormatter::try_new(
1445        ///     locale!("en-US").into(),
1446        ///     SpecificShort,
1447        /// )
1448        /// .unwrap();
1449        ///
1450        /// // error[E0271]: type mismatch resolving `<Base as TimeZoneModel>::ZoneNameTimestamp == ZoneNameTimestamp`
1451        /// formatter.format(&time_zone_basic);
1452        /// ```
1453        SpecificShort,
1454        description = "time zone in specific non-location format, short length",
1455        length_override = Short,
1456        sample = "CDT",
1457        field = (fields::TimeZone::SpecificNonLocation, fields::FieldLength::One),
1458        zone_essentials = yes,
1459        zone_specific_short = yes,
1460        metazone_periods = yes,
1461        input_tzid = yes,
1462        input_timestamp = yes,
1463    );
1464
1465    impl_zone_marker!(
1466        /// All shapes of time zones can be formatted with this style.
1467        ///
1468        /// ```
1469        /// use icu::datetime::input::Date;
1470        /// use icu::datetime::NoCalendarFormatter;
1471        /// use icu::datetime::fieldsets::zone::LocalizedOffsetLong;
1472        /// use icu::datetime::input::{DateTime, Time, TimeZone, UtcOffset};
1473        /// use icu::locale::{locale, subtags::subtag};
1474        /// use writeable::assert_writeable_eq;
1475        ///
1476        /// let utc_offset = "-06".parse().unwrap();
1477        /// let time_zone_basic = TimeZone(subtag!("uschi")).with_offset(Some(utc_offset));
1478        ///
1479        /// let date = Date::try_new_iso(2024, 10, 18).unwrap();
1480        /// let time = Time::start_of_day();
1481        /// let time_zone_at_time = time_zone_basic.at_date_time_iso(DateTime{ date, time });
1482        ///
1483        /// let formatter = NoCalendarFormatter::try_new(
1484        ///     locale!("en-US").into(),
1485        ///     LocalizedOffsetLong,
1486        /// )
1487        /// .unwrap();
1488        ///
1489        /// assert_writeable_eq!(
1490        ///     formatter.format(&utc_offset),
1491        ///     "GMT-06:00"
1492        /// );
1493        ///
1494        /// assert_writeable_eq!(
1495        ///     formatter.format(&time_zone_basic),
1496        ///     "GMT-06:00"
1497        /// );
1498        ///
1499        /// assert_writeable_eq!(
1500        ///     formatter.format(&time_zone_at_time),
1501        ///     "GMT-06:00"
1502        /// );
1503        /// ```
1504        LocalizedOffsetLong,
1505        description = "UTC offset, long length",
1506        length_override = Long,
1507        sample = "GMT-05:00",
1508        field = (fields::TimeZone::LocalizedOffset, fields::FieldLength::Four),
1509        zone_essentials = yes,
1510    );
1511
1512    impl_zone_marker!(
1513        /// All shapes of time zones can be formatted with this style.
1514        ///
1515        /// ```
1516        /// use icu::datetime::input::Date;
1517        /// use icu::datetime::NoCalendarFormatter;
1518        /// use icu::datetime::fieldsets::zone::LocalizedOffsetShort;
1519        /// use icu::datetime::input::{DateTime, Time, TimeZone, UtcOffset};
1520        /// use icu::locale::{locale, subtags::subtag};
1521        /// use writeable::assert_writeable_eq;
1522        ///
1523        /// let utc_offset = "-06".parse().unwrap();
1524        /// let time_zone_basic = TimeZone(subtag!("uschi")).with_offset(Some(utc_offset));
1525        ///
1526        /// let date = Date::try_new_iso(2024, 10, 18).unwrap();
1527        /// let time = Time::start_of_day();
1528        /// let time_zone_at_time = time_zone_basic.at_date_time_iso(DateTime{ date, time });
1529        ///
1530        /// let formatter = NoCalendarFormatter::try_new(
1531        ///     locale!("en-US").into(),
1532        ///     LocalizedOffsetShort,
1533        /// )
1534        /// .unwrap();
1535        ///
1536        /// assert_writeable_eq!(
1537        ///     formatter.format(&utc_offset),
1538        ///     "GMT-6"
1539        /// );
1540        ///
1541        /// assert_writeable_eq!(
1542        ///     formatter.format(&time_zone_basic),
1543        ///     "GMT-6"
1544        /// );
1545        ///
1546        /// assert_writeable_eq!(
1547        ///     formatter.format(&time_zone_at_time),
1548        ///     "GMT-6"
1549        /// );
1550        /// ```
1551        LocalizedOffsetShort,
1552        description = "UTC offset, short length",
1553        length_override = Short,
1554        sample = "GMT-5",
1555        field = (fields::TimeZone::LocalizedOffset, fields::FieldLength::One),
1556        zone_essentials = yes,
1557    );
1558
1559    impl_zone_marker!(
1560        /// If a non-location name is not defined, falls back to the specific location format:
1561        ///
1562        /// ```
1563        /// use icu::datetime::input::{Date, DateTime, Time, TimeZone, TimeZoneInfo, UtcOffset};
1564        /// use icu::datetime::NoCalendarFormatter;
1565        /// use icu::datetime::fieldsets::zone::GenericLong;
1566        /// use icu::locale::{locale, subtags::subtag};
1567        /// use writeable::assert_writeable_eq;
1568        ///
1569        /// // Time zone info for Europe/Istanbul in the winter
1570        /// let zone = TimeZone(subtag!("trist"))
1571        ///     .with_offset("+03".parse().ok())
1572        ///     .at_date_time_iso(DateTime{ date: Date::try_new_iso(2022, 1, 29).unwrap(), time: Time::start_of_day() });
1573        ///
1574        /// let fmt = NoCalendarFormatter::try_new(
1575        ///     locale!("en").into(),
1576        ///     GenericLong,
1577        /// )
1578        /// .unwrap();
1579        ///
1580        /// assert_writeable_eq!(
1581        ///     fmt.format(&zone),
1582        ///     "Türkiye Time"
1583        /// );
1584        /// ```
1585        ///
1586        /// If the offset doesn't match one of the valid offsets for the zone, falls back to the localized offset format:
1587        /// ```
1588        /// use icu::datetime::input::{Date, DateTime, Time, TimeZone, TimeZoneInfo, UtcOffset};
1589        /// use icu::datetime::NoCalendarFormatter;
1590        /// use icu::datetime::fieldsets::zone::GenericLong;
1591        /// use icu::locale::{locale, subtags::subtag};
1592        /// use writeable::assert_writeable_eq;
1593        ///
1594        /// // Time zone info for America/Chicago with a wrong offset
1595        /// let wrong_offset = TimeZone(subtag!("uschi"))
1596        ///     .with_offset("-04".parse().ok())
1597        ///     .at_date_time_iso(DateTime{ date: Date::try_new_iso(2022, 8, 29).unwrap(), time: Time::start_of_day() });
1598        ///
1599        /// let fmt = NoCalendarFormatter::try_new(
1600        ///     locale!("en").into(),
1601        ///     GenericLong,
1602        /// )
1603        /// .unwrap();
1604        ///
1605        /// assert_writeable_eq!(
1606        ///     fmt.format(&wrong_offset),
1607        ///     "GMT-04:00"
1608        /// );
1609        ///
1610        /// // This of course always happens for the unknown time zone
1611        /// let unk = TimeZone::UNKNOWN.with_offset(wrong_offset.offset()).with_zone_name_timestamp(wrong_offset.zone_name_timestamp());
1612        ///
1613        /// assert_writeable_eq!(
1614        ///     fmt.format(&unk),
1615        ///     "GMT-04:00"
1616        /// );
1617        /// ```
1618        ///
1619        /// Since non-location names might change over time,
1620        /// this time zone style requires a reference time.
1621        ///
1622        /// ```compile_fail,E0271
1623        /// use icu::datetime::NoCalendarFormatter;
1624        /// use icu::datetime::fieldsets::zone::GenericLong;
1625        /// use icu::datetime::input::TimeZone;
1626        /// use icu::locale::{locale, subtags::subtag};
1627        ///
1628        /// let time_zone_basic = TimeZone(subtag!("uschi")).without_offset();
1629        ///
1630        /// let formatter = NoCalendarFormatter::try_new(
1631        ///     locale!("en-US").into(),
1632        ///     GenericLong,
1633        /// )
1634        /// .unwrap();
1635        ///
1636        /// // error[E0271]: type mismatch resolving `<Base as TimeZoneModel>::ZoneNameTimestamp == ZoneNameTimestamp`
1637        /// formatter.format(&time_zone_basic);
1638        /// ```
1639        GenericLong,
1640        description = "time zone in generic non-location format, long length",
1641        length_override = Long,
1642        sample = "Central Time",
1643        field = (fields::TimeZone::GenericNonLocation, fields::FieldLength::Four),
1644        zone_essentials = yes,
1645        zone_locations = yes,
1646        zone_generic_long = yes,
1647        zone_standard_long = yes,
1648        metazone_periods = yes,
1649        input_tzid = yes,
1650        input_timestamp = yes,
1651    );
1652
1653    impl_zone_marker!(
1654        /// If a non-location name is not defined, falls back to the location format, which is
1655        /// often significantly longer!
1656        /// This is the case for most zones, as each locale only contains the short names that are
1657        /// used locally and generally understood:
1658        ///
1659        /// ```
1660        /// use icu::datetime::input::{Date, DateTime, Time, TimeZone, TimeZoneInfo, UtcOffset};
1661        /// use icu::datetime::NoCalendarFormatter;
1662        /// use icu::datetime::fieldsets::zone::GenericShort;
1663        /// use icu::locale::{locale, subtags::subtag};
1664        /// use writeable::assert_writeable_eq;
1665        ///
1666        /// // Time zone info for Asia/Tokyo
1667        /// let zone = TimeZone(subtag!("jptyo"))
1668        ///     .with_offset("+09".parse().ok())
1669        ///     .at_date_time_iso(DateTime{ date: Date::try_new_iso(2022, 1, 29).unwrap(), time: Time::start_of_day() });
1670        ///
1671        /// let fmt = NoCalendarFormatter::try_new(
1672        ///     locale!("en").into(),
1673        ///     GenericShort,
1674        /// )
1675        /// .unwrap();
1676        ///
1677        /// // "JST" is not generally known in American English
1678        /// assert_writeable_eq!(
1679        ///     fmt.format(&zone),
1680        ///     "Japan Time"
1681        /// );
1682        /// ```
1683        ///
1684        /// If the offset doesn't match one of the valid offsets for the zone, falls back to the localized offset format:
1685        /// ```
1686        /// use icu::datetime::input::{Date, DateTime, Time, TimeZone, TimeZoneInfo, UtcOffset};
1687        /// use icu::datetime::NoCalendarFormatter;
1688        /// use icu::datetime::fieldsets::zone::GenericShort;
1689        /// use icu::locale::{locale, subtags::subtag};
1690        /// use writeable::assert_writeable_eq;
1691        ///
1692        /// // Time zone info for America/Chicago with a wrong offset
1693        /// let wrong_offset = TimeZone(subtag!("uschi"))
1694        ///     .with_offset("-04".parse().ok())
1695        ///     .at_date_time_iso(DateTime{ date: Date::try_new_iso(2022, 8, 29).unwrap(), time: Time::start_of_day() });
1696        ///
1697        /// let fmt = NoCalendarFormatter::try_new(
1698        ///     locale!("en").into(),
1699        ///     GenericShort,
1700        /// )
1701        /// .unwrap();
1702        ///
1703        /// assert_writeable_eq!(
1704        ///     fmt.format(&wrong_offset),
1705        ///     "GMT-4"
1706        /// );
1707        ///
1708        /// // This of course always happens for the unknown time zone
1709        /// let unk = TimeZone::UNKNOWN.with_offset(wrong_offset.offset()).with_zone_name_timestamp(wrong_offset.zone_name_timestamp());
1710        ///
1711        /// assert_writeable_eq!(
1712        ///     fmt.format(&unk),
1713        ///     "GMT-4"
1714        /// );
1715        /// ```
1716        ///
1717        /// Since non-location names might change over time,
1718        /// this time zone style requires a reference time.
1719        ///
1720        /// ```compile_fail,E0271
1721        /// use icu::datetime::NoCalendarFormatter;
1722        /// use icu::datetime::fieldsets::zone::GenericShort;
1723        /// use icu::datetime::input::TimeZone;
1724        /// use icu::locale::{locale, subtags::subtag};
1725        ///
1726        /// let time_zone_basic = TimeZone(subtag!("uschi")).without_offset();
1727        ///
1728        /// let formatter = NoCalendarFormatter::try_new(
1729        ///     locale!("en-US").into(),
1730        ///     GenericShort,
1731        /// )
1732        /// .unwrap();
1733        ///
1734        /// // error[E0271]: type mismatch resolving `<Base as TimeZoneModel>::ZoneNameTimestamp == ZoneNameTimestamp`
1735        /// formatter.format(&time_zone_basic);
1736        /// ```
1737        GenericShort,
1738        description = "time zone in generic non-location format, short length",
1739        length_override = Short,
1740        sample = "CT",
1741        field = (fields::TimeZone::GenericNonLocation, fields::FieldLength::One),
1742        zone_essentials = yes,
1743        zone_locations = yes,
1744        zone_generic_short = yes,
1745        metazone_periods = yes,
1746        input_tzid = yes,
1747        input_timestamp = yes,
1748    );
1749
1750    impl_zone_marker!(
1751        /// A time zone ID is required to format with this style.
1752        /// For example, a raw [`UtcOffset`] cannot be used here.
1753        ///
1754        /// ```compile_fail,E0277
1755        /// use icu::datetime::input::DateTime;
1756        /// use icu::datetime::NoCalendarFormatter;
1757        /// use icu::datetime::fieldsets::zone::Location;
1758        /// use icu::datetime::input::UtcOffset;
1759        /// use tinystr::tinystr;
1760        /// use icu::locale::locale;
1761        /// use writeable::assert_writeable_eq;
1762        ///
1763        /// let utc_offset = UtcOffset::try_from_str("-06").unwrap();
1764        ///
1765        /// let formatter = NoCalendarFormatter::try_new(
1766        ///     locale!("en-US").into(),
1767        ///     Location,
1768        /// )
1769        /// .unwrap();
1770        ///
1771        /// // error[E0277]: the trait bound `UtcOffset: AllInputMarkers<Location>` is not satisfied
1772        /// // note: required by a bound in `NoCalendarFormatter::<C, FSet>::format`
1773        /// formatter.format(&utc_offset);
1774        /// ```
1775        Location,
1776        description = "time zone in location format",
1777        length_override = Long,
1778        sample = "Chicago Time",
1779        field = (fields::TimeZone::Location, fields::FieldLength::Four),
1780        zone_essentials = yes,
1781        zone_locations = yes,
1782        input_tzid = yes,
1783    );
1784
1785    impl_zone_marker!(
1786        /// A time zone ID is required to format with this style.
1787        /// For example, a raw [`UtcOffset`] cannot be used here.
1788        ///
1789        /// ```compile_fail,E0277
1790        /// use icu::datetime::input::DateTime;
1791        /// use icu::datetime::NoCalendarFormatter;
1792        /// use icu::datetime::fieldsets::zone::ExemplarCity;
1793        /// use icu::datetime::input::UtcOffset;
1794        /// use tinystr::tinystr;
1795        /// use icu::locale::locale;
1796        /// use writeable::assert_writeable_eq;
1797        ///
1798        /// let utc_offset = UtcOffset::try_from_str("-06").unwrap();
1799        ///
1800        /// let formatter = NoCalendarFormatter::try_new(
1801        ///     locale!("en-US").into(),
1802        ///     ExemplarCity,
1803        /// )
1804        /// .unwrap();
1805        ///
1806        /// // error[E0277]: the trait bound `UtcOffset: AllInputMarkers<ExemplarCity>` is not satisfied
1807        /// // note: required by a bound in `NoCalendarFormatter::<C, FSet>::format`
1808        /// formatter.format(&utc_offset);
1809        /// ```
1810        ExemplarCity,
1811        description = "time zone in exemplar city format",
1812        length_override = Long,
1813        sample = "Chicago",
1814        field = (fields::TimeZone::Location, fields::FieldLength::Three),
1815        zone_locations = yes,
1816        zone_exemplars = yes,
1817        input_tzid = yes,
1818    );
1819}
1820
1821impl_zone_combo_helpers!(DateFieldSet, DateZone, DateFieldSet);
1822
1823impl_zone_combo_helpers!(TimeFieldSet, TimeZone, TimeFieldSet);
1824
1825impl_zone_combo_helpers!(DateAndTimeFieldSet, DateTimeZone, DateAndTimeFieldSet);