• 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

0.0
/components/datetime/src/zoned_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
use alloc::string::String;
6
use core::marker::PhantomData;
7
use icu_calendar::provider::WeekDataV1Marker;
8
use icu_decimal::provider::DecimalSymbolsV1Marker;
9
use icu_plurals::provider::OrdinalV1Marker;
10
use icu_provider::prelude::*;
11
use writeable::Writeable;
12

13
use crate::{
14
    calendar,
15
    format::zoned_datetime::FormattedZonedDateTime,
16
    input::{DateTimeInput, TimeZoneInput},
17
    options::DateTimeFormatterOptions,
18
    provider::{
19
        self,
20
        calendar::{TimeLengthsV1Marker, TimeSymbolsV1Marker},
21
        date_time::PatternSelector,
22
    },
23
    raw,
24
    time_zone::TimeZoneFormatterOptions,
25
    CldrCalendar, DateTimeError,
26
};
27

28
/// The composition of [`TypedDateTimeFormatter`](crate::TypedDateTimeFormatter) and [`TimeZoneFormatter`].
29
///
30
/// [`TypedZonedDateTimeFormatter`] is a formatter capable of formatting
31
/// date/times with time zones from a calendar selected at compile time. For the difference between this
32
/// and [`DateTimeFormatter`](crate::DateTimeFormatter), please read the [crate root docs][crate].
33
///
34
/// [`TypedZonedDateTimeFormatter`] uses data from the [data provider]s, the selected locale, and the
35
/// provided pattern to collect all data necessary to format a datetime with time zones into that locale.
36
///
37
/// The various pattern symbols specified in UTS-35 require different sets of data for formatting.
38
/// As such, [`TimeZoneFormatter`] will pull in only the resources it needs to format that pattern
39
/// that is derived from the provided [`DateTimeFormatterOptions`].
40
///
41
/// For that reason, one should think of the process of formatting a zoned datetime in two steps:
42
/// first, a computationally heavy construction of [`TypedZonedDateTimeFormatter`], and then fast formatting
43
/// of the data using the instance.
44
///
45
/// # Examples
46
///
47
/// ```
48
/// use icu::calendar::{DateTime, Gregorian};
49
/// use icu::datetime::time_zone::TimeZoneFormatterOptions;
50
/// use icu::datetime::{options::length, TypedZonedDateTimeFormatter};
51
/// use icu::locid::locale;
52
/// use icu::timezone::CustomTimeZone;
53
/// use std::str::FromStr;
54
/// use writeable::assert_writeable_eq;
55
///
56
/// let options = length::Bag::from_date_time_style(
57
///     length::Date::Medium,
58
///     length::Time::Long,
59
/// );
60
/// let zdtf = TypedZonedDateTimeFormatter::<Gregorian>::try_new(
61
///     &locale!("en").into(),
62
///     options.into(),
63
///     TimeZoneFormatterOptions::default(),
64
/// )
65
/// .expect("Failed to create TypedDateTimeFormatter instance.");
66
///
67
/// let datetime =
68
///     DateTime::try_new_gregorian_datetime(2020, 9, 12, 12, 34, 28).unwrap();
69
/// let time_zone = CustomTimeZone::from_str("-07:00").unwrap();
70
///
71
/// let formatted_date = zdtf.format(&datetime, &time_zone);
72
///
73
/// assert_writeable_eq!(formatted_date, "Sep 12, 2020, 12:34:28 PM GMT-07:00");
74
/// ```
75
///
76
/// [`TimeZoneFormatter`]: crate::time_zone::TimeZoneFormatter
77
#[derive(Debug)]
78
pub struct TypedZonedDateTimeFormatter<C>(raw::ZonedDateTimeFormatter, PhantomData<C>);
79

