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

zbraniecki / icu4x / 6815798908

09 Nov 2023 05:17PM UTC coverage: 72.607% (-2.4%) from 75.01%
6815798908

push

github

web-flow
Implement `Any/BufferProvider` for some smart pointers (#4255)

Allows storing them as a `Box<dyn Any/BufferProvider>` without using a
wrapper type that implements the trait.

44281 of 60987 relevant lines covered (72.61%)

201375.86 hits per line

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

37.5
/components/datetime/src/datetime.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
//! The collection of code that is needed for handling formatting operations for DateTimes.
6
//! Central to this is the [`TypedDateTimeFormatter`].
7

8
use crate::{
9
    options::{length, preferences, DateTimeFormatterOptions},
10
    provider::calendar::{TimeLengthsV1Marker, TimeSymbolsV1Marker},
11
    provider::date_time::PatternSelector,
12
    raw,
13
};
14
use alloc::string::String;
15
use core::marker::PhantomData;
16
use icu_calendar::provider::WeekDataV1Marker;
17
use icu_decimal::provider::DecimalSymbolsV1Marker;
18
use icu_plurals::provider::OrdinalV1Marker;
19
use icu_provider::prelude::*;
20
use writeable::Writeable;
21

22
use crate::{
23
    calendar, input::DateInput, input::DateTimeInput, input::IsoTimeInput, CldrCalendar,
24
    DateTimeError, FormattedDateTime,
25
};
26

27
/// [`TimeFormatter`] is a structure of the [`icu_datetime`] component that provides time formatting only.
28
/// When constructed, it uses data from the [data provider], selected locale and provided preferences to
29
/// collect all data necessary to format any time into that locale.
30
///
31
/// For that reason, one should think of the process of formatting a time in two steps - first, a computational
32
/// heavy construction of [`TimeFormatter`], and then fast formatting of [`DateTimeInput`] data using the instance.
33
///
34
/// [`icu_datetime`]: crate
35
/// [`TypedDateTimeFormatter`]: crate::datetime::TimeFormatter
36
///
37
/// # Examples
38
///
39
/// ```
40
/// use icu::calendar::DateTime;
41
/// use icu::datetime::{options::length::Time, TimeFormatter};
42
/// use icu::locid::locale;
43
/// use writeable::assert_writeable_eq;
44
///
45
/// let tf =
46
///     TimeFormatter::try_new_with_length(&locale!("en").into(), Time::Short)
47
///         .expect("Failed to create TimeFormatter instance.");
48
///
49
/// let datetime = DateTime::try_new_gregorian_datetime(2020, 9, 1, 12, 34, 28)
50
///     .expect("Failed to construct DateTime.");
51
///
52
/// assert_writeable_eq!(tf.format(&datetime), "12:34 PM");
53
/// ```
54
///
55
/// This model replicates that of `ICU` and `ECMA402`.
56
///
57
/// [data provider]: icu_provider
58
#[derive(Debug)]
×
59
pub struct TimeFormatter(pub(super) raw::TimeFormatter);
×
60

61
impl TimeFormatter {
62
    /// Constructor that takes a selected locale and a list of preferences, then collects all
63
    /// compiled data necessary to format date and time values into the given locale,
64
    /// using the given style.
65
    ///
66
    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
67
    ///
68
    /// [📚 Help choosing a constructor](icu_provider::constructors)
69
    ///
70
    /// # Examples
71
    ///
72
    /// ```
73
    /// use icu::datetime::{options::length::Time, TimeFormatter};
74
    /// use icu::locid::locale;
75
    ///
76
    /// TimeFormatter::try_new_with_length(&locale!("en").into(), Time::Short)
77
    ///     .unwrap();
78
    /// ```
79
    #[cfg(feature = "compiled_data")]
80
    pub fn try_new_with_length(
22✔
81
        locale: &DataLocale,
82
        length: length::Time,
83
    ) -> Result<Self, DateTimeError> {
84
        let preferences = Some(preferences::Bag::from_data_locale(locale));
22✔
85

86
        Ok(Self(raw::TimeFormatter::try_new(
22✔
87
            locale,
88
            length,
89
            preferences,
22✔
90
        )?))
×
91
    }
22✔
92

93
    icu_provider::gen_any_buffer_data_constructors!(
94
        locale: include,
95
        length: length::Time,
96
        error: DateTimeError,
97
        #[cfg(skip)]
98
        functions: [
99
            try_new_with_length,
100
            try_new_with_length_with_any_provider,
101
            try_new_with_length_with_buffer_provider,
102
            try_new_with_length_unstable,
103
            Self,
104
        ]
105
    );
106

107
    #[inline]
108
    #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::try_new_with_length)]
109
    pub fn try_new_with_length_unstable<D>(
×
110
        provider: &D,
111
        locale: &DataLocale,
112
        length: length::Time,
113
    ) -> Result<Self, DateTimeError>
114
    where
115
        D: DataProvider<TimeLengthsV1Marker>
116
            + DataProvider<TimeSymbolsV1Marker>
117
            + DataProvider<DecimalSymbolsV1Marker>
118
            + ?Sized,
119
    {
120
        let preferences = Some(preferences::Bag::from_data_locale(locale));
×
121

122
        Ok(Self(raw::TimeFormatter::try_new_unstable(
×
123
            provider,
124
            locale,
125
            length,
126
            preferences,
×
127
        )?))
×
128
    }
×
129

130
    /// Takes a [`IsoTimeInput`] implementer and returns an instance of a [`FormattedDateTime`]
131
    /// that contains all information necessary to display a formatted date and operate on it.
132
    ///
133
    /// # Examples
134
    ///
135
    /// ```
136
    /// use icu::calendar::DateTime;
137
    /// use icu::datetime::{options::length::Time, TimeFormatter};
138
    /// use icu::locid::locale;
139
    /// use writeable::assert_writeable_eq;
140
    ///
141
    /// let tf =
142
    ///     TimeFormatter::try_new_with_length(&locale!("en").into(), Time::Short)
143
    ///         .expect("Failed to create TimeFormatter instance.");
144
    ///
145
    /// let datetime = DateTime::try_new_gregorian_datetime(2020, 9, 1, 12, 34, 28)
146
    ///     .expect("Failed to construct DateTime.");
147
    ///
148
    /// assert_writeable_eq!(tf.format(&datetime), "12:34 PM");
149
    /// ```
150
    #[inline]
151
    pub fn format<'l, T>(&'l self, value: &T) -> FormattedDateTime<'l>
×
152
    where
153
        T: IsoTimeInput,
154
    {
155
        self.0.format(value)
×
156
    }
×
157

158
    /// Takes a [`IsoTimeInput`] implementer and returns it formatted as a string.
159
    ///
160
    /// # Examples
161
    ///
162
    /// ```
163
    /// use icu::calendar::DateTime;
164
    /// use icu::datetime::{options::length::Time, TimeFormatter};
165
    /// use icu::locid::locale;
166
    /// let tf =
167
    ///     TimeFormatter::try_new_with_length(&locale!("en").into(), Time::Short)
168
    ///         .expect("Failed to create TimeFormatter instance.");
169
    ///
170
    /// let datetime = DateTime::try_new_gregorian_datetime(2020, 9, 1, 12, 34, 28)
171
    ///     .expect("Failed to construct DateTime.");
172
    ///
173
    /// assert_eq!(tf.format_to_string(&datetime), "12:34 PM");
174
    /// ```
175
    #[inline]
176
    pub fn format_to_string(&self, value: &impl IsoTimeInput) -> String {
177
        self.format(value).write_to_string().into_owned()
178
    }
179
}
180

