• 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

83.84
/components/datetime/src/any/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 crate::{calendar, options::DateTimeFormatterOptions, raw};
6
use alloc::string::String;
7

8
use icu_provider::prelude::*;
9

10
use crate::input::{DateTimeInput, ExtractedDateTimeInput, TimeZoneInput};
11
use crate::provider::{self, calendar::*, date_time::PatternSelector};
12
use crate::time_zone::TimeZoneFormatterOptions;
13
use crate::{DateTimeError, FormattedZonedDateTime};
14
use icu_calendar::any_calendar::{AnyCalendar, AnyCalendarKind};
15
use icu_calendar::provider::{
16
    JapaneseErasV1Marker, JapaneseExtendedErasV1Marker, WeekDataV1Marker,
17
};
18
use icu_calendar::{types::Time, DateTime};
19
use icu_decimal::provider::DecimalSymbolsV1Marker;
20
use icu_plurals::provider::OrdinalV1Marker;
21
use writeable::Writeable;
22

23
/// [`ZonedDateTimeFormatter`] is a formatter capable of formatting
24
/// date/times with time zones from any calendar, selected at runtime. For the difference between this and [`TypedZonedDateTimeFormatter`](crate::TypedZonedDateTimeFormatter),
25
/// please read the [crate root docs][crate].
26
///
27
/// This is equivalently the composition of
28
/// [`DateTimeFormatter`](crate::DateTimeFormatter) and [`TimeZoneFormatter`].
29
///
30
/// [`ZonedDateTimeFormatter`] uses data from the [data provider]s, the selected [`DataLocale`], and the
31
/// provided pattern to collect all data necessary to format a datetime with time zones into that locale.
32
///
33
/// The various pattern symbols specified in UTS-35 require different sets of data for formatting.
34
/// As such, `TimeZoneFormatter` will pull in only the resources it needs to format that pattern
35
/// that is derived from the provided [`DateTimeFormatterOptions`].
36
///
37
/// For that reason, one should think of the process of formatting a zoned datetime in two steps:
38
/// first, a computationally heavy construction of [`ZonedDateTimeFormatter`], and then fast formatting
39
/// of the data using the instance.
40
///
41
/// # Examples
42
///
43
/// Using a GMT time zone:
44
///
45
/// ```
46
/// use icu::calendar::{DateTime, Gregorian};
47
/// use icu::datetime::{options::length, ZonedDateTimeFormatter};
48
/// use icu::locid::locale;
49
/// use icu::timezone::CustomTimeZone;
50
/// use writeable::assert_writeable_eq;
51
///
52
/// let options = length::Bag::from_date_time_style(
53
///     length::Date::Medium,
54
///     length::Time::Long,
55
/// );
56
/// let zdtf = ZonedDateTimeFormatter::try_new(
57
///     &locale!("en").into(),
58
///     options.into(),
59
///     Default::default(),
60
/// )
61
/// .expect("Failed to create ZonedDateTimeFormatter instance.");
62
///
63
/// let datetime = DateTime::try_new_iso_datetime(2020, 9, 1, 12, 34, 28)
64
///     .expect("Failed to construct DateTime.");
65
/// let any_datetime = datetime.to_any();
66
///
67
/// let time_zone = CustomTimeZone::utc();
68
///
69
/// assert_writeable_eq!(
70
///     zdtf.format(&any_datetime, &time_zone)
71
///         .expect("Calendars should match"),
72
///     "Sep 1, 2020, 12:34:28 PM GMT"
73
/// );
74
/// ```
75
///
76
/// Using a non-GMT time zone, specified by id:
77
///
78
/// ```
79
/// use icu::calendar::{DateTime, Gregorian};
80
/// use icu::datetime::{options::length, ZonedDateTimeFormatter};
81
/// use icu::locid::locale;
82
/// use icu::timezone::{CustomTimeZone, GmtOffset, MetazoneCalculator, ZoneVariant};
83
/// use tinystr::TinyAsciiStr;
84
/// use writeable::assert_writeable_eq;
85
///
86
/// let options = length::Bag::from_date_time_style(
87
///     length::Date::Medium,
88
///     length::Time::Full,
89
/// );
90
/// let zdtf = ZonedDateTimeFormatter::try_new(
91
///     &locale!("en").into(),
92
///     options.into(),
93
///     Default::default(),
94
/// )
95
/// .expect("Failed to create ZonedDateTimeFormatter instance.");
96
///
97
/// // Create a DateTime at September 1, 2020 at 12:34:28 PM
98
/// let datetime = DateTime::try_new_iso_datetime(2020, 9, 1, 12, 34, 28)
99
///     .expect("Failed to construct DateTime.");
100
/// let any_datetime = datetime.to_any();
101
///
102
/// // Create a time zone for America/Chicago at GMT-6:
103
/// let mut time_zone = CustomTimeZone::new_empty();
104
/// time_zone.gmt_offset = "-06:00".parse::<GmtOffset>().ok();
105
/// time_zone.time_zone_id = "uschi".parse::<TinyAsciiStr<8>>().ok().map(Into::into);
106
/// time_zone.zone_variant = Some(ZoneVariant::daylight());
107
///
108
/// // Compute the metazone during `datetime` (September 1, 2020 at 12:34:28 PM):
109
/// let mzc = MetazoneCalculator::new();
110
/// time_zone.maybe_calculate_metazone(&mzc, &datetime);
111
///
112
/// assert_writeable_eq!(
113
///     zdtf
114
///       .format(&any_datetime, &time_zone)
115
///       .expect("Calendars should match"),
116
///     "Sep 1, 2020, 12:34:28 PM Central Daylight Time");
117
/// ```
118
///
119
/// [`TimeZoneFormatter`]: crate::time_zone::TimeZoneFormatter
120
#[derive(Debug)]
×
121
pub struct ZonedDateTimeFormatter(raw::ZonedDateTimeFormatter, AnyCalendar);
×
122

