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

zbraniecki / icu4x / 13958601093

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

push

github

web-flow
Clean up properties docs (#6315)

58056 of 78281 relevant lines covered (74.16%)

819371.32 hits per line

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

47.22
/components/datetime/src/dynamic.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
//! Enumerations over [field sets](crate::fieldsets).
6
//!
7
//! These enumerations can be used when the field set is not known at compile time. However,
8
//! they may contribute negatively to the binary size of the formatters.
9
//!
10
//! The most general type is [`CompositeFieldSet`], which supports all field
11
//! sets in a single enumeration. [`CompositeDateTimeFieldSet`] is a good
12
//! choice when you don't need to format time zones.
13
//!
14
//! Summary of all the types:
15
//!
16
//! | Type | Supported Field Sets |
17
//! |---|---|
18
//! | [`DateFieldSet`] | Date |
19
//! | [`CalendarPeriodFieldSet`] | Calendar Period |
20
//! | [`TimeFieldSet`] | Time |
21
//! | [`ZoneFieldSet`] | Zone |
22
//! | [`DateAndTimeFieldSet`] | Date + Time |
23
//! | [`CompositeDateTimeFieldSet`] | Date, Calendar Period, Time, Date + Time |
24
//! | [`CompositeFieldSet`] | All |
25
//!
26
//! # Examples
27
//!
28
//! Format with the time display depending on a runtime boolean:
29
//!
30
//! ```
31
//! use icu::calendar::Date;
32
//! use icu::datetime::fieldsets;
33
//! use icu::datetime::fieldsets::enums::CompositeDateTimeFieldSet;
34
//! use icu::datetime::input::{DateTime, Time};
35
//! use icu::datetime::DateTimeFormatter;
36
//! use icu::locale::locale;
37
//! use writeable::Writeable;
38
//!
39
//! fn get_field_set(should_display_time: bool) -> CompositeDateTimeFieldSet {
40
//!     if should_display_time {
41
//!         let field_set = fieldsets::MDT::medium().hm();
42
//!         CompositeDateTimeFieldSet::DateTime(
43
//!             fieldsets::enums::DateAndTimeFieldSet::MDT(field_set),
44
//!         )
45
//!     } else {
46
//!         let field_set = fieldsets::MD::medium();
47
//!         CompositeDateTimeFieldSet::Date(fieldsets::enums::DateFieldSet::MD(
48
//!             field_set,
49
//!         ))
50
//!     }
51
//! }
52
//!
53
//! let datetime = DateTime {
54
//!     date: Date::try_new_iso(2025, 1, 15).unwrap(),
55
//!     time: Time::try_new(16, 0, 0, 0).unwrap(),
56
//! };
57
//!
58
//! let results = [true, false]
59
//!     .map(get_field_set)
60
//!     .map(|field_set| {
61
//!         DateTimeFormatter::try_new(locale!("en-US").into(), field_set)
62
//!             .unwrap()
63
//!     })
64
//!     .map(|formatter| formatter.format(&datetime).to_string());
65
//!
66
//! assert_eq!(results, ["Jan 15, 4:00 PM", "Jan 15"])
67
//! ```
68

69
use crate::fieldsets::{builder, Combo};
70
use crate::raw::neo::RawOptions;
71
use crate::scaffold::GetField;
72
use crate::{fieldsets, provider};
73
use icu_provider::prelude::*;
74

75
/// An enumeration over all possible date field sets.
76
///
77
/// This is a dynamic field set. For more information, see [`enums`](crate::fieldsets::enums).
78
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
×
79
#[non_exhaustive]
80
pub enum DateFieldSet {
81
    /// The day of the month, as in
82
    /// “on the 1st”.
83
    D(fieldsets::D),
×
84
    /// The month and day of the month, as in
85
    /// “January 1st”.
86
    MD(fieldsets::MD),
×
87
    /// The year, month, and day of the month, as in
88
    /// “January 1st, 2000”.
89
    YMD(fieldsets::YMD),
×
90
    /// The day of the month and day of the week, as in
91
    /// “Saturday 1st”.
92
    DE(fieldsets::DE),
×
93
    /// The month, day of the month, and day of the week, as in
94
    /// “Saturday, January 1st”.
95
    MDE(fieldsets::MDE),
×
96
    /// The year, month, day of the month, and day of the week, as in
97
    /// “Saturday, January 1st, 2000”.
98
    YMDE(fieldsets::YMDE),
×
99
    /// The day of the week alone, as in
100
    /// “Saturday”.
101
    E(fieldsets::E),
×
102
}
103

104
/// An enumeration over all possible calendar period field sets.
105
///
106
/// This is a dynamic field set. For more information, see [`enums`](crate::fieldsets::enums).
107
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
×
108
#[non_exhaustive]
109
pub enum CalendarPeriodFieldSet {
110
    /// A standalone month, as in
111
    /// “January”.
112
    M(fieldsets::M),
×
113
    /// A month and year, as in
114
    /// “January 2000”.
115
    YM(fieldsets::YM),
×
116
    /// A year, as in
117
    /// “2000”.
118
    Y(fieldsets::Y),
×
119
    // TODO: Add support for week-of-year
120
    // /// The year and week of the year, as in
121
    // /// “52nd week of 1999”.
122
    // YW(fieldsets::YW),
123
    // TODO(#501): Consider adding support for Quarter and YearQuarter.
124
}
125

126
/// An enumeration over all possible time field sets.
127
///
128
/// This is a dynamic field set. For more information, see [`enums`](crate::fieldsets::enums).
129
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
2✔
130
#[non_exhaustive]
131
pub enum TimeFieldSet {
132
    /// A time of day.
133
    T(fieldsets::T),
1✔
134
}
135

136
/// An enumeration over all possible zone field sets.
137
///
138
/// This is a dynamic field set. For more information, see [`enums`](crate::fieldsets::enums).
139
///
140
/// # Time Zone Data Size
141
///
142
/// Time zone names contribute a lot of data size. For resource-constrained
143
/// environments, the following formats require the least amount of data:
144
///
145
/// - [`fieldsets::zone::SpecificShort`]
146
/// - [`fieldsets::zone::LocalizedOffsetLong`]
147
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
2✔
148
#[non_exhaustive]
149
pub enum ZoneFieldSet {
150
    /// The long specific non-location format, as in
151
    /// “Pacific Daylight Time”.
152
    SpecificLong(fieldsets::zone::SpecificLong),
1✔
153
    /// The short specific non-location format, as in
154
    /// “PDT”.
155
    SpecificShort(fieldsets::zone::SpecificShort),
×
156
    /// The long offset format, as in
157
    /// “GMT−8:00”.
158
    LocalizedOffsetLong(fieldsets::zone::LocalizedOffsetLong),
×
159
    /// The short offset format, as in
160
    /// “GMT−8”.
161
    LocalizedOffsetShort(fieldsets::zone::LocalizedOffsetShort),
×
162
    /// The long generic non-location format, as in
163
    /// “Pacific Time”.
164
    GenericLong(fieldsets::zone::GenericLong),
×
165
    /// The short generic non-location format, as in
166
    /// “PT”.
167
    GenericShort(fieldsets::zone::GenericShort),
×
168
    /// The location format, as in
169
    /// “Los Angeles Time”.
170
    Location(fieldsets::zone::Location),
×
171
    /// The exemplar city format, as in
172
    /// “Los Angeles.
173
    ExemplarCity(fieldsets::zone::ExemplarCity),
×
174
}
175

176
/// An enumeration over all possible date+time composite field sets.
177
///
178
/// This is a dynamic field set. For more information, see [`enums`](crate::fieldsets::enums).
179
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
×
180
#[non_exhaustive]
181
pub enum DateAndTimeFieldSet {
182
    /// The day of the month with time of day, as in
183
    /// “on the 1st at 10:31 AM”.
184
    DT(fieldsets::DT),
×
185
    /// The month and day of the month with time of day, as in
186
    /// “January 1st at 10:31 AM”.
187
    MDT(fieldsets::MDT),
×
188
    /// The year, month, and day of the month with time of day, as in
189
    /// “January 1st, 2000 at 10:31 AM”.
190
    YMDT(fieldsets::YMDT),
×
191
    /// The day of the month and day of the week with time of day, as in
192
    /// “Saturday 1st at 10:31 AM”.
193
    DET(fieldsets::DET),
×
194
    /// The month, day of the month, and day of the week with time of day, as in
195
    /// “Saturday, January 1st at 10:31 AM”.
196
    MDET(fieldsets::MDET),
×
197
    /// The year, month, day of the month, and day of the week with time of day, as in
198
    /// “Saturday, January 1st, 2000 at 10:31 AM”.
199
    YMDET(fieldsets::YMDET),
×
200
    /// The day of the week alone with time of day, as in
201
    /// “Saturday at 10:31 AM”.
202
    ET(fieldsets::ET),
×
203
}
204

205
/// An enum supporting date, calendar period, time, and date+time field sets
206
/// and options.
207
///
208
/// Time zones are not supported with this enum.
209
///
210
/// This enum is useful when formatting a type that does not contain a
211
/// time zone or to avoid storing time zone data.
212
///
213
/// This is a dynamic field set. For more information, see [`enums`](crate::fieldsets::enums).
214
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
×
215
#[non_exhaustive]
216
pub enum CompositeDateTimeFieldSet {
217
    /// Field set for a date.
218
    Date(DateFieldSet),
×
219
    /// Field set for a calendar period.
220
    CalendarPeriod(CalendarPeriodFieldSet),
×
221
    /// Field set for a time.
222
    Time(TimeFieldSet),
21✔
223
    /// Field set for a date and a time together.
224
    DateTime(DateAndTimeFieldSet),
18✔
225
}
226

227
impl CompositeDateTimeFieldSet {
228
    /// If the [`CompositeFieldSet`] does not contain a time zone,
229
    /// returns the corresponding [`CompositeDateTimeFieldSet`].
230
    pub fn try_from_composite_field_set(field_set: CompositeFieldSet) -> Option<Self> {
×
231
        match field_set {
×
232
            CompositeFieldSet::Date(v) => Some(Self::Date(v)),
×
233
            CompositeFieldSet::CalendarPeriod(v) => Some(Self::CalendarPeriod(v)),
×
234
            CompositeFieldSet::Time(v) => Some(Self::Time(v)),
×
235
            CompositeFieldSet::Zone(_) => None,
×
236
            CompositeFieldSet::DateTime(v) => Some(Self::DateTime(v)),
×
237
            CompositeFieldSet::DateZone(_) => None,
×
238
            CompositeFieldSet::TimeZone(_) => None,
×
239
            CompositeFieldSet::DateTimeZone(_) => None,
×
240
        }
241
    }
×
242

243
    /// Returns the [`CompositeFieldSet`] corresponding to this
244
    /// [`CompositeDateTimeFieldSet`].
245
    pub fn to_composite_field_set(self) -> CompositeFieldSet {
275✔
246
        match self {
275✔
247
            Self::Date(v) => CompositeFieldSet::Date(v),
83✔
248
            Self::CalendarPeriod(v) => CompositeFieldSet::CalendarPeriod(v),
28✔
249
            Self::Time(v) => CompositeFieldSet::Time(v),
42✔
250
            Self::DateTime(v) => CompositeFieldSet::DateTime(v),
122✔
251
        }
252
    }
275✔
253
}
254

255
impl GetField<CompositeFieldSet> for CompositeDateTimeFieldSet {
256
    fn get_field(&self) -> CompositeFieldSet {
273✔
257
        self.to_composite_field_set()
273✔
258
    }
273✔
259
}
260

261
/// An enum supporting all possible field sets and options.
262
///
263
/// This is a dynamic field set. For more information, see [`enums`](crate::fieldsets::enums).
264
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
×
265
#[non_exhaustive]
266
pub enum CompositeFieldSet {
267
    /// Field set for a date.
268
    Date(DateFieldSet),
×
269
    /// Field set for a calendar period.
270
    CalendarPeriod(CalendarPeriodFieldSet),
×
271
    /// Field set for a time.
272
    Time(TimeFieldSet),
1✔
273
    /// Field set for a time zone.
274
    Zone(ZoneFieldSet),
8✔
275
    /// Field set for a date and a time together.
276
    DateTime(DateAndTimeFieldSet),
7✔
277
    /// Field set for a date and a time zone together.
278
    DateZone(Combo<DateFieldSet, ZoneFieldSet>),
×
279
    /// Field set for a time and a time zone together.
280
    TimeZone(Combo<TimeFieldSet, ZoneFieldSet>),
×
281
    /// Field set for a date, a time, and a time zone together.
282
    DateTimeZone(Combo<DateAndTimeFieldSet, ZoneFieldSet>),
×
283
}
284

285
macro_rules! first {
286
    ($first:literal, $($remainder:literal,)*) => {
287
        $first
288
    };
289
}
290

291
macro_rules! impl_attrs {
292
    (@attrs, $type:path, [$(($attr_var:ident, $str_var:ident, $value:literal),)+]) => {
293
        impl $type {
294
            $(
295
                const $attr_var: &'static DataMarkerAttributes = DataMarkerAttributes::from_str_or_panic($value);
296
            )+
297
            /// All attributes associated with this enum.
298
            ///
299
            /// # Encoding Details
300
            ///
301
            /// The string is based roughly on the UTS 35 symbol table with the following exceptions:
302
            ///
303
            /// 1. Lowercase letters are chosen where there is no ambiguity: `E` becomes `e`
304
            /// 2. Capitals are replaced with their lowercase and a number 0: `M` becomes `m0`
305
            /// 3. A single symbol is included for each component: length doesn't matter
306
            /// 4. Time fields are encoded with their hour field only: `j`, `h`, or `h0`
307
            ///
308
            /// # Examples
309
            ///
310
            /// ```
311
            #[doc = concat!("use icu::datetime::fieldsets::enums::", stringify!($type), " as FS;")]
312
            /// use icu_provider::DataMarkerAttributes;
313
            ///
314
            /// assert!(FS::ALL_DATA_MARKER_ATTRIBUTES.contains(
315
            #[doc = concat!("    &DataMarkerAttributes::from_str_or_panic(\"", first!($($value,)*), "\")")]
316
            /// ));
317
            /// ```
318
            pub const ALL_DATA_MARKER_ATTRIBUTES: &'static [&'static DataMarkerAttributes] = &[
319
                $(
320
                    Self::$attr_var,
321
                )+
322
            ];
323
        }
324
    };
325
    (@id_str, $type:path, [$(($variant:ident, $attr_var:ident)),+,]) => {
326
        impl $type {
327
            /// Returns a stable string identifying this set of fields.
328
            pub(crate) const fn id_str(self) -> &'static DataMarkerAttributes {
301✔
329
                match self {
301✔
330
                    $(
331
                        Self::$variant(_) => Self::$attr_var,
301✔
332
                    )+
333
                }
334
            }
301✔
335
        }
336
    };