181
/// [`TypedDateFormatter`] is a formatter capable of formatting
182
/// dates from a calendar selected at compile time. For the difference between this
183
/// and [`DateFormatter`](crate::DateFormatter), please read the [crate root docs][crate].
184
///
185
/// When constructed, it uses data from the [data provider], selected locale and provided options to
186
/// collect all data necessary to format any dates into that locale.
187
///
188
/// For that reason, one should think of the process of formatting a date in two steps - first, a computational
189
/// heavy construction of [`TypedDateFormatter`], and then fast formatting of [`DateInput`] data using the instance.
190
///
191
/// [`icu_datetime`]: crate
192
///
193
/// # Examples
194
///
195
/// ```
196
/// use icu::calendar::{Date, Gregorian};
197
/// use icu::datetime::{options::length, TypedDateFormatter};
198
/// use icu::locid::locale;
199
/// use writeable::assert_writeable_eq;
200
///
201
/// let df = TypedDateFormatter::<Gregorian>::try_new_with_length(
202
///     &locale!("en").into(),
203
///     length::Date::Full,
204
/// )
205
/// .expect("Failed to create TypedDateFormatter instance.");
206
///
207
/// let date = Date::try_new_gregorian_date(2020, 9, 1)
208
///     .expect("Failed to construct Date.");
209
///
210
/// assert_writeable_eq!(df.format(&date), "Tuesday, September 1, 2020");
211
/// ```
212
///
213
/// This model replicates that of `ICU` and `ECMA402`.
214
///
215
/// [data provider]: icu_provider
216
#[derive(Debug)]
217
pub struct TypedDateFormatter<C>(pub(super) raw::DateFormatter, PhantomData<C>);
218