123
impl ZonedDateTimeFormatter {
124
    /// Constructor that takes a selected [`DataLocale`] and a list of [`DateTimeFormatterOptions`] and uses compiled data.
125
    /// It collects all data necessary to format zoned datetime values into the given locale.
126
    ///
127
    /// This method will pick the calendar off of the locale; and if unspecified or unknown will fall back to the default
128
    /// calendar for the locale. See [`AnyCalendarKind`] for a list of supported calendars.
129
    ///
130
    /// ✨ *Enabled with the `compiled_data` and `experimental` Cargo features.*
131
    ///
132
    /// [📚 Help choosing a constructor](icu_provider::constructors)
133
    ///
134
    /// <div class="stab unstable">
135
    /// 🚧 This code is experimental; it may change at any time, in breaking or non-breaking ways,
136
    /// including in SemVer minor releases. It can be enabled with the "experimental" Cargo feature
137
    /// of the icu meta-crate. Use with caution.
138
    /// <a href="https://github.com/unicode-org/icu4x/issues/1317">#1317</a>
139
    /// </div>
140
    ///
141
    /// # Examples
142
    ///
143
    /// ```
144
    /// use icu::calendar::{DateTime, Gregorian};
145
    /// use icu::datetime::options::components;
146
    /// use icu::datetime::{DateTimeFormatterOptions, ZonedDateTimeFormatter};
147
    /// use icu::locid::locale;
148
    /// use icu::timezone::CustomTimeZone;
149
    /// use icu_provider::AsDeserializingBufferProvider;
150
    /// use std::str::FromStr;
151
    /// use writeable::assert_writeable_eq;
152
    ///
153
    /// let mut options = components::Bag::default();
154
    /// options.year = Some(components::Year::Numeric);
155
    /// options.month = Some(components::Month::Long);
156
    /// options.hour = Some(components::Numeric::Numeric);
157
    /// options.minute = Some(components::Numeric::Numeric);
158
    /// options.time_zone_name = Some(components::TimeZoneName::GmtOffset);
159
    ///
160
    /// let zdtf = ZonedDateTimeFormatter::try_new_experimental(
161
    ///     &locale!("en-u-ca-gregory").into(),
162
    ///     options.into(),
163
    ///     Default::default(),
164
    /// )
165
    /// .expect("Construction should succeed");
166
    ///
167
    /// let datetime =
168
    ///     DateTime::try_new_iso_datetime(2021, 04, 08, 16, 12, 37).unwrap();
169
    /// let time_zone = CustomTimeZone::from_str("-07:00").unwrap();
170
    /// let any_datetime = datetime.to_any();
171
    ///
172
    /// assert_writeable_eq!(
173
    ///     zdtf.format(&any_datetime, &time_zone).unwrap(),
174
    ///     "April 2021, 16:12 GMT-07:00"
175
    /// );
176
    /// ```
177
    #[cfg(feature = "experimental")]
178
    #[cfg(feature = "compiled_data")]
179
    pub fn try_new_experimental(
1✔
180
        locale: &DataLocale,
181
        date_time_format_options: DateTimeFormatterOptions,
182
        time_zone_format_options: TimeZoneFormatterOptions,
183
    ) -> Result<Self, DateTimeError> {
184
        let calendar = AnyCalendar::new_for_locale(locale);
1✔
185
        let kind = calendar.kind();
1✔
186

187
        let patterns = PatternSelector::for_options_experimental(
1✔
188
            &crate::provider::Baked,
189
            calendar::load_lengths_for_any_calendar_kind(&crate::provider::Baked, locale, kind)?,
1✔
190
            locale,
191
            &kind.as_bcp47_value(),
1✔
192
            &date_time_format_options,
193
        )?;
1✔
194

195
        Ok(Self(
1✔
196
            raw::ZonedDateTimeFormatter::try_new(
1✔
197
                patterns,
1✔
198
                || {
2✔
199
                    calendar::load_symbols_for_any_calendar_kind(
1✔
200
                        &crate::provider::Baked,
201
                        locale,
1✔
202
                        kind,
1✔
203
                    )
204
                },
1✔
205
                locale,
206
                time_zone_format_options,
1✔
207
            )?,
×
208
            calendar,
1✔
209
        ))
210
    }
1✔
211

212
    #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::try_new_experimental)]
213
    #[cfg(feature = "experimental")]
214
    #[inline]
215
    #[allow(clippy::too_many_arguments)]
216
    pub fn try_new_experimental_unstable<P>(
217
        provider: &P,
218
        locale: &DataLocale,
219
        date_time_format_options: DateTimeFormatterOptions,
220
        time_zone_format_options: TimeZoneFormatterOptions,
221
    ) -> Result<Self, DateTimeError>
222
    where
223
        P: DataProvider<TimeSymbolsV1Marker>
224
            + DataProvider<TimeLengthsV1Marker>
225
            + DataProvider<crate::provider::calendar::DateSkeletonPatternsV1Marker>
226
            + DataProvider<WeekDataV1Marker>
227
            + DataProvider<provider::time_zones::TimeZoneFormatsV1Marker>
228
            + DataProvider<provider::time_zones::ExemplarCitiesV1Marker>
229
            + DataProvider<provider::time_zones::MetazoneGenericNamesLongV1Marker>
230
            + DataProvider<provider::time_zones::MetazoneGenericNamesShortV1Marker>
231
            + DataProvider<provider::time_zones::MetazoneSpecificNamesLongV1Marker>
232
            + DataProvider<provider::time_zones::MetazoneSpecificNamesShortV1Marker>
233
            + DataProvider<OrdinalV1Marker>
234
            + DataProvider<DecimalSymbolsV1Marker>
235
            + DataProvider<BuddhistDateLengthsV1Marker>
236
            + DataProvider<BuddhistDateSymbolsV1Marker>
237
            + DataProvider<ChineseDateLengthsV1Marker>
238
            + DataProvider<ChineseDateSymbolsV1Marker>
239
            + DataProvider<CopticDateLengthsV1Marker>
240
            + DataProvider<CopticDateSymbolsV1Marker>
241
            + DataProvider<DangiDateLengthsV1Marker>
242
            + DataProvider<DangiDateSymbolsV1Marker>
243
            + DataProvider<EthiopianDateLengthsV1Marker>
244
            + DataProvider<EthiopianDateSymbolsV1Marker>
245
            + DataProvider<GregorianDateLengthsV1Marker>
246
            + DataProvider<GregorianDateSymbolsV1Marker>
247
            + DataProvider<HebrewDateLengthsV1Marker>
248
            + DataProvider<HebrewDateSymbolsV1Marker>
249
            + DataProvider<IndianDateLengthsV1Marker>
250
            + DataProvider<IndianDateSymbolsV1Marker>
251
            + DataProvider<IslamicDateLengthsV1Marker>
252
            + DataProvider<IslamicDateSymbolsV1Marker>
253
            + DataProvider<JapaneseDateLengthsV1Marker>
254
            + DataProvider<JapaneseDateSymbolsV1Marker>
255
            + DataProvider<JapaneseErasV1Marker>
256
            + DataProvider<JapaneseExtendedDateLengthsV1Marker>
257
            + DataProvider<JapaneseExtendedDateSymbolsV1Marker>
258
            + DataProvider<JapaneseExtendedErasV1Marker>
259
            + DataProvider<PersianDateLengthsV1Marker>
260
            + DataProvider<PersianDateSymbolsV1Marker>
261
            + DataProvider<RocDateLengthsV1Marker>
262
            + DataProvider<RocDateSymbolsV1Marker>
263
            + ?Sized,
264
    {
265
        let calendar = AnyCalendar::try_new_for_locale_unstable(provider, locale)?;
266
        let kind = calendar.kind();
267

268
        let patterns = PatternSelector::for_options_experimental(
269
            provider,
270
            calendar::load_lengths_for_any_calendar_kind(provider, locale, kind)?,
271
            locale,
272
            &kind.as_bcp47_value(),
273
            &date_time_format_options,
274
        )?;
275

276
        Ok(Self(
277
            raw::ZonedDateTimeFormatter::try_new_unstable(
278
                provider,
279
                patterns,
280
                || calendar::load_symbols_for_any_calendar_kind(provider, locale, kind),
281
                locale,
282
                time_zone_format_options,
283
            )?,
284
            calendar,
285
        ))
286
    }
287

288
    /// Constructor that takes a selected [`DataLocale`] and a list of [`DateTimeFormatterOptions`] and uses compiled data.
289
    /// It collects all data necessary to format zoned datetime values into the given locale.
290
    ///
291
    /// This method will pick the calendar off of the locale; and if unspecified or unknown will fall back to the default
292
    /// calendar for the locale. See [`AnyCalendarKind`] for a list of supported calendars.
293
    ///
294
    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
295
    ///
296
    /// [📚 Help choosing a constructor](icu_provider::constructors)
297
    ///
298
    /// # Examples
299
    ///
300
    /// ```
301
    /// use icu::calendar::{DateTime, Gregorian};
302
    /// use icu::datetime::options::length;
303
    /// use icu::datetime::time_zone::TimeZoneFormatterOptions;
304
    /// use icu::datetime::{DateTimeFormatterOptions, ZonedDateTimeFormatter};
305
    /// use icu::locid::locale;
306
    /// use icu::timezone::CustomTimeZone;
307
    /// use std::str::FromStr;
308
    /// use writeable::assert_writeable_eq;
309
    ///
310
    /// let options = length::Bag::from_date_time_style(
311
    ///     length::Date::Medium,
312
    ///     length::Time::Long,
313
    /// );
314
    /// let locale = locale!("en-u-ca-gregory");
315
    ///
316
    /// let zdtf = ZonedDateTimeFormatter::try_new(
317
    ///     &locale.into(),
318
    ///     options.into(),
319
    ///     TimeZoneFormatterOptions::default(),
320
    /// )
321
    /// .expect("Construction should succeed");
322
    ///
323
    /// let datetime =
324
    ///     DateTime::try_new_iso_datetime(2021, 04, 08, 16, 12, 37).unwrap();
325
    /// let time_zone = CustomTimeZone::from_str("-07:00").unwrap();
326
    /// let any_datetime = datetime.to_any();
327
    ///
328
    /// assert_writeable_eq!(
329
    ///     zdtf.format(&any_datetime, &time_zone).unwrap(),
330
    ///     "Apr 8, 2021, 4:12:37 PM GMT-07:00"
331
    /// );
332
    /// ```
333
    #[cfg(feature = "compiled_data")]
334
    pub fn try_new(
3✔
335
        locale: &DataLocale,
336
        date_time_format_options: DateTimeFormatterOptions,
337
        time_zone_format_options: TimeZoneFormatterOptions,
338
    ) -> Result<Self, DateTimeError> {
339
        let calendar = AnyCalendar::new_for_locale(locale);
3✔
340
        let kind = calendar.kind();
3✔
341

342
        let patterns = PatternSelector::for_options(
3✔
343
            &crate::provider::Baked,
344
            calendar::load_lengths_for_any_calendar_kind(&crate::provider::Baked, locale, kind)?,
3✔
345
            locale,
346
            &date_time_format_options,
347
        )?;
×
348

349
        Ok(Self(
3✔
350
            raw::ZonedDateTimeFormatter::try_new(
3✔
351
                patterns,
3✔
352
                || {
6✔
353
                    calendar::load_symbols_for_any_calendar_kind(
3✔
354
                        &crate::provider::Baked,
355
                        locale,
3✔
356
                        kind,
3✔
357
                    )
358
                },
3✔
359
                locale,
360
                time_zone_format_options,
3✔
361
            )?,
×
362
            calendar,
3✔
363
        ))
364
    }
3✔
365

366
    #[inline]
367
    #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::try_new)]
368
    #[allow(clippy::too_many_arguments)]
369
    pub fn try_new_unstable<P>(
1✔
370
        provider: &P,
371
        locale: &DataLocale,
372
        date_time_format_options: DateTimeFormatterOptions,
373
        time_zone_format_options: TimeZoneFormatterOptions,
374
    ) -> Result<Self, DateTimeError>
375
    where
376
        P: DataProvider<TimeSymbolsV1Marker>
377
            + DataProvider<TimeLengthsV1Marker>
378
            + DataProvider<WeekDataV1Marker>
379
            + DataProvider<provider::time_zones::TimeZoneFormatsV1Marker>
380
            + DataProvider<provider::time_zones::ExemplarCitiesV1Marker>
381
            + DataProvider<provider::time_zones::MetazoneGenericNamesLongV1Marker>
382
            + DataProvider<provider::time_zones::MetazoneGenericNamesShortV1Marker>
383
            + DataProvider<provider::time_zones::MetazoneSpecificNamesLongV1Marker>
384
            + DataProvider<provider::time_zones::MetazoneSpecificNamesShortV1Marker>
385
            + DataProvider<OrdinalV1Marker>
386
            + DataProvider<DecimalSymbolsV1Marker>
387
            + DataProvider<BuddhistDateLengthsV1Marker>
388
            + DataProvider<BuddhistDateSymbolsV1Marker>
389
            + DataProvider<ChineseDateLengthsV1Marker>
390
            + DataProvider<ChineseDateSymbolsV1Marker>
391
            + DataProvider<CopticDateLengthsV1Marker>
392
            + DataProvider<CopticDateSymbolsV1Marker>
393
            + DataProvider<DangiDateLengthsV1Marker>
394
            + DataProvider<DangiDateSymbolsV1Marker>
395
            + DataProvider<EthiopianDateLengthsV1Marker>
396
            + DataProvider<EthiopianDateSymbolsV1Marker>
397
            + DataProvider<GregorianDateLengthsV1Marker>
398
            + DataProvider<GregorianDateSymbolsV1Marker>
399
            + DataProvider<HebrewDateLengthsV1Marker>
400
            + DataProvider<HebrewDateSymbolsV1Marker>
401
            + DataProvider<IndianDateLengthsV1Marker>
402
            + DataProvider<IndianDateSymbolsV1Marker>
403
            + DataProvider<IslamicDateLengthsV1Marker>
404
            + DataProvider<IslamicDateSymbolsV1Marker>
405
            + DataProvider<JapaneseDateLengthsV1Marker>
406
            + DataProvider<JapaneseDateSymbolsV1Marker>
407
            + DataProvider<JapaneseErasV1Marker>
408
            + DataProvider<JapaneseExtendedDateLengthsV1Marker>
409
            + DataProvider<JapaneseExtendedDateSymbolsV1Marker>
410
            + DataProvider<JapaneseExtendedErasV1Marker>
411
            + DataProvider<PersianDateLengthsV1Marker>
412
            + DataProvider<PersianDateSymbolsV1Marker>
413
            + DataProvider<RocDateLengthsV1Marker>
414
            + DataProvider<RocDateSymbolsV1Marker>
415
            + ?Sized,
416
    {
417
        let calendar = AnyCalendar::try_new_for_locale_unstable(provider, locale)?;
1✔
418
        let kind = calendar.kind();
1✔
419

420
        let patterns = PatternSelector::for_options(
1✔
421
            provider,
422
            calendar::load_lengths_for_any_calendar_kind(provider, locale, kind)?,
1✔
423
            locale,
424
            &date_time_format_options,
425
        )?;
×
426

427
        Ok(Self(
1✔
428
            raw::ZonedDateTimeFormatter::try_new_unstable(
1✔
429
                provider,
430
                patterns,
1✔
431
                || calendar::load_symbols_for_any_calendar_kind(provider, locale, kind),
2✔
432
                locale,
433
                time_zone_format_options,
1✔
434
            )?,
×
435
            calendar,
1✔
436
        ))
437
    }
1✔
438

439
    #[doc = icu_provider::gen_any_buffer_unstable_docs!(ANY, Self::try_new)]
440
    #[inline]
441
    pub fn try_new_with_any_provider(
×
442
        provider: &impl AnyProvider,
443
        locale: &DataLocale,
444
        options: DateTimeFormatterOptions,
445
        time_zone_format_options: TimeZoneFormatterOptions,
446
    ) -> Result<Self, DateTimeError> {
447
        let downcasting = provider.as_downcasting();
×
448
        Self::try_new_unstable(&downcasting, locale, options, time_zone_format_options)
×
449
    }
×
450

451
    #[doc = icu_provider::gen_any_buffer_unstable_docs!(BUFFER, Self::try_new)]
452
    #[inline]
453
    #[cfg(feature = "serde")]
454
    pub fn try_new_with_buffer_provider(
1✔
455
        provider: &impl BufferProvider,
456
        locale: &DataLocale,
457
        options: DateTimeFormatterOptions,
458
        time_zone_format_options: TimeZoneFormatterOptions,
459
    ) -> Result<Self, DateTimeError> {
460
        let deserializing = provider.as_deserializing();
1✔
461
        Self::try_new_unstable(&deserializing, locale, options, time_zone_format_options)
1✔
462
    }
1✔
463

464
    /// Takes a [`DateTimeInput`] and a [`TimeZoneInput`] and returns an instance of a [`FormattedZonedDateTime`]
465
    /// that contains all information necessary to display a formatted date and operate on it.
466
    ///
467
    /// This function will fail if the date passed in uses a different calendar than that of the
468
    /// AnyCalendar. Please convert dates before passing them in if necessary. This function
469
    /// will automatically convert and format dates that are associated with the ISO calendar.
470
    #[inline]
471
    pub fn format<'l>(
1✔
472
        &'l self,
473
        date: &impl DateTimeInput<Calendar = AnyCalendar>,
474
        time_zone: &impl TimeZoneInput,
475
    ) -> Result<FormattedZonedDateTime<'l>, DateTimeError> {
