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

zbraniecki / icu4x / 8219362155

08 Mar 2024 01:21PM UTC coverage: 75.985% (+3.0%) from 73.009%
8219362155

push

github

web-flow
Bump diplomat (#4671)

And fix some Dart renames

49581 of 65251 relevant lines covered (75.99%)

519628.46 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
    calendar::CldrCalendar,
16
    format::zoned_datetime::FormattedZonedDateTime,
17
    input::{DateTimeInput, TimeZoneInput},
18
    options::DateTimeFormatterOptions,
19
    provider::{
20
        self,
21
        calendar::{TimeLengthsV1Marker, TimeSymbolsV1Marker},
22
        date_time::PatternSelector,
23
    },
24
    raw,
25
    time_zone::TimeZoneFormatterOptions,
26
    DateTimeError,
27
};
28

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

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

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

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

204
    /// Constructor that takes a selected locale and a list of [`DateTimeFormatterOptions`].
205
    /// It collects all data necessary to format zoned datetime values into the given locale.
206
    ///
207
    /// ✨ *Enabled with the `compiled_data` and `experimental` Cargo features.*
208
    ///
209
    /// [📚 Help choosing a constructor](icu_provider::constructors)
210
    ///
211
    /// <div class="stab unstable">
212
    /// 🚧 This code is experimental; it may change at any time, in breaking or non-breaking ways,
213
    /// including in SemVer minor releases. It can be enabled with the "experimental" Cargo feature
214
    /// of the icu meta-crate. Use with caution.
215
    /// <a href="https://github.com/unicode-org/icu4x/issues/1317">#1317</a>
216
    /// </div>
217
    ///
218
    /// # Examples
219
    ///
220
    /// ```
221
    /// use icu::calendar::{DateTime, Gregorian};
222
    /// use icu::datetime::time_zone::TimeZoneFormatterOptions;
223
    /// use icu::datetime::{options::components, TypedZonedDateTimeFormatter};
224
    /// use icu::locid::locale;
225
    /// use icu::timezone::CustomTimeZone;
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