219
impl<C: CldrCalendar> TypedDateFormatter<C> {
220
    /// Constructor that takes a selected locale and a list of options, then collects all
221
    /// compiled data necessary to format date and time values into the given locale.
222
    ///
223
    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
224
    ///
225
    /// [📚 Help choosing a constructor](icu_provider::constructors)
226
    ///
227
    /// # Examples
228
    ///
229
    /// ```
230
    /// use icu::calendar::Date;
231
    /// use icu::calendar::Gregorian;
232
    /// use icu::datetime::{options::length, TypedDateFormatter};
233
    /// use icu::locid::locale;
234
    /// use writeable::assert_writeable_eq;
235
    ///
236
    /// let formatter = TypedDateFormatter::<Gregorian>::try_new_with_length(
237
    ///     &locale!("en").into(),
238
    ///     length::Date::Full,
239
    /// )
240
    /// .unwrap();
241
    ///
242
    /// assert_writeable_eq!(
243
    ///     formatter.format(&Date::try_new_gregorian_date(2022, 8, 29).unwrap()),
244
    ///     "Monday, August 29, 2022",
245
    /// );
246
    /// ```
247
    ///
248
    /// If the locale has a calendar keyword, the keyword is ignored in favor of the
249
    /// type parameter on the [`TypedDateFormatter`]. To obey the calendar keyword,
250
    /// use [`DateFormatter`] instead.
251
    ///
252
    /// ```
253
    /// use icu::calendar::indian::Indian;
254
    /// use icu::calendar::Date;
255
    /// use icu::datetime::{options::length, TypedDateFormatter};
256
    /// use icu::locid::locale;
257
    /// use writeable::assert_writeable_eq;
258
    ///
259
    /// let formatter = TypedDateFormatter::<Indian>::try_new_with_length(
260
    ///     &locale!("en-u-ca-japanese").into(),
261
    ///     length::Date::Full,
262
    /// )
263
    /// .unwrap();
264
    ///
265
    /// // Indian format from type wins over locale keyword
266
    /// assert_writeable_eq!(
267
    ///     formatter.format(&Date::try_new_indian_date(1944, 6, 7).unwrap()),
268
    ///     "Monday, Bhadra 7, 1944 Saka",
269
    /// );
270
    /// ```
271
    ///
272
    /// [`DateFormatter`]: crate::DateFormatter
273
    #[cfg(feature = "compiled_data")]
274
    pub fn try_new_with_length(
×
275
        locale: &DataLocale,
276
        length: length::Date,
277
    ) -> Result<Self, DateTimeError>
278
    where
279
        crate::provider::Baked: icu_provider::DataProvider<<C as CldrCalendar>::DateLengthsV1Marker>
280
            + icu_provider::DataProvider<<C as CldrCalendar>::DateSymbolsV1Marker>,
281
    {
282
        Ok(Self(
×
283
            raw::DateFormatter::try_new(
×
284
                calendar::load_lengths_for_cldr_calendar::<C, _>(&crate::provider::Baked, locale)?,
×
285
                || {
×
286
                    calendar::load_symbols_for_cldr_calendar::<C, _>(
×
287
                        &crate::provider::Baked,
288
                        locale,
×
289
                    )
290
                },
×
291
                locale,
292
                length,
293
            )?,
×
294
            PhantomData,
295
        ))
296
    }
×
297

298
    icu_provider::gen_any_buffer_data_constructors!(
299
        locale: include,
300
        length: length::Date,
301
        error: DateTimeError,
302
        #[cfg(skip)]
303
        functions: [
304
            try_new_with_length,
305
            try_new_with_length_with_any_provider,
306
            try_new_with_length_with_buffer_provider,
307
            try_new_with_length_unstable,
308
            Self,
309
        ]
310
    );
311

312
    #[inline]
313
    #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::try_new_with_length)]
314
    pub fn try_new_with_length_unstable<D>(
×
315
        provider: &D,
316
        locale: &DataLocale,
317
        length: length::Date,
318
    ) -> Result<Self, DateTimeError>
319
    where
320
        D: DataProvider<<C as CldrCalendar>::DateSymbolsV1Marker>
321
            + DataProvider<<C as CldrCalendar>::DateLengthsV1Marker>
322
            + DataProvider<DecimalSymbolsV1Marker>
323
            + DataProvider<OrdinalV1Marker>
324
            + DataProvider<WeekDataV1Marker>
325
            + ?Sized,
326
    {
327
        Ok(Self(
×
328
            raw::DateFormatter::try_new_unstable(
×
329
                provider,
330
                calendar::load_lengths_for_cldr_calendar::<C, _>(provider, locale)?,
×
331
                || calendar::load_symbols_for_cldr_calendar::<C, _>(provider, locale),
×
332
                locale,
333
                length,
334
            )?,
×
335
            PhantomData,
336
        ))
337
    }
×
338

339
    /// Takes a [`DateTimeInput`] implementer and returns an instance of a [`FormattedDateTime`]
340
    /// that contains all information necessary to display a formatted date and operate on it.
341
    ///
342
    /// # Examples
343
    ///
344
    /// ```
345
    /// use icu::calendar::{Date, Gregorian};
346
    /// use icu::datetime::{options::length, TypedDateFormatter};
347
    /// use icu::locid::locale;
348
    /// use writeable::assert_writeable_eq;
349
    /// let df = TypedDateFormatter::<Gregorian>::try_new_with_length(
350
    ///     &locale!("en").into(),
351
    ///     length::Date::Full,
352
    /// )
353
    /// .expect("Failed to create TypedDateFormatter instance.");
354
    ///
355
    /// let date = Date::try_new_gregorian_date(2020, 9, 1)
356
    ///     .expect("Failed to construct Date.");
357
    ///
358
    /// assert_writeable_eq!(df.format(&date), "Tuesday, September 1, 2020");
359
    /// ```
360
    #[inline]
361
    pub fn format<'l, T>(&'l self, value: &T) -> FormattedDateTime<'l>