337
    (@to_raw_options, $type:path, [$($variant:ident),+,]) => {
338
        impl $type {
339
            pub(crate) fn to_raw_options(self) -> RawOptions {
371✔
340
                match self {
310✔
341
                    $(
342
                        Self::$variant(variant) => variant.to_raw_options(),
371✔
343
                    )+
344
                }
345
            }
371✔
346
        }
347
    };
348
    (@composite, $type:path, $variant:ident) => {
349
        impl $type {
350
            #[inline]
351
            pub(crate) fn to_enum(self) -> $type {
×
352
                self
×
353
            }
×
354
        }
355
        impl GetField<CompositeFieldSet> for $type {
356
            #[inline]
357
            fn get_field(&self) -> CompositeFieldSet {
×
358
                CompositeFieldSet::$variant(self.to_enum())
×
359
            }
×
360
        }
361
    };
362
    (@date, $type:path, [$(($variant:ident, $attr_var:ident, $str_var:ident, $value:literal)),+,]) => {
363
        impl_attrs! { @attrs, $type, [$(($attr_var, $str_var, $value)),+,] }
364
        impl_attrs! { @id_str, $type, [$(($variant, $attr_var)),+,] }
365
        impl_attrs! { @to_raw_options, $type, [$($variant),+,] }
366
        impl_attrs! { @composite, $type, Date }
367
    };