80
impl<C: CldrCalendar> TypedZonedDateTimeFormatter<C> {
81
    /// Constructor that takes a selected locale and a list of [`DateTimeFormatterOptions`].
82
    /// It collects all data necessary to format zoned datetime values into the given locale.
83
    ///
84
    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
85
    ///
86
    /// [📚 Help choosing a constructor](icu_provider::constructors)
87
    ///
88
    /// # Examples
89
    ///
90
    /// ```
91
    /// use icu::calendar::{DateTime, Gregorian};
92
    /// use icu::datetime::time_zone::TimeZoneFormatterOptions;
93
    /// use icu::datetime::{options::length, TypedZonedDateTimeFormatter};
94
    /// use icu::locid::locale;
95
    /// use icu::timezone::CustomTimeZone;
96
    /// use writeable::assert_writeable_eq;
97
    ///
98
    /// let options = length::Bag::from_date_time_style(
99
    ///     length::Date::Medium,
100
    ///     length::Time::Long,
101
    /// );
102
    ///
103
    /// let zdtf = TypedZonedDateTimeFormatter::<Gregorian>::try_new(
104
    ///     &locale!("en").into(),
105
    ///     options.into(),
106
    ///     TimeZoneFormatterOptions::default(),
107
    /// )
108
    /// .unwrap();
109
    ///
110
    /// let datetime =
111
    ///     DateTime::try_new_gregorian_datetime(2022, 8, 31, 1, 2, 3).unwrap();
112
    ///
113
    /// assert_writeable_eq!(
114
    ///     zdtf.format(&datetime, &CustomTimeZone::utc()),
115
    ///     "Aug 31, 2022, 1:02:03 AM GMT",
116
    /// );
117
    /// ```
118
    ///
119
    /// [data provider]: icu_provider
120
    #[inline]
121
    #[cfg(feature = "compiled_data")]
122
    pub fn try_new(
×
123
        locale: &DataLocale,
124
        date_time_format_options: DateTimeFormatterOptions,
125
        time_zone_format_options: TimeZoneFormatterOptions,
126
    ) -> Result<Self, DateTimeError>
127
    where
128
        crate::provider::Baked:
129
            DataProvider<C::DateLengthsV1Marker> + DataProvider<C::DateSymbolsV1Marker>,
130
    {
131
        let patterns = PatternSelector::for_options(
×
132
            &crate::provider::Baked,
133
            calendar::load_lengths_for_cldr_calendar::<C, _>(&crate::provider::Baked, locale)?,
×
134
            locale,
135
            &date_time_format_options,
136
        )?;
×
137
        Ok(Self(
×
138
            raw::ZonedDateTimeFormatter::try_new(
×
139
                patterns,
×
140
                || {
×
141
                    calendar::load_symbols_for_cldr_calendar::<C, _>(
×
142
                        &crate::provider::Baked,
143
                        locale,
×
144
                    )
145
                },
×
146
                locale,
147
                time_zone_format_options,
×
148
            )?,
×
149
            PhantomData,
150
        ))
151
    }
×
152

153
    icu_provider::gen_any_buffer_data_constructors!(
154
        locale: include,
155
        date_time_format_options: DateTimeFormatterOptions,
156
        time_zone_format_options: TimeZoneFormatterOptions,
157
        error: DateTimeError,
158
        #[cfg(skip)]
159
    );
160

161
    #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::try_new)]
162
    #[inline]
163
    pub fn try_new_unstable<P>(
×
164
        provider: &P,
165
        locale: &DataLocale,
166
        date_time_format_options: DateTimeFormatterOptions,
167
        time_zone_format_options: TimeZoneFormatterOptions,
168
    ) -> Result<Self, DateTimeError>
169
    where
170
        P: DataProvider<<C as CldrCalendar>::DateSymbolsV1Marker>
171
            + DataProvider<<C as CldrCalendar>::DateLengthsV1Marker>
172
            + DataProvider<TimeSymbolsV1Marker>
173
            + DataProvider<TimeLengthsV1Marker>
174
            + DataProvider<WeekDataV1Marker>
175
            + DataProvider<provider::time_zones::TimeZoneFormatsV1Marker>
176
            + DataProvider<provider::time_zones::ExemplarCitiesV1Marker>
177
            + DataProvider<provider::time_zones::MetazoneGenericNamesLongV1Marker>
178
            + DataProvider<provider::time_zones::MetazoneGenericNamesShortV1Marker>
179
            + DataProvider<provider::time_zones::MetazoneSpecificNamesLongV1Marker>
180
            + DataProvider<provider::time_zones::MetazoneSpecificNamesShortV1Marker>
181
            + DataProvider<OrdinalV1Marker>
182
            + DataProvider<DecimalSymbolsV1Marker>
183
            + ?Sized,
184
    {
185
        let patterns = PatternSelector::for_options(
×
186
            provider,
187
            calendar::load_lengths_for_cldr_calendar::<C, _>(provider, locale)?,
×
188
            locale,
189
            &date_time_format_options,
190
        )?;
×
191
        Ok(Self(
×
192
            raw::ZonedDateTimeFormatter::try_new_unstable(
×
193
                provider,
194
                patterns,
×
195
                || calendar::load_symbols_for_cldr_calendar::<C, _>(provider, locale),
×
196
                locale,
197
                time_zone_format_options,
×
198
            )?,
×
199
            PhantomData,
200
        ))
201
    }
×
202

203
    /// Constructor that takes a selected locale and a list of [`DateTimeFormatterOptions`].
204
    /// It collects all data necessary to format zoned datetime values into the given locale.
205
    ///
206
    /// ✨ *Enabled with the `compiled_data` and `experimental` Cargo features.*
207
    ///
208
    /// [📚 Help choosing a constructor](icu_provider::constructors)
209
    ///
210
    /// <div class="stab unstable">
211
    /// 🚧 This code is experimental; it may change at any time, in breaking or non-breaking ways,
212
    /// including in SemVer minor releases. It can be enabled with the "experimental" Cargo feature
213
    /// of the icu meta-crate. Use with caution.
214
    /// <a href="https://github.com/unicode-org/icu4x/issues/1317">#1317</a>
215
    /// </div>
216
    ///
217
    /// # Examples
218
    ///
219
    /// ```
220
    /// use icu::calendar::{DateTime, Gregorian};
221
    /// use icu::datetime::time_zone::TimeZoneFormatterOptions;
222
    /// use icu::datetime::{options::components, TypedZonedDateTimeFormatter};
223
    /// use icu::locid::locale;
224
    /// use icu::timezone::CustomTimeZone;
225
    /// use icu_provider::AsDeserializingBufferProvider;
226
    /// use writeable::assert_writeable_eq;
227
    ///
228
    /// let mut options = components::Bag::default();
229
    /// options.year = Some(components::Year::Numeric);
230
    /// options.month = Some(components::Month::Long);
231
    /// options.hour = Some(components::Numeric::Numeric);
232
    /// options.minute = Some(components::Numeric::Numeric);
233
    /// options.time_zone_name = Some(components::TimeZoneName::GmtOffset);
234
    ///
235
    /// let zdtf = TypedZonedDateTimeFormatter::<Gregorian>::try_new_experimental(
236
    ///     &locale!("en").into(),
237
    ///     options.into(),
238
    ///     TimeZoneFormatterOptions::default(),
239
    /// )
240
    /// .unwrap();
241
    ///
242
    /// let datetime =
243
    ///     DateTime::try_new_gregorian_datetime(2022, 8, 31, 1, 2, 3).unwrap();
244
    ///
245
    /// assert_writeable_eq!(
246
    ///     zdtf.format(&datetime, &CustomTimeZone::utc()),
247
    ///     "August 2022, 01:02 GMT",
248
    /// );
249
    /// ```
250
    ///
251
    /// [data provider]: icu_provider
252
    #[cfg(feature = "experimental")]
253
    #[cfg(feature = "compiled_data")]
254
    #[inline]
255
    pub fn try_new_experimental(
256
        locale: &DataLocale,
257
        date_time_format_options: DateTimeFormatterOptions,
258
        time_zone_format_options: TimeZoneFormatterOptions,
259
    ) -> Result<Self, DateTimeError>
260
    where
261
        crate::provider::Baked:
262
            DataProvider<C::DateLengthsV1Marker> + DataProvider<C::DateSymbolsV1Marker>,
263
    {
264
        let patterns = PatternSelector::for_options_experimental(
265
            &crate::provider::Baked,
266
            calendar::load_lengths_for_cldr_calendar::<C, _>(&crate::provider::Baked, locale)?,
267
            locale,
268
            &C::DEFAULT_BCP_47_IDENTIFIER,
269
            &date_time_format_options,
270
        )?;
271
        Ok(Self(
272
            raw::ZonedDateTimeFormatter::try_new(
273
                patterns,
274
                || {
275
                    calendar::load_symbols_for_cldr_calendar::<C, _>(
276
                        &crate::provider::Baked,
277
                        locale,
278
                    )
279
                },
280
                locale,
281
                time_zone_format_options,
282
            )?,
283
            PhantomData,
284
        ))
285
    }
286

287
    #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::try_new_experimental)]
288
    #[cfg(feature = "experimental")]
289
    #[inline]
290
    pub fn try_new_experimental_unstable<P>(
291
        provider: &P,
292
        locale: &DataLocale,
293
        date_time_format_options: DateTimeFormatterOptions,
294
        time_zone_format_options: TimeZoneFormatterOptions,
295
    ) -> Result<Self, DateTimeError>
296
    where
297
        P: DataProvider<<C as CldrCalendar>::DateSymbolsV1Marker>
298
            + DataProvider<<C as CldrCalendar>::DateLengthsV1Marker>
299
            + DataProvider<TimeSymbolsV1Marker>
300
            + DataProvider<TimeLengthsV1Marker>
301
            + DataProvider<crate::provider::calendar::DateSkeletonPatternsV1Marker>
302
            + DataProvider<WeekDataV1Marker>
303
            + DataProvider<provider::time_zones::TimeZoneFormatsV1Marker>
304
            + DataProvider<provider::time_zones::ExemplarCitiesV1Marker>
305
            + DataProvider<provider::time_zones::MetazoneGenericNamesLongV1Marker>
306
            + DataProvider<provider::time_zones::MetazoneGenericNamesShortV1Marker>
307
            + DataProvider<provider::time_zones::MetazoneSpecificNamesLongV1Marker>
308
            + DataProvider<provider::time_zones::MetazoneSpecificNamesShortV1Marker>
309
            + DataProvider<OrdinalV1Marker>
310
            + DataProvider<DecimalSymbolsV1Marker>
311
            + ?Sized,
312
    {
313
        let patterns = PatternSelector::for_options_experimental(
314
            provider,
315
            calendar::load_lengths_for_cldr_calendar::<C, _>(provider, locale)?,
316
            locale,
317
            &C::DEFAULT_BCP_47_IDENTIFIER,
318
            &date_time_format_options,
319
        )?;
320
        Ok(Self(
321
            raw::ZonedDateTimeFormatter::try_new_unstable(
322
                provider,
323
                patterns,
324
                || calendar::load_symbols_for_cldr_calendar::<C, _>(provider, locale),
325
                locale,
326
                time_zone_format_options,
327
            )?,
328
            PhantomData,
329
        ))
330
    }
331

332
    /// Takes a [`DateTimeInput`] and a [`TimeZoneInput`] and returns an instance of a [`FormattedZonedDateTime`]
333
    /// that contains all information necessary to display a formatted zoned datetime and operate on it.
334
    ///
335
    /// # Examples
336
    ///
337
    /// ```
338
    /// use icu::calendar::{DateTime, Gregorian};
339
    /// use icu::datetime::{options::length, TypedZonedDateTimeFormatter};
340
    /// use icu::locid::locale;
341
    /// use icu::timezone::CustomTimeZone;
342
    /// use std::str::FromStr;
343
    /// use writeable::assert_writeable_eq;
344
    ///
345
    /// let options = length::Bag::from_date_time_style(
346
    ///     length::Date::Medium,
347
    ///     length::Time::Long,
348
    /// );
349
    ///
350
    /// let zdtf = TypedZonedDateTimeFormatter::<Gregorian>::try_new(
351
    ///     &locale!("en").into(),
352
    ///     options.into(),
353
    ///     Default::default(),
354
    /// )
355
    /// .expect("Failed to create TypedZonedDateTimeFormatter instance.");
356
    ///
357
    /// let datetime =
358
    ///     DateTime::try_new_gregorian_datetime(2020, 9, 12, 12, 34, 28).unwrap();
359
    /// let time_zone = CustomTimeZone::from_str("-07:00").unwrap();
360
    ///
361
    /// let formatted_date = zdtf.format(&datetime, &time_zone);
362
    ///
363
    /// assert_writeable_eq!(formatted_date, "Sep 12, 2020, 12:34:28 PM GMT-07:00");
364
    /// ```
365
    #[inline]
366
    pub fn format<'l>(
×
367
        &'l self,
368
        date: &impl DateTimeInput<Calendar = C>,
369
        time_zone: &impl TimeZoneInput,
370
    ) -> FormattedZonedDateTime<'l> {