476
        if let Some(converted) = self.convert_if_necessary(date)? {
1✔
477
            Ok(self.0.format(&converted, time_zone))
1✔
478
        } else {
479
            Ok(self.0.format(date, time_zone))
×
480
        }
481
    }
1✔
482

483
    /// Takes a [`DateTimeInput`] and a [`TimeZoneInput`] and returns it formatted as a string.
484
    ///
485
    /// This function will fail if the date passed in uses a different calendar than that of the
486
    /// AnyCalendar. Please convert dates before passing them in if necessary. This function
487
    /// will automatically convert and format dates that are associated with the ISO calendar.
488
    #[inline]
489
    pub fn format_to_string(
490
        &self,
491
        date: &impl DateTimeInput<Calendar = AnyCalendar>,
492
        time_zone: &impl TimeZoneInput,
493
    ) -> Result<String, DateTimeError> {
494
        Ok(self.format(date, time_zone)?.write_to_string().into_owned())
495
    }
496

497
    /// Converts a date to the correct calendar if necessary
498
    ///
499
    /// Returns `Err` if the date is not ISO or compatible with the current calendar, returns `Ok(None)`
500
    /// if the date is compatible with the current calendar and doesn't need conversion
501
    fn convert_if_necessary(
1✔
502
        &self,
503
        value: &impl DateTimeInput<Calendar = AnyCalendar>,
504
    ) -> Result<Option<ExtractedDateTimeInput>, DateTimeError> {
505
        let this_calendar = self.1.kind();
1✔
506
        let date_calendar = value.any_calendar_kind();
1✔
507
        if Some(this_calendar) != date_calendar {
1✔
508
            if date_calendar != Some(AnyCalendarKind::Iso) {
1✔
509
                return Err(DateTimeError::MismatchedAnyCalendar(
×
510
                    this_calendar,
511
                    date_calendar,
×
512
                ));
513
            }
514
            let date = value.to_iso();
1✔
515
            let time = Time::new(
1✔
516
                value.hour().unwrap_or_default(),
1✔
517
                value.minute().unwrap_or_default(),
1✔
518
                value.second().unwrap_or_default(),
1✔
519
                value.nanosecond().unwrap_or_default(),
1✔
520
            );
521
            let datetime = DateTime::new(date, time).to_any();
1✔
522
            let converted = self.1.convert_any_datetime(&datetime);
1✔
523
            // FIXME(#2145) this is very hacky, can be improved after we improve ZonedDateTimeInput
524
            let converted = ExtractedDateTimeInput::extract_from(&converted);
1✔
525
            Ok(Some(converted))
1✔
526
        } else {
1✔
527
            Ok(None)
×
528
        }
529
    }
