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);