371
        self.0.format(date, time_zone)
×
372
    }
×
373

374
    /// Takes a [`DateTimeInput`] and a [`TimeZoneInput`] and returns it formatted as a string.
375
    ///
376
    /// # Examples
377
    ///
378
    /// ```
379
    /// use icu::calendar::{DateTime, Gregorian};
380
    /// use icu::datetime::{options::length, TypedZonedDateTimeFormatter};
381
    /// use icu::locid::locale;
382
    /// use icu::timezone::CustomTimeZone;
383
    /// use std::str::FromStr;
384
    ///
385
    /// let options = length::Bag::from_date_time_style(
386
    ///     length::Date::Medium,
387
    ///     length::Time::Long,
388
    /// );
389
    ///
390
    /// let zdtf = TypedZonedDateTimeFormatter::<Gregorian>::try_new(
391
    ///     &locale!("en").into(),
392
    ///     options.into(),
393
    ///     Default::default(),
394
    /// )
395
    /// .expect("Failed to create TypedZonedDateTimeFormatter instance.");
396
    ///
397
    /// let datetime =
398
    ///     DateTime::try_new_gregorian_datetime(2020, 9, 12, 12, 34, 28).unwrap();
399
    /// let time_zone = CustomTimeZone::from_str("-07:00").unwrap();
400
    ///
401
    /// let formatted_string = zdtf.format_to_string(&datetime, &time_zone);
402
    ///
403
    /// assert_eq!(formatted_string, "Sep 12, 2020, 12:34:28 PM GMT-07:00");
404
    /// ```
405
    #[inline]
406
    pub fn format_to_string(
407
        &self,
408
        date: &impl DateTimeInput<Calendar = C>,
409
        time_zone: &impl TimeZoneInput,
410
    ) -> String {
411
        self.format(date, time_zone).write_to_string().into_owned()
412
    }
413
}
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

© 2025 Coveralls, Inc