1✔
530
}
531

532
#[test]
533
#[cfg(feature = "serde")]
534
fn buffer_constructor() {
2✔
535
    #![allow(clippy::zero_prefixed_literal)]
536
    use icu::calendar::DateTime;
537
    use icu::datetime::options::length;
538
    use icu::datetime::ZonedDateTimeFormatter;
539
    use icu::locid::locale;
540
    use icu::timezone::CustomTimeZone;
541
    use std::str::FromStr;
542
    use writeable::assert_writeable_eq;
543

544
    let provider = icu_provider_blob::BlobDataProvider::try_new_from_static_blob(include_bytes!(
1✔
545
        "../../tests/data/blob.postcard"
546
    ))
547
    .unwrap();
548

549
    let zdtf = ZonedDateTimeFormatter::try_new_with_buffer_provider(
1✔
550
        &provider,
551
        &locale!("en").into(),
1✔
552
        length::Bag::from_date_time_style(length::Date::Medium, length::Time::Long).into(),
1✔
553
        Default::default(),
1✔
554
    )
555
    .unwrap();
1✔
556

557
    assert_writeable_eq!(
1✔
558
        zdtf.format(
1✔
559
            &DateTime::try_new_iso_datetime(2021, 04, 08, 16, 12, 37)
1✔
560
                .unwrap()
561
                .to_any(),
562
            &CustomTimeZone::from_str("-07:00").unwrap()
1✔
563
        )
564
        .unwrap(),
565
        "Apr 8, 2021, 4:12:37 PM GMT-07:00"
566
    );
567
}
2✔
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