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

zbraniecki / icu4x / 9457158389

10 Jun 2024 11:45PM UTC coverage: 75.174% (+0.05%) from 75.121%
9457158389

push

github

web-flow
Add constructing TinyAsciiStr from utf16 (#5025)

Introduces TinyAsciiStr constructors from utf16 and converges on the
consensus from #4931.

---------

Co-authored-by: Robert Bastian <4706271+robertbastian@users.noreply.github.com>

65 of 82 new or added lines in 14 files covered. (79.27%)

3441 existing lines in 141 files now uncovered.

52850 of 70304 relevant lines covered (75.17%)

563298.06 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::provider::date_time::PatternForLengthError;
14
#[cfg(feature = "experimental")]
15
use crate::provider::date_time::UnsupportedOptionsOrDataOrPatternError;
16
use crate::{
17
    calendar,
18
    calendar::CldrCalendar,
19
    format::zoned_datetime::FormattedZonedDateTime,
20
    input::{DateTimeInput, TimeZoneInput},
21
    options::DateTimeFormatterOptions,
22
    provider::{
23
        self,
24
        calendar::{TimeLengthsV1Marker, TimeSymbolsV1Marker},
25
        date_time::PatternSelector,
26
    },
27
    raw,
28
    time_zone::TimeZoneFormatterOptions,
29
    DateTimeError,
30
};
31

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

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

161
    icu_provider::gen_any_buffer_data_constructors!(
162
        locale: include,
163
        date_time_format_options: DateTimeFormatterOptions,
164
        time_zone_format_options: TimeZoneFormatterOptions,
165
        error: DateTimeError,
166
        #[cfg(skip)]
167
    );
168

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

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

305
    #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::try_new_experimental)]
306
    #[cfg(feature = "experimental")]
307
    #[inline]
308
    pub fn try_new_experimental_unstable<P>(
309
        provider: &P,
310
        locale: &DataLocale,
311
        date_time_format_options: DateTimeFormatterOptions,
312
        time_zone_format_options: TimeZoneFormatterOptions,
313
    ) -> Result<Self, DateTimeError>
314
    where
315
        P: DataProvider<<C as CldrCalendar>::DateSymbolsV1Marker>
316
            + DataProvider<<C as CldrCalendar>::DateLengthsV1Marker>
317
            + DataProvider<TimeSymbolsV1Marker>
318
            + DataProvider<TimeLengthsV1Marker>
319
            + DataProvider<crate::provider::calendar::DateSkeletonPatternsV1Marker>
320
            + DataProvider<WeekDataV1Marker>
321
            + DataProvider<provider::time_zones::TimeZoneFormatsV1Marker>
322
            + DataProvider<provider::time_zones::ExemplarCitiesV1Marker>
323
            + DataProvider<provider::time_zones::MetazoneGenericNamesLongV1Marker>
324
            + DataProvider<provider::time_zones::MetazoneGenericNamesShortV1Marker>
325
            + DataProvider<provider::time_zones::MetazoneSpecificNamesLongV1Marker>
326
            + DataProvider<provider::time_zones::MetazoneSpecificNamesShortV1Marker>
327
            + DataProvider<OrdinalV1Marker>
328
            + DataProvider<DecimalSymbolsV1Marker>
329
            + ?Sized,
330
    {
331
        let patterns = PatternSelector::for_options_experimental(
332
            provider,
333
            calendar::load_lengths_for_cldr_calendar::<C, _>(provider, locale)?,
334
            locale,
335
            &C::DEFAULT_BCP_47_IDENTIFIER,
336
            &date_time_format_options,
337
        )
338
        .map_err(|e| match e {
339
            UnsupportedOptionsOrDataOrPatternError::UnsupportedOptions => {
340
                DateTimeError::UnsupportedOptions
341
            }
342
            UnsupportedOptionsOrDataOrPatternError::Data(e) => DateTimeError::Data(e),
343
            UnsupportedOptionsOrDataOrPatternError::Pattern(e) => DateTimeError::Pattern(e),
344
        })?;
345
        Ok(Self(
346
            raw::ZonedDateTimeFormatter::try_new_unstable(
347
                provider,
348
                patterns,
349
                || calendar::load_symbols_for_cldr_calendar::<C, _>(provider, locale),
350
                locale,
351
                time_zone_format_options,
352
            )?,
353
            PhantomData,
354
        ))
355
    }
356

357
    /// Takes a [`DateTimeInput`] and a [`TimeZoneInput`] and returns an instance of a [`FormattedZonedDateTime`]
358
    /// that contains all information necessary to display a formatted zoned datetime and operate on it.
359
    ///
360
    /// # Examples
361
    ///
362
    /// ```
363
    /// use icu::calendar::{DateTime, Gregorian};
364
    /// use icu::datetime::{options::length, TypedZonedDateTimeFormatter};
365
    /// use icu::locale::locale;
366
    /// use icu::timezone::CustomTimeZone;
367
    /// use std::str::FromStr;
368
    /// use writeable::assert_writeable_eq;
369
    ///
370
    /// let options = length::Bag::from_date_time_style(
371
    ///     length::Date::Medium,
372
    ///     length::Time::Long,
373
    /// );
374
    ///
375
    /// let zdtf = TypedZonedDateTimeFormatter::<Gregorian>::try_new(
376
    ///     &locale!("en").into(),
377
    ///     options.into(),
378
    ///     Default::default(),
379
    /// )
380
    /// .expect("Failed to create TypedZonedDateTimeFormatter instance.");
381
    ///
382
    /// let datetime =
383
    ///     DateTime::try_new_gregorian_datetime(2020, 9, 12, 12, 34, 28).unwrap();
384
    /// let time_zone = CustomTimeZone::from_str("-07:00").unwrap();
385
    ///
386
    /// let formatted_date = zdtf.format(&datetime, &time_zone);
387
    ///
388
    /// assert_writeable_eq!(formatted_date, "Sep 12, 2020, 12:34:28 PM GMT-07:00");
389
    /// ```
390
    #[inline]
391
    pub fn format<'l>(
×
392
        &'l self,
393
        date: &impl DateTimeInput<Calendar = C>,
394
        time_zone: &impl TimeZoneInput,
395
    ) -> FormattedZonedDateTime<'l> {