×
362
    where
363
        T: DateInput<Calendar = C>,
364
    {
365
        self.0.format(value)
×
366
    }
×
367

368
    /// Takes a [`DateTimeInput`] implementer and returns it formatted as a string.
369
    ///
370
    /// # Examples
371
    ///
372
    /// ```
373
    /// use icu::calendar::{Date, Gregorian};
374
    /// use icu::datetime::{options::length, TypedDateFormatter};
375
    /// use icu::locid::locale;
376
    /// let df = TypedDateFormatter::<Gregorian>::try_new_with_length(
377
    ///     &locale!("en").into(),
378
    ///     length::Date::Short,
379
    /// )
380
    /// .expect("Failed to create TypedDateTimeFormatter instance.");
381
    ///
382
    /// let date = Date::try_new_gregorian_date(2020, 9, 1)
383
    ///     .expect("Failed to construct Date.");
384
    ///
385
    /// assert_eq!(df.format_to_string(&date), "9/1/20");
386
    /// ```
387
    #[inline]
388
    pub fn format_to_string(&self, value: &impl DateInput<Calendar = C>) -> String {
389
        self.format(value).write_to_string().into_owned()
390
    }
391
}
392

393
/// [`TypedDateTimeFormatter`] is a formatter capable of formatting
394
/// date/times from a calendar selected at compile time. For the difference between this
395
///  and [`DateTimeFormatter`](crate::DateTimeFormatter), please read the [crate root docs][crate].
396
///
397
/// When constructed, it uses data from the [data provider], selected locale and provided options to
398
/// collect all data necessary to format any dates into that locale.
399
///
400
/// For that reason, one should think of the process of formatting a date in two steps - first, a computational
401
/// heavy construction of [`TypedDateTimeFormatter`], and then fast formatting of [`DateInput`] data using the instance.
402
///
403
/// [`icu_datetime`]: crate
404
/// [`TypedDateTimeFormatter`]: crate::datetime::TypedDateTimeFormatter
405
///
406
/// # Examples
407
///
408
/// ```
409
/// use icu::calendar::{DateTime, Gregorian};
410
/// use icu::datetime::{options::length, TypedDateTimeFormatter};
411
/// use icu::locid::locale;
412
/// use writeable::assert_writeable_eq;
413
///
414
/// let mut options = length::Bag::from_date_time_style(
415
///     length::Date::Medium,
416
///     length::Time::Short,
417
/// );
418
///
419
/// let dtf = TypedDateTimeFormatter::<Gregorian>::try_new(
420
///     &locale!("en").into(),
421
///     options.into(),
422
/// )
423
/// .expect("Failed to create TypedDateTimeFormatter instance.");
424
///
425
/// let datetime = DateTime::try_new_gregorian_datetime(2020, 9, 1, 12, 34, 28)
426
///     .expect("Failed to construct DateTime.");
427
///
428
/// assert_writeable_eq!(dtf.format(&datetime), "Sep 1, 2020, 12:34 PM");
429
/// ```
430
///
431
/// This model replicates that of `ICU` and `ECMA402`.
432
///
433
/// [data provider]: icu_provider
434
#[derive(Debug)]
435
pub struct TypedDateTimeFormatter<C>(pub(super) raw::DateTimeFormatter, PhantomData<C>);
436