368
    (@calendar_period, $type:path, [$(($variant:ident, $attr_var:ident, $str_var:ident, $value:literal)),+,]) => {
369
        impl_attrs! { @attrs, $type, [$(($attr_var, $str_var, $value)),+,] }
370
        impl_attrs! { @to_raw_options, $type, [$($variant),+,] }
371
        impl_attrs! { @composite, $type, CalendarPeriod }
372
        impl_attrs! { @id_str, $type, [$(($variant, $attr_var)),+,] }
373
    };
374
    (@time, $type:path, [$(($attr_var:ident, $str_var:ident, $value:literal)),+,]) => {
375
        impl_attrs! { @attrs, $type, [$(($attr_var, $str_var, $value)),+,] }
376
        impl_attrs! { @to_raw_options, $type, [T,] }
377
        impl_attrs! { @composite, $type, Time }
378
    };
379
    (@zone, $type:path, [$($variant:ident),+,]) => {
380
        impl_attrs! { @composite, $type, Zone }
381
        impl $type {
382
            pub(crate) fn to_field(self) -> (provider::fields::TimeZone, provider::fields::FieldLength) {
131✔
383
                match self {
131✔
384
                    $(
385
                        Self::$variant(variant) => variant.to_field(),
131✔
386
                    )+
387
                }
388
            }
131✔
389
            pub(crate) fn to_zone_style(self) -> builder::ZoneStyle {
×
390
                match self {
×
391
                    $(
392
                        Self::$variant(_) => builder::ZoneStyle::$variant,
×
393
                    )+
394
                }
395
            }
×
396
        }
397
    };