396
        self.0.format(date, time_zone)
×
397
    }
×
398

399
    /// Takes a [`DateTimeInput`] and a [`TimeZoneInput`] and returns it formatted as a string.
400
    ///
401
    /// # Examples
402
    ///
403
    /// ```
404
    /// use icu::calendar::{DateTime, Gregorian};
405
    /// use icu::datetime::{options::length, TypedZonedDateTimeFormatter};
406
    /// use icu::locale::locale;
407
    /// use icu::timezone::CustomTimeZone;
408
    /// use std::str::FromStr;
409
    ///
410
    /// let options = length::Bag::from_date_time_style(
411
    ///     length::Date::Medium,
412
    ///     length::Time::Long,
413
    /// );
414
    ///
415
    /// let zdtf = TypedZonedDateTimeFormatter::<Gregorian>::try_new(
416
    ///     &locale!("en").into(),
417
    ///     options.into(),
418
    ///     Default::default(),
419
    /// )
420
    /// .expect("Failed to create TypedZonedDateTimeFormatter instance.");
421
    ///
422
    /// let datetime =
423
    ///     DateTime::try_new_gregorian_datetime(2020, 9, 12, 12, 34, 28).unwrap();
424
    /// let time_zone = CustomTimeZone::from_str("-07:00").unwrap();
425
    ///
426
    /// let formatted_string = zdtf.format_to_string(&datetime, &time_zone);
427
    ///
428
    /// assert_eq!(formatted_string, "Sep 12, 2020, 12:34:28 PM GMT-07:00");
429
    /// ```
430
    #[inline]
431
    pub fn format_to_string(
432
        &self,
433
        date: &impl DateTimeInput<Calendar = C>,
434
        time_zone: &impl TimeZoneInput,
435
    ) -> String {
436
        self.format(date, time_zone).write_to_string().into_owned()
437
    }
438
}
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