437
impl<C: CldrCalendar> TypedDateTimeFormatter<C> {
438
    /// Constructor that takes a [`TimeFormatter`] and [`TypedDateFormatter`] and combines them into a [`TypedDateTimeFormatter`].
439
    ///
440
    /// # Examples
441
    ///
442
    /// ```
443
    /// use icu::calendar::Gregorian;
444
    /// use icu::datetime::{
445
    ///     options::length, TimeFormatter, TypedDateFormatter,
446
    ///     TypedDateTimeFormatter,
447
    /// };
448
    /// use icu::locid::locale;
449
    ///
450
    /// let tf = TimeFormatter::try_new_with_length(
451
    ///     &locale!("en").into(),
452
    ///     length::Time::Short,
453
    /// )
454
    /// .expect("Failed to create TimeFormatter instance.");
455
    /// let df = TypedDateFormatter::<Gregorian>::try_new_with_length(
456
    ///     &locale!("en").into(),
457
    ///     length::Date::Short,
458
    /// )
459
    /// .expect("Failed to create TypedDateFormatter instance.");
460
    ///
461
    /// TypedDateTimeFormatter::<Gregorian>::try_from_date_and_time(df, tf)
462
    ///     .unwrap();
463
    /// ```
464
    ///
465
    /// [data provider]: icu_provider
466
    #[inline]
467
    pub fn try_from_date_and_time(
468
        date: TypedDateFormatter<C>,
469
        time: TimeFormatter,
470
    ) -> Result<Self, DateTimeError>
471
where {
472
        Ok(Self(
473
            raw::DateTimeFormatter::try_from_date_and_time(date.0, time.0)?,
474
            PhantomData,
475
        ))
476
    }
477

478
    /// Constructor that takes a selected locale, then collects all
479
    /// compiled data necessary to format date and time values into the given locale.
480
    ///
481
    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
482
    ///
483
    /// [📚 Help choosing a constructor](icu_provider::constructors)
484
    ///
485
    /// # Examples
486
    ///
487
    /// ```
488
    /// use icu::calendar::{DateTime, Gregorian};
489
    /// use icu::datetime::{options::length, TypedDateTimeFormatter};
490
    /// use icu::locid::locale;
491
    /// use writeable::assert_writeable_eq;
492
    ///
493
    /// let options = length::Bag::from_date_time_style(
494
    ///     length::Date::Medium,
495
    ///     length::Time::Medium,
496
    /// );
497
    ///
498
    /// let dtf = TypedDateTimeFormatter::<Gregorian>::try_new(
499
    ///     &locale!("en").into(),
500
    ///     options.into(),
501
    /// )
502
    /// .unwrap();
503
    ///
504
    /// let datetime =
505
    ///     DateTime::try_new_gregorian_datetime(2022, 8, 31, 1, 2, 3).unwrap();
506
    ///
507
    /// assert_writeable_eq!(dtf.format(&datetime), "Aug 31, 2022, 1:02:03 AM");
508
    /// ```
509
    ///
510
    /// [data provider]: icu_provider
511
    #[cfg(feature = "compiled_data")]
512
    pub fn try_new(
1✔
513
        locale: &DataLocale,
514
        options: DateTimeFormatterOptions,
515
    ) -> Result<Self, DateTimeError>
516
    where
517
        crate::provider::Baked: DataProvider<<C as CldrCalendar>::DateLengthsV1Marker>,
518
        crate::provider::Baked: DataProvider<<C as CldrCalendar>::DateSymbolsV1Marker>,
519
    {
520
        let patterns = PatternSelector::for_options(
1✔
521
            &crate::provider::Baked,
522
            calendar::load_lengths_for_cldr_calendar::<C, _>(&crate::provider::Baked, locale)?,
1✔
523
            locale,
524
            &options,
525
        )?;
×
526
        Ok(Self(
1✔
527
            raw::DateTimeFormatter::try_new(
1✔
528
                patterns,
1✔
529
                || {
2✔
530
                    calendar::load_symbols_for_cldr_calendar::<C, _>(
1✔
531
                        &crate::provider::Baked,
532
                        locale,
1✔
533
                    )
534
                },
1✔
535
                locale,
536
            )?,
×
537
            PhantomData,
538
        ))
539
    }
1✔
540

541
    icu_provider::gen_any_buffer_data_constructors!(
542
        locale: include,
543
        options: DateTimeFormatterOptions,
544
        error: DateTimeError,
545
        #[cfg(skip)]
546
        functions: [
547
            try_new,
548
            try_new_with_any_provider,
549
            try_new_with_buffer_provider,
550
            try_new_unstable,
551
            Self
552
        ]
553
    );
554

555
    #[inline]
556
    #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::try_new)]
557
    pub fn try_new_unstable<D>(
×
558
        provider: &D,
559
        locale: &DataLocale,
560
        options: DateTimeFormatterOptions,
561
    ) -> Result<Self, DateTimeError>
562
    where
563
        D: DataProvider<<C as CldrCalendar>::DateSymbolsV1Marker>
564
            + DataProvider<<C as CldrCalendar>::DateLengthsV1Marker>
565
            + DataProvider<TimeSymbolsV1Marker>
566
            + DataProvider<TimeLengthsV1Marker>
567
            + DataProvider<DecimalSymbolsV1Marker>
568
            + DataProvider<OrdinalV1Marker>
569
            + DataProvider<WeekDataV1Marker>
570
            + ?Sized,
571
    {
572
        let patterns = PatternSelector::for_options(
×
573
            provider,
574
            calendar::load_lengths_for_cldr_calendar::<C, _>(provider, locale)?,
×
575
            locale,
576
            &options,
577
        )?;
×
578
        Ok(Self(
×
579
            raw::DateTimeFormatter::try_new_unstable(
×
580
                provider,
581
                patterns,
×
582
                || calendar::load_symbols_for_cldr_calendar::<C, _>(provider, locale),
×
583
                locale,
584
            )?,
×
585
            PhantomData,
586
        ))
587
    }
×
588

589
    /// Constructor that supports experimental options using compiled data.
590
    ///
591
    /// ✨ *Enabled with the `compiled_data` and `experimental` Cargo features.*
592
    ///
593
    /// [📚 Help choosing a constructor](icu_provider::constructors)
594
    ///
595
    /// <div class="stab unstable">
596
    /// 🚧 This code is experimental; it may change at any time, in breaking or non-breaking ways,
597
    /// including in SemVer minor releases. It can be enabled with the "experimental" Cargo feature
598
    /// of the icu meta-crate. Use with caution.
599
    /// <a href="https://github.com/unicode-org/icu4x/issues/1317">#1317</a>
600
    /// </div>
601
    ///
602
    /// # Examples
603
    ///
604
    /// ```
605
    /// use icu::calendar::{DateTime, Gregorian};
606
    /// use icu::datetime::{options::components, TypedDateTimeFormatter};
607
    /// use icu::locid::locale;
608
    /// use icu_provider::AsDeserializingBufferProvider;
609
    /// use writeable::assert_writeable_eq;
610
    ///
611
    /// let mut options = components::Bag::default();
612
    /// options.year = Some(components::Year::Numeric);
613
    /// options.month = Some(components::Month::Long);
614
    ///
615
    /// let dtf = TypedDateTimeFormatter::<Gregorian>::try_new_experimental(
616
    ///     &locale!("en").into(),
617
    ///     options.into(),
618
    /// )
619
    /// .unwrap();
620
    ///
621
    /// let datetime =
622
    ///     DateTime::try_new_gregorian_datetime(2022, 8, 31, 1, 2, 3).unwrap();
623
    ///
624
    /// assert_writeable_eq!(dtf.format(&datetime), "August 2022");
625
    /// ```
626
    ///
627
    /// [data provider]: icu_provider
628
    #[cfg(feature = "experimental")]
629
    #[inline]
630
    #[cfg(feature = "compiled_data")]
631
    pub fn try_new_experimental(
632
        locale: &DataLocale,
633
        options: DateTimeFormatterOptions,
634
    ) -> Result<Self, DateTimeError>
635
    where
636
        crate::provider::Baked: DataProvider<<C as CldrCalendar>::DateLengthsV1Marker>,
637
        crate::provider::Baked: DataProvider<<C as CldrCalendar>::DateSymbolsV1Marker>,
638
    {
639
        let patterns = PatternSelector::for_options_experimental(
640
            &crate::provider::Baked,
641
            calendar::load_lengths_for_cldr_calendar::<C, _>(&crate::provider::Baked, locale)?,
642
            locale,
643
            &C::DEFAULT_BCP_47_IDENTIFIER,
644
            &options,
645
        )?;
646
        Ok(Self(
647
            raw::DateTimeFormatter::try_new(
648
                patterns,
649
                || {
650
                    calendar::load_symbols_for_cldr_calendar::<C, _>(
651
                        &crate::provider::Baked,
652
                        locale,
653
                    )
654
                },
655
                locale,
656
            )?,
657
            PhantomData,
658
        ))
659
    }
660

661
    #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::try_new_experimental)]
662
    #[cfg(feature = "experimental")]
663
    #[inline]
664
    pub fn try_new_experimental_unstable<D>(
665
        provider: &D,
666
        locale: &DataLocale,
667
        options: DateTimeFormatterOptions,
668
    ) -> Result<Self, DateTimeError>
669
    where
670
        D: DataProvider<<C as CldrCalendar>::DateSymbolsV1Marker>
671
            + DataProvider<<C as CldrCalendar>::DateLengthsV1Marker>
672
            + DataProvider<TimeSymbolsV1Marker>
673
            + DataProvider<TimeLengthsV1Marker>
674
            + DataProvider<crate::provider::calendar::DateSkeletonPatternsV1Marker>
675
            + DataProvider<DecimalSymbolsV1Marker>
676
            + DataProvider<OrdinalV1Marker>
677
            + DataProvider<WeekDataV1Marker>
678
            + ?Sized,
679
    {
680
        let patterns = PatternSelector::for_options_experimental(
681
            provider,
682
            calendar::load_lengths_for_cldr_calendar::<C, _>(provider, locale)?,
683
            locale,
684
            &C::DEFAULT_BCP_47_IDENTIFIER,
685
            &options,
686
        )?;
687
        Ok(Self(
688
            raw::DateTimeFormatter::try_new_unstable(
689
                provider,
690
                patterns,
691
                || calendar::load_symbols_for_cldr_calendar::<C, _>(provider, locale),
692
                locale,
693
            )?,
694
            PhantomData,
695
        ))
696
    }
697

698
    /// Takes a [`DateTimeInput`] implementer and returns an instance of a [`FormattedDateTime`]
699
    /// that contains all information necessary to display a formatted date and operate on it.
700
    ///
701
    /// # Examples
702
    ///
703
    /// ```
704
    /// use icu::calendar::{DateTime, Gregorian};
705
    /// use icu::datetime::TypedDateTimeFormatter;
706
    /// use writeable::assert_writeable_eq;
707
    /// use icu::locid::locale;
708
    /// # let options = icu::datetime::options::length::Bag::from_time_style(icu::datetime::options::length::Time::Medium);
709
    /// let dtf = TypedDateTimeFormatter::<Gregorian>::try_new(&locale!("en").into(), options.into())
710
    ///     .expect("Failed to create TypedDateTimeFormatter instance.");
711
    ///
712
    /// let datetime = DateTime::try_new_gregorian_datetime(2020, 9, 1, 12, 34, 28)
713
    ///     .expect("Failed to construct DateTime.");
714
    ///
715
    /// assert_writeable_eq!(dtf.format(&datetime), "12:34:28 PM");
716
    /// ```
717
    #[inline]
718
    pub fn format<'l, T>(&'l self, value: &T) -> FormattedDateTime<'l>