398
    (@datetime, $type:path, [$(($d_variant:ident, $variant:ident)),+,]) => {
399
        impl_attrs! { @to_raw_options, $type, [$($variant),+,] }
400
        impl_attrs! { @composite, $type, DateTime }
401
        impl $type {
402
            pub(crate) fn to_date_field_set(self) -> DateFieldSet {
140✔
403
                match self {
140✔
404
                    $(
405
                        Self::$variant(variant) => DateFieldSet::$d_variant(variant.to_date_field_set()),
140✔
406
                    )+
407
                }
408
            }
140✔
409
            pub(crate) fn to_time_field_set(self) -> TimeFieldSet {
140✔
410
                let (length, time_precision, alignment) = match self {
280✔
411
                    $(
412
                        Self::$variant(variant) => (variant.length, variant.time_precision, variant.alignment),
140✔
413
                    )+
414
                };
415
                TimeFieldSet::T(fieldsets::T {
140✔
416
                    length,
417
                    time_precision,
418
                    alignment,
419
                })
420
            }
140✔
421
        }
422
    };
423
}
424

425
impl_attrs! {
426
    @date,
427
    DateFieldSet,
428
    [
429
        (D, ATTR_D, STR_D, "d"),
430
        (MD, ATTR_MD, STR_MD, "m0d"),
431
        (YMD, ATTR_YMD, STR_YMD, "ym0d"),
432
        (DE, ATTR_DE, STR_DE, "de"),
433
        (MDE, ATTR_MDE, STR_MDE, "m0de"),
434
        (YMDE, ATTR_YMDE, STR_YMDE, "ym0de"),
435
        (E, ATTR_E, STR_E, "e"),
436
    ]
437
}
438