1✔
719
    where
720
        T: DateTimeInput<Calendar = C>,
721
    {
722
        self.0.format(value)
1✔
723
    }
1✔
724

725
    /// Takes a [`DateTimeInput`] implementer and returns it formatted as a string.
726
    ///
727
    /// # Examples
728
    ///
729
    /// ```
730
    /// use icu::calendar::{DateTime, Gregorian};
731
    /// use icu::datetime::TypedDateTimeFormatter;
732
    /// use icu::locid::locale;
733
    /// # let options = icu::datetime::options::length::Bag::from_time_style(icu::datetime::options::length::Time::Medium);
734
    /// let dtf = TypedDateTimeFormatter::<Gregorian>::try_new(&locale!("en").into(), options.into())
735
    ///     .expect("Failed to create TypedDateTimeFormatter instance.");
736
    ///
737
    /// let datetime = DateTime::try_new_gregorian_datetime(2020, 9, 1, 12, 34, 28)
738
    ///     .expect("Failed to construct DateTime.");
739
    ///
740
    /// assert_eq!(dtf.format_to_string(&datetime), "12:34:28 PM");
741
    /// ```
742
    #[inline]
743
    pub fn format_to_string(&self, value: &impl DateTimeInput<Calendar = C>) -> String {
1✔
744
        self.format(value).write_to_string().into_owned()
1✔
745
    }
1✔
746

747
    /// Returns a [`components::Bag`](crate::options::components::Bag) that represents the resolved components for the
748
    /// options that were provided to the [`TypedDateTimeFormatter`]. The developer may request
749
    /// a certain set of options for a [`TypedDateTimeFormatter`] but the locale and resolution
750
    /// algorithm may change certain details of what actually gets resolved.
751
    ///
752
    /// # Examples
753
    ///
754
    /// ```
755
    /// use icu::calendar::Gregorian;
756
    /// use icu::datetime::{
757
    ///     options::{components, length},
758
    ///     DateTimeFormatterOptions, TypedDateTimeFormatter,
759
    /// };
760
    /// use icu::locid::locale;
761
    ///
762
    /// let options = length::Bag::from_date_style(length::Date::Medium).into();
763
    /// let dtf = TypedDateTimeFormatter::<Gregorian>::try_new(
764
    ///     &locale!("en").into(),
765
    ///     options,
766
    /// )
767
    /// .expect("Failed to create TypedDateTimeFormatter instance.");
768
    ///
769
    /// let mut expected_components_bag = components::Bag::default();
770
    /// expected_components_bag.year = Some(components::Year::Numeric);
771
    /// expected_components_bag.month = Some(components::Month::Short);
772
    /// expected_components_bag.day = Some(components::Day::NumericDayOfMonth);
773
    ///
774
    /// assert_eq!(dtf.resolve_components(), expected_components_bag);
775
    /// ```
776
    #[cfg(feature = "experimental")]
777
    pub fn resolve_components(&self) -> crate::options::components::Bag {
778
        self.0.resolve_components()
779
    }
780
}
781

782
#[cfg(test)]
783
#[cfg(feature = "serde")]
784
mod tests {
785
    use super::*;
786
    use icu_calendar::DateTime;
787
    use icu_calendar::Gregorian;
788

789
    #[test]
790
    fn works_with_default_options() {
2✔
791
        assert_eq!(
1✔
792
            TypedDateTimeFormatter::<Gregorian>::try_new(Default::default(), Default::default(),)
2✔
793
                .unwrap()
794
                .format_to_string(
795
                    &DateTime::try_new_gregorian_datetime(2022, 9, 20, 0, 0, 0).unwrap()
1✔
796
                ),
797
            "2022 M09 20 00:00:00"
798
        );
799
    }
2✔
800
}
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