439
impl_attrs! {
440
    @calendar_period,
441
    CalendarPeriodFieldSet,
442
    [
443
        (M, ATTR_M, STR_M, "m0"),
444
        (YM, ATTR_YM, STR_YM, "ym0"),
445
        (Y, ATTR_Y, STR_Y, "y"),
446
    ]
447
}
448

449
impl_attrs! {
450
    @time,
451
    TimeFieldSet,
452
    [
453
        (ATTR_T, STR_T, "j"),
454
        (ATTR_T12, STR_T12, "h"),
455
        (ATTR_T24, STR_T24, "h0"),
456
    ]
457
}
458

459
impl TimeFieldSet {
460
    pub(crate) const fn id_str_for_hour_cycle(
201✔
461
        self,
462
        hour_cycle: Option<provider::fields::Hour>,
463
    ) -> &'static DataMarkerAttributes {
464
        use provider::fields::Hour::*;
465
        match hour_cycle {
201✔
466
            None => Self::ATTR_T,
69✔
467
            Some(H11 | H12) => Self::ATTR_T12,
27✔
468
            Some(H23 | H24) => Self::ATTR_T24,
105✔
469
        }
470
    }
201✔
471
}
472

473
impl_attrs! {
474
    @zone,
475
    ZoneFieldSet,
476
    [
477
        SpecificLong,
478
        SpecificShort,
479
        LocalizedOffsetLong,
480
        LocalizedOffsetShort,
481
        GenericLong,
482
        GenericShort,
483
        Location,
484
        ExemplarCity,
485
    ]
486
}
487

488
impl_attrs! {
489
    @attrs,
490
    DateAndTimeFieldSet,
491
    [
492
        (ATTR_ET, STR_ET, "ej"),
493
    ]
494
}
495

496
impl_attrs! {
497
    @datetime,
498
    DateAndTimeFieldSet,
499
    [
500
        (D, DT),
501
        (MD, MDT),
502
        (YMD, YMDT),
503
        (DE, DET),
504
        (MDE, MDET),
505
        (YMDE, YMDET),
506
        (E, ET),
507
    ]
508
}
509

510
impl DateAndTimeFieldSet {
511
    pub(crate) const fn id_str(self) -> Option<&'static DataMarkerAttributes> {
141✔
512
        match self {
141✔
513
            DateAndTimeFieldSet::ET(_) => Some(Self::ATTR_ET),
15✔
514
            _ => None,
126✔
515
        }
516
    }
141✔
517
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc