/rust/registry/src/index.crates.io-6f17d22bba15001f/icu_datetime-1.5.1/src/datetime.rs
Line | Count | Source (jump to first uncovered line) |
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 | | #[cfg(feature = "experimental")] |
9 | | use crate::provider::date_time::UnsupportedOptionsOrDataOrPatternError; |
10 | | use crate::{ |
11 | | helpers::size_test, |
12 | | options::{length, preferences, DateTimeFormatterOptions}, |
13 | | provider::{ |
14 | | calendar::{TimeLengthsV1Marker, TimeSymbolsV1Marker}, |
15 | | date_time::{PatternForLengthError, PatternSelector}, |
16 | | }, |
17 | | raw, |
18 | | }; |
19 | | use alloc::string::String; |
20 | | use core::marker::PhantomData; |
21 | | use icu_calendar::provider::WeekDataV1Marker; |
22 | | use icu_decimal::provider::DecimalSymbolsV1Marker; |
23 | | use icu_plurals::provider::OrdinalV1Marker; |
24 | | use icu_provider::prelude::*; |
25 | | use writeable::Writeable; |
26 | | |
27 | | use crate::{ |
28 | | calendar, calendar::CldrCalendar, input::DateInput, input::DateTimeInput, input::IsoTimeInput, |
29 | | DateTimeError, FormattedDateTime, |
30 | | }; |
31 | | |
32 | | size_test!(TimeFormatter, time_formatter_size, 1200); |
33 | | |
34 | | /// [`TimeFormatter`] is a structure of the [`icu::datetime`] component that provides time formatting only. |
35 | | /// When constructed, it uses data from the [data provider], selected locale and provided preferences to |
36 | | /// collect all data necessary to format any time into that locale. |
37 | | /// |
38 | | /// For that reason, one should think of the process of formatting a time in two steps - first, a computational |
39 | | /// heavy construction of [`TimeFormatter`], and then fast formatting of [`DateTimeInput`] data using the instance. |
40 | | #[doc = time_formatter_size!()] |
41 | | /// |
42 | | /// [`icu::datetime`]: crate |
43 | | /// [`TypedDateTimeFormatter`]: crate::datetime::TimeFormatter |
44 | | /// |
45 | | /// # Examples |
46 | | /// |
47 | | /// ``` |
48 | | /// use icu::calendar::DateTime; |
49 | | /// use icu::datetime::{options::length::Time, TimeFormatter}; |
50 | | /// use icu::locid::locale; |
51 | | /// use writeable::assert_writeable_eq; |
52 | | /// |
53 | | /// let tf = |
54 | | /// TimeFormatter::try_new_with_length(&locale!("en").into(), Time::Short) |
55 | | /// .expect("Failed to create TimeFormatter instance."); |
56 | | /// |
57 | | /// let datetime = DateTime::try_new_gregorian_datetime(2020, 9, 1, 12, 34, 28) |
58 | | /// .expect("Failed to construct DateTime."); |
59 | | /// |
60 | | /// assert_writeable_eq!(tf.format(&datetime), "12:34 PM"); |
61 | | /// ``` |
62 | | /// |
63 | | /// This model replicates that of `ICU` and `ECMA402`. |
64 | | /// |
65 | | /// [data provider]: icu_provider |
66 | | #[derive(Debug)] |
67 | | pub struct TimeFormatter(pub(super) raw::TimeFormatter); |
68 | | |
69 | | impl TimeFormatter { |
70 | | /// Constructor that takes a selected locale and a list of preferences, then collects all |
71 | | /// compiled data necessary to format date and time values into the given locale, |
72 | | /// using the given style. |
73 | | /// |
74 | | /// ✨ *Enabled with the `compiled_data` Cargo feature.* |
75 | | /// |
76 | | /// [📚 Help choosing a constructor](icu_provider::constructors) |
77 | | /// |
78 | | /// # Examples |
79 | | /// |
80 | | /// ``` |
81 | | /// use icu::datetime::{options::length::Time, TimeFormatter}; |
82 | | /// use icu::locid::locale; |
83 | | /// |
84 | | /// TimeFormatter::try_new_with_length(&locale!("en").into(), Time::Short) |
85 | | /// .unwrap(); |
86 | | /// ``` |
87 | | #[cfg(feature = "compiled_data")] |
88 | 0 | pub fn try_new_with_length( |
89 | 0 | locale: &DataLocale, |
90 | 0 | length: length::Time, |
91 | 0 | ) -> Result<Self, DateTimeError> { |
92 | 0 | let preferences = Some(preferences::Bag::from_data_locale(locale)); |
93 | 0 |
|
94 | 0 | Ok(Self(raw::TimeFormatter::try_new( |
95 | 0 | locale, |
96 | 0 | length, |
97 | 0 | preferences, |
98 | 0 | )?)) |
99 | 0 | } |
100 | | |
101 | | icu_provider::gen_any_buffer_data_constructors!( |
102 | | locale: include, |
103 | | length: length::Time, |
104 | | error: DateTimeError, |
105 | | #[cfg(skip)] |
106 | | functions: [ |
107 | | try_new_with_length, |
108 | | try_new_with_length_with_any_provider, |
109 | | try_new_with_length_with_buffer_provider, |
110 | | try_new_with_length_unstable, |
111 | | Self, |
112 | | ] |
113 | | ); |
114 | | |
115 | | #[inline] |
116 | | #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::try_new_with_length)] |
117 | 0 | pub fn try_new_with_length_unstable<D>( |
118 | 0 | provider: &D, |
119 | 0 | locale: &DataLocale, |
120 | 0 | length: length::Time, |
121 | 0 | ) -> Result<Self, DateTimeError> |
122 | 0 | where |
123 | 0 | D: DataProvider<TimeLengthsV1Marker> |
124 | 0 | + DataProvider<TimeSymbolsV1Marker> |
125 | 0 | + DataProvider<DecimalSymbolsV1Marker> |
126 | 0 | + ?Sized, |
127 | 0 | { |
128 | 0 | let preferences = Some(preferences::Bag::from_data_locale(locale)); |
129 | 0 |
|
130 | 0 | Ok(Self(raw::TimeFormatter::try_new_unstable( |
131 | 0 | provider, |
132 | 0 | locale, |
133 | 0 | length, |
134 | 0 | preferences, |
135 | 0 | )?)) |
136 | 0 | } Unexecuted instantiation: <icu_datetime::datetime::TimeFormatter>::try_new_with_length_unstable::<icu_provider::any::DowncastingAnyProvider<icu_provider_adapters::empty::EmptyDataProvider>> Unexecuted instantiation: <icu_datetime::datetime::TimeFormatter>::try_new_with_length_unstable::<_> |
137 | | |
138 | | /// Takes a [`IsoTimeInput`] implementer and returns an instance of a [`FormattedDateTime`] |
139 | | /// that contains all information necessary to display a formatted date and operate on it. |
140 | | /// |
141 | | /// # Examples |
142 | | /// |
143 | | /// ``` |
144 | | /// use icu::calendar::DateTime; |
145 | | /// use icu::datetime::{options::length::Time, TimeFormatter}; |
146 | | /// use icu::locid::locale; |
147 | | /// use writeable::assert_writeable_eq; |
148 | | /// |
149 | | /// let tf = |
150 | | /// TimeFormatter::try_new_with_length(&locale!("en").into(), Time::Short) |
151 | | /// .expect("Failed to create TimeFormatter instance."); |
152 | | /// |
153 | | /// let datetime = DateTime::try_new_gregorian_datetime(2020, 9, 1, 12, 34, 28) |
154 | | /// .expect("Failed to construct DateTime."); |
155 | | /// |
156 | | /// assert_writeable_eq!(tf.format(&datetime), "12:34 PM"); |
157 | | /// ``` |
158 | | #[inline] |
159 | 0 | pub fn format<'l, T>(&'l self, value: &T) -> FormattedDateTime<'l> |
160 | 0 | where |
161 | 0 | T: IsoTimeInput, |
162 | 0 | { |
163 | 0 | self.0.format(value) |
164 | 0 | } Unexecuted instantiation: <icu_datetime::datetime::TimeFormatter>::format::<icu_calendar::datetime::DateTime<alloc::sync::Arc<icu_calendar::any_calendar::AnyCalendar>>> Unexecuted instantiation: <icu_datetime::datetime::TimeFormatter>::format::<icu_calendar::datetime::DateTime<icu_calendar::iso::Iso>> Unexecuted instantiation: <icu_datetime::datetime::TimeFormatter>::format::<icu_calendar::types::Time> Unexecuted instantiation: <icu_datetime::datetime::TimeFormatter>::format::<_> |
165 | | |
166 | | /// Takes a [`IsoTimeInput`] implementer and returns it formatted as a string. |
167 | | /// |
168 | | /// # Examples |
169 | | /// |
170 | | /// ``` |
171 | | /// use icu::calendar::DateTime; |
172 | | /// use icu::datetime::{options::length::Time, TimeFormatter}; |
173 | | /// use icu::locid::locale; |
174 | | /// let tf = |
175 | | /// TimeFormatter::try_new_with_length(&locale!("en").into(), Time::Short) |
176 | | /// .expect("Failed to create TimeFormatter instance."); |
177 | | /// |
178 | | /// let datetime = DateTime::try_new_gregorian_datetime(2020, 9, 1, 12, 34, 28) |
179 | | /// .expect("Failed to construct DateTime."); |
180 | | /// |
181 | | /// assert_eq!(tf.format_to_string(&datetime), "12:34 PM"); |
182 | | /// ``` |
183 | | #[inline] |
184 | 0 | pub fn format_to_string(&self, value: &impl IsoTimeInput) -> String { |
185 | 0 | self.format(value).write_to_string().into_owned() |
186 | 0 | } |
187 | | } |
188 | | |
189 | | size_test!( |
190 | | TypedDateFormatter<icu_calendar::Gregorian>, |
191 | | typed_date_formatter_size, |
192 | | 4400 |
193 | | ); |
194 | | |
195 | | /// [`TypedDateFormatter`] is a formatter capable of formatting |
196 | | /// dates from a calendar selected at compile time. For the difference between this |
197 | | /// and [`DateFormatter`](crate::DateFormatter), please read the [crate root docs][crate]. |
198 | | /// |
199 | | /// When constructed, it uses data from the [data provider], selected locale and provided options to |
200 | | /// collect all data necessary to format any dates into that locale. |
201 | | /// |
202 | | /// For that reason, one should think of the process of formatting a date in two steps - first, a computational |
203 | | /// heavy construction of [`TypedDateFormatter`], and then fast formatting of [`DateInput`] data using the instance. |
204 | | #[doc = typed_date_formatter_size!()] |
205 | | /// |
206 | | /// [`icu::datetime`]: crate |
207 | | /// |
208 | | /// # Examples |
209 | | /// |
210 | | /// ``` |
211 | | /// use icu::calendar::{Date, Gregorian}; |
212 | | /// use icu::datetime::{options::length, TypedDateFormatter}; |
213 | | /// use icu::locid::locale; |
214 | | /// use writeable::assert_writeable_eq; |
215 | | /// |
216 | | /// let df = TypedDateFormatter::<Gregorian>::try_new_with_length( |
217 | | /// &locale!("en").into(), |
218 | | /// length::Date::Full, |
219 | | /// ) |
220 | | /// .expect("Failed to create TypedDateFormatter instance."); |
221 | | /// |
222 | | /// let date = Date::try_new_gregorian_date(2020, 9, 1) |
223 | | /// .expect("Failed to construct Date."); |
224 | | /// |
225 | | /// assert_writeable_eq!(df.format(&date), "Tuesday, September 1, 2020"); |
226 | | /// ``` |
227 | | /// |
228 | | /// This model replicates that of `ICU` and `ECMA402`. |
229 | | /// |
230 | | /// [data provider]: icu_provider |
231 | | #[derive(Debug)] |
232 | | pub struct TypedDateFormatter<C>(pub(super) raw::DateFormatter, PhantomData<C>); |
233 | | |
234 | | impl<C: CldrCalendar> TypedDateFormatter<C> { |
235 | | /// Constructor that takes a selected locale and a list of options, then collects all |
236 | | /// compiled data necessary to format date and time values into the given locale. |
237 | | /// |
238 | | /// ✨ *Enabled with the `compiled_data` Cargo feature.* |
239 | | /// |
240 | | /// [📚 Help choosing a constructor](icu_provider::constructors) |
241 | | /// |
242 | | /// # Examples |
243 | | /// |
244 | | /// ``` |
245 | | /// use icu::calendar::Date; |
246 | | /// use icu::calendar::Gregorian; |
247 | | /// use icu::datetime::{options::length, TypedDateFormatter}; |
248 | | /// use icu::locid::locale; |
249 | | /// use writeable::assert_writeable_eq; |
250 | | /// |
251 | | /// let formatter = TypedDateFormatter::<Gregorian>::try_new_with_length( |
252 | | /// &locale!("en").into(), |
253 | | /// length::Date::Full, |
254 | | /// ) |
255 | | /// .unwrap(); |
256 | | /// |
257 | | /// assert_writeable_eq!( |
258 | | /// formatter.format(&Date::try_new_gregorian_date(2022, 8, 29).unwrap()), |
259 | | /// "Monday, August 29, 2022", |
260 | | /// ); |
261 | | /// ``` |
262 | | /// |
263 | | /// If the locale has a calendar keyword, the keyword is ignored in favor of the |
264 | | /// type parameter on the [`TypedDateFormatter`]. To obey the calendar keyword, |
265 | | /// use [`DateFormatter`] instead. |
266 | | /// |
267 | | /// ``` |
268 | | /// use icu::calendar::indian::Indian; |
269 | | /// use icu::calendar::Date; |
270 | | /// use icu::datetime::{options::length, TypedDateFormatter}; |
271 | | /// use icu::locid::locale; |
272 | | /// use writeable::assert_writeable_eq; |
273 | | /// |
274 | | /// let formatter = TypedDateFormatter::<Indian>::try_new_with_length( |
275 | | /// &locale!("en-u-ca-japanese").into(), |
276 | | /// length::Date::Full, |
277 | | /// ) |
278 | | /// .unwrap(); |
279 | | /// |
280 | | /// // Indian format from type wins over locale keyword |
281 | | /// assert_writeable_eq!( |
282 | | /// formatter.format(&Date::try_new_indian_date(1944, 6, 7).unwrap()), |
283 | | /// "Monday, Bhadra 7, 1944 Saka", |
284 | | /// ); |
285 | | /// ``` |
286 | | /// |
287 | | /// [`DateFormatter`]: crate::DateFormatter |
288 | | #[cfg(feature = "compiled_data")] |
289 | 0 | pub fn try_new_with_length( |
290 | 0 | locale: &DataLocale, |
291 | 0 | length: length::Date, |
292 | 0 | ) -> Result<Self, DateTimeError> |
293 | 0 | where |
294 | 0 | crate::provider::Baked: icu_provider::DataProvider<<C as CldrCalendar>::DateLengthsV1Marker> |
295 | 0 | + icu_provider::DataProvider<<C as CldrCalendar>::DateSymbolsV1Marker>, |
296 | 0 | { |
297 | 0 | Ok(Self( |
298 | 0 | raw::DateFormatter::try_new( |
299 | 0 | calendar::load_lengths_for_cldr_calendar::<C, _>(&crate::provider::Baked, locale)?, |
300 | 0 | || { |
301 | 0 | calendar::load_symbols_for_cldr_calendar::<C, _>( |
302 | 0 | &crate::provider::Baked, |
303 | 0 | locale, |
304 | 0 | ) |
305 | 0 | }, Unexecuted instantiation: <icu_datetime::datetime::TypedDateFormatter<icu_calendar::gregorian::Gregorian>>::try_new_with_length::{closure#0} Unexecuted instantiation: <icu_datetime::datetime::TypedDateFormatter<_>>::try_new_with_length::{closure#0} |
306 | 0 | locale, |
307 | 0 | length, |
308 | 0 | )?, |
309 | 0 | PhantomData, |
310 | | )) |
311 | 0 | } Unexecuted instantiation: <icu_datetime::datetime::TypedDateFormatter<icu_calendar::gregorian::Gregorian>>::try_new_with_length Unexecuted instantiation: <icu_datetime::datetime::TypedDateFormatter<_>>::try_new_with_length |
312 | | |
313 | | icu_provider::gen_any_buffer_data_constructors!( |
314 | | locale: include, |
315 | | length: length::Date, |
316 | | error: DateTimeError, |
317 | | #[cfg(skip)] |
318 | | functions: [ |
319 | | try_new_with_length, |
320 | | try_new_with_length_with_any_provider, |
321 | | try_new_with_length_with_buffer_provider, |
322 | | try_new_with_length_unstable, |
323 | | Self, |
324 | | ] |
325 | | ); |
326 | | |
327 | | #[inline] |
328 | | #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::try_new_with_length)] |
329 | 0 | pub fn try_new_with_length_unstable<D>( |
330 | 0 | provider: &D, |
331 | 0 | locale: &DataLocale, |
332 | 0 | length: length::Date, |
333 | 0 | ) -> Result<Self, DateTimeError> |
334 | 0 | where |
335 | 0 | D: DataProvider<<C as CldrCalendar>::DateSymbolsV1Marker> |
336 | 0 | + DataProvider<<C as CldrCalendar>::DateLengthsV1Marker> |
337 | 0 | + DataProvider<DecimalSymbolsV1Marker> |
338 | 0 | + DataProvider<OrdinalV1Marker> |
339 | 0 | + DataProvider<WeekDataV1Marker> |
340 | 0 | + ?Sized, |
341 | 0 | { |
342 | 0 | Ok(Self( |
343 | 0 | raw::DateFormatter::try_new_unstable( |
344 | 0 | provider, |
345 | 0 | calendar::load_lengths_for_cldr_calendar::<C, _>(provider, locale)?, |
346 | 0 | || calendar::load_symbols_for_cldr_calendar::<C, _>(provider, locale), Unexecuted instantiation: <icu_datetime::datetime::TypedDateFormatter<icu_calendar::gregorian::Gregorian>>::try_new_with_length_unstable::<icu_provider::any::DowncastingAnyProvider<icu_provider_adapters::empty::EmptyDataProvider>>::{closure#0} Unexecuted instantiation: <icu_datetime::datetime::TypedDateFormatter<_>>::try_new_with_length_unstable::<_>::{closure#0} |
347 | 0 | locale, |
348 | 0 | length, |
349 | 0 | )?, |
350 | 0 | PhantomData, |
351 | | )) |
352 | 0 | } Unexecuted instantiation: <icu_datetime::datetime::TypedDateFormatter<icu_calendar::gregorian::Gregorian>>::try_new_with_length_unstable::<icu_provider::any::DowncastingAnyProvider<icu_provider_adapters::empty::EmptyDataProvider>> Unexecuted instantiation: <icu_datetime::datetime::TypedDateFormatter<_>>::try_new_with_length_unstable::<_> |
353 | | |
354 | | /// Takes a [`DateTimeInput`] implementer and returns an instance of a [`FormattedDateTime`] |
355 | | /// that contains all information necessary to display a formatted date and operate on it. |
356 | | /// |
357 | | /// # Examples |
358 | | /// |
359 | | /// ``` |
360 | | /// use icu::calendar::{Date, Gregorian}; |
361 | | /// use icu::datetime::{options::length, TypedDateFormatter}; |
362 | | /// use icu::locid::locale; |
363 | | /// use writeable::assert_writeable_eq; |
364 | | /// let df = TypedDateFormatter::<Gregorian>::try_new_with_length( |
365 | | /// &locale!("en").into(), |
366 | | /// length::Date::Full, |
367 | | /// ) |
368 | | /// .expect("Failed to create TypedDateFormatter instance."); |
369 | | /// |
370 | | /// let date = Date::try_new_gregorian_date(2020, 9, 1) |
371 | | /// .expect("Failed to construct Date."); |
372 | | /// |
373 | | /// assert_writeable_eq!(df.format(&date), "Tuesday, September 1, 2020"); |
374 | | /// ``` |
375 | | #[inline] |
376 | 0 | pub fn format<'l, T>(&'l self, value: &T) -> FormattedDateTime<'l> |
377 | 0 | where |
378 | 0 | T: DateInput<Calendar = C>, |
379 | 0 | { |
380 | 0 | self.0.format(value) |
381 | 0 | } Unexecuted instantiation: <icu_datetime::datetime::TypedDateFormatter<icu_calendar::gregorian::Gregorian>>::format::<icu_calendar::date::Date<icu_calendar::gregorian::Gregorian>> Unexecuted instantiation: <icu_datetime::datetime::TypedDateFormatter<icu_calendar::gregorian::Gregorian>>::format::<icu_calendar::datetime::DateTime<icu_calendar::gregorian::Gregorian>> Unexecuted instantiation: <icu_datetime::datetime::TypedDateFormatter<_>>::format::<_> |
382 | | |
383 | | /// Takes a [`DateTimeInput`] implementer and returns it formatted as a string. |
384 | | /// |
385 | | /// # Examples |
386 | | /// |
387 | | /// ``` |
388 | | /// use icu::calendar::{Date, Gregorian}; |
389 | | /// use icu::datetime::{options::length, TypedDateFormatter}; |
390 | | /// use icu::locid::locale; |
391 | | /// let df = TypedDateFormatter::<Gregorian>::try_new_with_length( |
392 | | /// &locale!("en").into(), |
393 | | /// length::Date::Short, |
394 | | /// ) |
395 | | /// .expect("Failed to create TypedDateTimeFormatter instance."); |
396 | | /// |
397 | | /// let date = Date::try_new_gregorian_date(2020, 9, 1) |
398 | | /// .expect("Failed to construct Date."); |
399 | | /// |
400 | | /// assert_eq!(df.format_to_string(&date), "9/1/20"); |
401 | | /// ``` |
402 | | #[inline] |
403 | 0 | pub fn format_to_string(&self, value: &impl DateInput<Calendar = C>) -> String { |
404 | 0 | self.format(value).write_to_string().into_owned() |
405 | 0 | } |
406 | | } |
407 | | |
408 | | size_test!( |
409 | | TypedDateTimeFormatter<icu_calendar::Gregorian>, |
410 | | typed_date_time_formatter_size, |
411 | | 5152 |
412 | | ); |
413 | | |
414 | | /// [`TypedDateTimeFormatter`] is a formatter capable of formatting |
415 | | /// date/times from a calendar selected at compile time. For the difference between this |
416 | | /// and [`DateTimeFormatter`](crate::DateTimeFormatter), please read the [crate root docs][crate]. |
417 | | /// |
418 | | /// When constructed, it uses data from the [data provider], selected locale and provided options to |
419 | | /// collect all data necessary to format any dates into that locale. |
420 | | /// |
421 | | /// For that reason, one should think of the process of formatting a date in two steps - first, a computational |
422 | | /// heavy construction of [`TypedDateTimeFormatter`], and then fast formatting of [`DateInput`] data using the instance. |
423 | | #[doc = typed_date_time_formatter_size!()] |
424 | | /// |
425 | | /// [`icu::datetime`]: crate |
426 | | /// [`TypedDateTimeFormatter`]: crate::datetime::TypedDateTimeFormatter |
427 | | /// |
428 | | /// # Examples |
429 | | /// |
430 | | /// ``` |
431 | | /// use icu::calendar::{DateTime, Gregorian}; |
432 | | /// use icu::datetime::{options::length, TypedDateTimeFormatter}; |
433 | | /// use icu::locid::locale; |
434 | | /// use writeable::assert_writeable_eq; |
435 | | /// |
436 | | /// let mut options = length::Bag::from_date_time_style( |
437 | | /// length::Date::Medium, |
438 | | /// length::Time::Short, |
439 | | /// ); |
440 | | /// |
441 | | /// let dtf = TypedDateTimeFormatter::<Gregorian>::try_new( |
442 | | /// &locale!("en").into(), |
443 | | /// options.into(), |
444 | | /// ) |
445 | | /// .expect("Failed to create TypedDateTimeFormatter instance."); |
446 | | /// |
447 | | /// let datetime = DateTime::try_new_gregorian_datetime(2020, 9, 1, 12, 34, 28) |
448 | | /// .expect("Failed to construct DateTime."); |
449 | | /// |
450 | | /// assert_writeable_eq!(dtf.format(&datetime), "Sep 1, 2020, 12:34 PM"); |
451 | | /// ``` |
452 | | /// |
453 | | /// This model replicates that of `ICU` and `ECMA402`. |
454 | | /// |
455 | | /// [data provider]: icu_provider |
456 | | #[derive(Debug)] |
457 | | pub struct TypedDateTimeFormatter<C>(pub(super) raw::DateTimeFormatter, PhantomData<C>); |
458 | | |
459 | | impl<C: CldrCalendar> TypedDateTimeFormatter<C> { |
460 | | /// Constructor that takes a [`TimeFormatter`] and [`TypedDateFormatter`] and combines them into a [`TypedDateTimeFormatter`]. |
461 | | /// |
462 | | /// # Examples |
463 | | /// |
464 | | /// ``` |
465 | | /// use icu::calendar::Gregorian; |
466 | | /// use icu::datetime::{ |
467 | | /// options::length, TimeFormatter, TypedDateFormatter, |
468 | | /// TypedDateTimeFormatter, |
469 | | /// }; |
470 | | /// use icu::locid::locale; |
471 | | /// |
472 | | /// let tf = TimeFormatter::try_new_with_length( |
473 | | /// &locale!("en").into(), |
474 | | /// length::Time::Short, |
475 | | /// ) |
476 | | /// .expect("Failed to create TimeFormatter instance."); |
477 | | /// let df = TypedDateFormatter::<Gregorian>::try_new_with_length( |
478 | | /// &locale!("en").into(), |
479 | | /// length::Date::Short, |
480 | | /// ) |
481 | | /// .expect("Failed to create TypedDateFormatter instance."); |
482 | | /// |
483 | | /// TypedDateTimeFormatter::<Gregorian>::try_from_date_and_time(df, tf) |
484 | | /// .unwrap(); |
485 | | /// ``` |
486 | | /// |
487 | | /// [data provider]: icu_provider |
488 | | #[inline] |
489 | 0 | pub fn try_from_date_and_time( |
490 | 0 | date: TypedDateFormatter<C>, |
491 | 0 | time: TimeFormatter, |
492 | 0 | ) -> Result<Self, DateTimeError> |
493 | 0 | where { |
494 | 0 | Ok(Self( |
495 | 0 | raw::DateTimeFormatter::try_from_date_and_time(date.0, time.0)?, |
496 | 0 | PhantomData, |
497 | | )) |
498 | 0 | } |
499 | | |
500 | | /// Constructor that takes a selected locale, then collects all |
501 | | /// compiled data necessary to format date and time values into the given locale. |
502 | | /// |
503 | | /// ✨ *Enabled with the `compiled_data` Cargo feature.* |
504 | | /// |
505 | | /// [📚 Help choosing a constructor](icu_provider::constructors) |
506 | | /// |
507 | | /// # Examples |
508 | | /// |
509 | | /// ``` |
510 | | /// use icu::calendar::{DateTime, Gregorian}; |
511 | | /// use icu::datetime::{options::length, TypedDateTimeFormatter}; |
512 | | /// use icu::locid::locale; |
513 | | /// use writeable::assert_writeable_eq; |
514 | | /// |
515 | | /// let options = length::Bag::from_date_time_style( |
516 | | /// length::Date::Medium, |
517 | | /// length::Time::Medium, |
518 | | /// ); |
519 | | /// |
520 | | /// let dtf = TypedDateTimeFormatter::<Gregorian>::try_new( |
521 | | /// &locale!("en").into(), |
522 | | /// options.into(), |
523 | | /// ) |
524 | | /// .unwrap(); |
525 | | /// |
526 | | /// let datetime = |
527 | | /// DateTime::try_new_gregorian_datetime(2022, 8, 31, 1, 2, 3).unwrap(); |
528 | | /// |
529 | | /// assert_writeable_eq!(dtf.format(&datetime), "Aug 31, 2022, 1:02:03 AM"); |
530 | | /// ``` |
531 | | /// |
532 | | /// [data provider]: icu_provider |
533 | | #[cfg(feature = "compiled_data")] |
534 | 0 | pub fn try_new( |
535 | 0 | locale: &DataLocale, |
536 | 0 | options: DateTimeFormatterOptions, |
537 | 0 | ) -> Result<Self, DateTimeError> |
538 | 0 | where |
539 | 0 | crate::provider::Baked: DataProvider<<C as CldrCalendar>::DateLengthsV1Marker>, |
540 | 0 | crate::provider::Baked: DataProvider<<C as CldrCalendar>::DateSymbolsV1Marker>, |
541 | 0 | { |
542 | 0 | let patterns = PatternSelector::for_options( |
543 | 0 | &crate::provider::Baked, |
544 | 0 | calendar::load_lengths_for_cldr_calendar::<C, _>(&crate::provider::Baked, locale)?, |
545 | 0 | locale, |
546 | 0 | &options, |
547 | 0 | ) |
548 | 0 | .map_err(|e| match e { |
549 | 0 | PatternForLengthError::Data(e) => DateTimeError::Data(e), |
550 | 0 | PatternForLengthError::Pattern(e) => DateTimeError::Pattern(e), |
551 | 0 | })?; Unexecuted instantiation: <icu_datetime::datetime::TypedDateTimeFormatter<icu_calendar::gregorian::Gregorian>>::try_new::{closure#0} Unexecuted instantiation: <icu_datetime::datetime::TypedDateTimeFormatter<_>>::try_new::{closure#0} |
552 | | Ok(Self( |
553 | 0 | raw::DateTimeFormatter::try_new( |
554 | 0 | patterns, |
555 | 0 | || { |
556 | 0 | calendar::load_symbols_for_cldr_calendar::<C, _>( |
557 | 0 | &crate::provider::Baked, |
558 | 0 | locale, |
559 | 0 | ) |
560 | 0 | }, Unexecuted instantiation: <icu_datetime::datetime::TypedDateTimeFormatter<icu_calendar::gregorian::Gregorian>>::try_new::{closure#1} Unexecuted instantiation: <icu_datetime::datetime::TypedDateTimeFormatter<_>>::try_new::{closure#1} |
561 | 0 | locale, |
562 | 0 | )?, |
563 | 0 | PhantomData, |
564 | | )) |
565 | 0 | } Unexecuted instantiation: <icu_datetime::datetime::TypedDateTimeFormatter<icu_calendar::gregorian::Gregorian>>::try_new Unexecuted instantiation: <icu_datetime::datetime::TypedDateTimeFormatter<_>>::try_new |
566 | | |
567 | | icu_provider::gen_any_buffer_data_constructors!( |
568 | | locale: include, |
569 | | options: DateTimeFormatterOptions, |
570 | | error: DateTimeError, |
571 | | #[cfg(skip)] |
572 | | functions: [ |
573 | | try_new, |
574 | | try_new_with_any_provider, |
575 | | try_new_with_buffer_provider, |
576 | | try_new_unstable, |
577 | | Self |
578 | | ] |
579 | | ); |
580 | | |
581 | | #[inline] |
582 | | #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::try_new)] |
583 | 0 | pub fn try_new_unstable<D>( |
584 | 0 | provider: &D, |
585 | 0 | locale: &DataLocale, |
586 | 0 | options: DateTimeFormatterOptions, |
587 | 0 | ) -> Result<Self, DateTimeError> |
588 | 0 | where |
589 | 0 | D: DataProvider<<C as CldrCalendar>::DateSymbolsV1Marker> |
590 | 0 | + DataProvider<<C as CldrCalendar>::DateLengthsV1Marker> |
591 | 0 | + DataProvider<TimeSymbolsV1Marker> |
592 | 0 | + DataProvider<TimeLengthsV1Marker> |
593 | 0 | + DataProvider<DecimalSymbolsV1Marker> |
594 | 0 | + DataProvider<OrdinalV1Marker> |
595 | 0 | + DataProvider<WeekDataV1Marker> |
596 | 0 | + ?Sized, |
597 | 0 | { |
598 | 0 | let patterns = PatternSelector::for_options( |
599 | 0 | provider, |
600 | 0 | calendar::load_lengths_for_cldr_calendar::<C, _>(provider, locale)?, |
601 | 0 | locale, |
602 | 0 | &options, |
603 | 0 | ) |
604 | 0 | .map_err(|e| match e { |
605 | 0 | PatternForLengthError::Data(e) => DateTimeError::Data(e), |
606 | 0 | PatternForLengthError::Pattern(e) => DateTimeError::Pattern(e), |
607 | 0 | })?; Unexecuted instantiation: <icu_datetime::datetime::TypedDateTimeFormatter<icu_calendar::gregorian::Gregorian>>::try_new_unstable::<icu_provider::any::DowncastingAnyProvider<icu_provider_adapters::empty::EmptyDataProvider>>::{closure#0} Unexecuted instantiation: <icu_datetime::datetime::TypedDateTimeFormatter<_>>::try_new_unstable::<_>::{closure#0} |
608 | | Ok(Self( |
609 | 0 | raw::DateTimeFormatter::try_new_unstable( |
610 | 0 | provider, |
611 | 0 | patterns, |
612 | 0 | || calendar::load_symbols_for_cldr_calendar::<C, _>(provider, locale), Unexecuted instantiation: <icu_datetime::datetime::TypedDateTimeFormatter<icu_calendar::gregorian::Gregorian>>::try_new_unstable::<icu_provider::any::DowncastingAnyProvider<icu_provider_adapters::empty::EmptyDataProvider>>::{closure#1} Unexecuted instantiation: <icu_datetime::datetime::TypedDateTimeFormatter<_>>::try_new_unstable::<_>::{closure#1} |
613 | 0 | locale, |
614 | 0 | )?, |
615 | 0 | PhantomData, |
616 | | )) |
617 | 0 | } Unexecuted instantiation: <icu_datetime::datetime::TypedDateTimeFormatter<icu_calendar::gregorian::Gregorian>>::try_new_unstable::<icu_provider::any::DowncastingAnyProvider<icu_provider_adapters::empty::EmptyDataProvider>> Unexecuted instantiation: <icu_datetime::datetime::TypedDateTimeFormatter<_>>::try_new_unstable::<_> |
618 | | |
619 | | /// Constructor that supports experimental options using compiled data. |
620 | | /// |
621 | | /// ✨ *Enabled with the `compiled_data` and `experimental` Cargo features.* |
622 | | /// |
623 | | /// [📚 Help choosing a constructor](icu_provider::constructors) |
624 | | /// |
625 | | /// <div class="stab unstable"> |
626 | | /// 🚧 This code is experimental; it may change at any time, in breaking or non-breaking ways, |
627 | | /// including in SemVer minor releases. It can be enabled with the "experimental" Cargo feature |
628 | | /// of the icu meta-crate. Use with caution. |
629 | | /// <a href="https://github.com/unicode-org/icu4x/issues/1317">#1317</a> |
630 | | /// </div> |
631 | | /// |
632 | | /// # Examples |
633 | | /// |
634 | | /// ``` |
635 | | /// use icu::calendar::{DateTime, Gregorian}; |
636 | | /// use icu::datetime::{options::components, TypedDateTimeFormatter}; |
637 | | /// use icu::locid::locale; |
638 | | /// use writeable::assert_writeable_eq; |
639 | | /// |
640 | | /// let mut options = components::Bag::default(); |
641 | | /// options.year = Some(components::Year::Numeric); |
642 | | /// options.month = Some(components::Month::Long); |
643 | | /// |
644 | | /// let dtf = TypedDateTimeFormatter::<Gregorian>::try_new_experimental( |
645 | | /// &locale!("en").into(), |
646 | | /// options.into(), |
647 | | /// ) |
648 | | /// .unwrap(); |
649 | | /// |
650 | | /// let datetime = |
651 | | /// DateTime::try_new_gregorian_datetime(2022, 8, 31, 1, 2, 3).unwrap(); |
652 | | /// |
653 | | /// assert_writeable_eq!(dtf.format(&datetime), "August 2022"); |
654 | | /// ``` |
655 | | /// |
656 | | /// [data provider]: icu_provider |
657 | | #[cfg(feature = "experimental")] |
658 | | #[inline] |
659 | | #[cfg(feature = "compiled_data")] |
660 | | pub fn try_new_experimental( |
661 | | locale: &DataLocale, |
662 | | options: DateTimeFormatterOptions, |
663 | | ) -> Result<Self, DateTimeError> |
664 | | where |
665 | | crate::provider::Baked: DataProvider<<C as CldrCalendar>::DateLengthsV1Marker>, |
666 | | crate::provider::Baked: DataProvider<<C as CldrCalendar>::DateSymbolsV1Marker>, |
667 | | { |
668 | | let patterns = PatternSelector::for_options_experimental( |
669 | | &crate::provider::Baked, |
670 | | calendar::load_lengths_for_cldr_calendar::<C, _>(&crate::provider::Baked, locale)?, |
671 | | locale, |
672 | | &C::DEFAULT_BCP_47_IDENTIFIER, |
673 | | &options, |
674 | | ) |
675 | | .map_err(|e| match e { |
676 | | UnsupportedOptionsOrDataOrPatternError::UnsupportedOptions => { |
677 | | DateTimeError::UnsupportedOptions |
678 | | } |
679 | | UnsupportedOptionsOrDataOrPatternError::Data(e) => DateTimeError::Data(e), |
680 | | UnsupportedOptionsOrDataOrPatternError::Pattern(e) => DateTimeError::Pattern(e), |
681 | | })?; |
682 | | Ok(Self( |
683 | | raw::DateTimeFormatter::try_new( |
684 | | patterns, |
685 | | || { |
686 | | calendar::load_symbols_for_cldr_calendar::<C, _>( |
687 | | &crate::provider::Baked, |
688 | | locale, |
689 | | ) |
690 | | }, |
691 | | locale, |
692 | | )?, |
693 | | PhantomData, |
694 | | )) |
695 | | } |
696 | | |
697 | | #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::try_new_experimental)] |
698 | | #[cfg(feature = "experimental")] |
699 | | #[inline] |
700 | | pub fn try_new_experimental_unstable<D>( |
701 | | provider: &D, |
702 | | locale: &DataLocale, |
703 | | options: DateTimeFormatterOptions, |
704 | | ) -> Result<Self, DateTimeError> |
705 | | where |
706 | | D: DataProvider<<C as CldrCalendar>::DateSymbolsV1Marker> |
707 | | + DataProvider<<C as CldrCalendar>::DateLengthsV1Marker> |
708 | | + DataProvider<TimeSymbolsV1Marker> |
709 | | + DataProvider<TimeLengthsV1Marker> |
710 | | + DataProvider<crate::provider::calendar::DateSkeletonPatternsV1Marker> |
711 | | + DataProvider<DecimalSymbolsV1Marker> |
712 | | + DataProvider<OrdinalV1Marker> |
713 | | + DataProvider<WeekDataV1Marker> |
714 | | + ?Sized, |
715 | | { |
716 | | let patterns = PatternSelector::for_options_experimental( |
717 | | provider, |
718 | | calendar::load_lengths_for_cldr_calendar::<C, _>(provider, locale)?, |
719 | | locale, |
720 | | &C::DEFAULT_BCP_47_IDENTIFIER, |
721 | | &options, |
722 | | ) |
723 | | .map_err(|e| match e { |
724 | | UnsupportedOptionsOrDataOrPatternError::UnsupportedOptions => { |
725 | | DateTimeError::UnsupportedOptions |
726 | | } |
727 | | UnsupportedOptionsOrDataOrPatternError::Data(e) => DateTimeError::Data(e), |
728 | | UnsupportedOptionsOrDataOrPatternError::Pattern(e) => DateTimeError::Pattern(e), |
729 | | })?; |
730 | | |
731 | | Ok(Self( |
732 | | raw::DateTimeFormatter::try_new_unstable( |
733 | | provider, |
734 | | patterns, |
735 | | || calendar::load_symbols_for_cldr_calendar::<C, _>(provider, locale), |
736 | | locale, |
737 | | )?, |
738 | | PhantomData, |
739 | | )) |
740 | | } |
741 | | |
742 | | /// Takes a [`DateTimeInput`] implementer and returns an instance of a [`FormattedDateTime`] |
743 | | /// that contains all information necessary to display a formatted date and operate on it. |
744 | | /// |
745 | | /// # Examples |
746 | | /// |
747 | | /// ``` |
748 | | /// use icu::calendar::{DateTime, Gregorian}; |
749 | | /// use icu::datetime::TypedDateTimeFormatter; |
750 | | /// use writeable::assert_writeable_eq; |
751 | | /// use icu::locid::locale; |
752 | | /// # let options = icu::datetime::options::length::Bag::from_time_style(icu::datetime::options::length::Time::Medium); |
753 | | /// let dtf = TypedDateTimeFormatter::<Gregorian>::try_new(&locale!("en").into(), options.into()) |
754 | | /// .expect("Failed to create TypedDateTimeFormatter instance."); |
755 | | /// |
756 | | /// let datetime = DateTime::try_new_gregorian_datetime(2020, 9, 1, 12, 34, 28) |
757 | | /// .expect("Failed to construct DateTime."); |
758 | | /// |
759 | | /// assert_writeable_eq!(dtf.format(&datetime), "12:34:28 PM"); |
760 | | /// ``` |
761 | | #[inline] |
762 | 0 | pub fn format<'l, T>(&'l self, value: &T) -> FormattedDateTime<'l> |
763 | 0 | where |
764 | 0 | T: DateTimeInput<Calendar = C>, |
765 | 0 | { |
766 | 0 | self.0.format(value) |
767 | 0 | } Unexecuted instantiation: <icu_datetime::datetime::TypedDateTimeFormatter<icu_calendar::gregorian::Gregorian>>::format::<icu_calendar::datetime::DateTime<icu_calendar::gregorian::Gregorian>> Unexecuted instantiation: <icu_datetime::datetime::TypedDateTimeFormatter<_>>::format::<_> |
768 | | |
769 | | /// Takes a [`DateTimeInput`] implementer and returns it formatted as a string. |
770 | | /// |
771 | | /// # Examples |
772 | | /// |
773 | | /// ``` |
774 | | /// use icu::calendar::{DateTime, Gregorian}; |
775 | | /// use icu::datetime::TypedDateTimeFormatter; |
776 | | /// use icu::locid::locale; |
777 | | /// # let options = icu::datetime::options::length::Bag::from_time_style(icu::datetime::options::length::Time::Medium); |
778 | | /// let dtf = TypedDateTimeFormatter::<Gregorian>::try_new(&locale!("en").into(), options.into()) |
779 | | /// .expect("Failed to create TypedDateTimeFormatter instance."); |
780 | | /// |
781 | | /// let datetime = DateTime::try_new_gregorian_datetime(2020, 9, 1, 12, 34, 28) |
782 | | /// .expect("Failed to construct DateTime."); |
783 | | /// |
784 | | /// assert_eq!(dtf.format_to_string(&datetime), "12:34:28 PM"); |
785 | | /// ``` |
786 | | #[inline] |
787 | 0 | pub fn format_to_string(&self, value: &impl DateTimeInput<Calendar = C>) -> String { |
788 | 0 | self.format(value).write_to_string().into_owned() |
789 | 0 | } |
790 | | |
791 | | /// Returns a [`components::Bag`](crate::options::components::Bag) that represents the resolved components for the |
792 | | /// options that were provided to the [`TypedDateTimeFormatter`]. The developer may request |
793 | | /// a certain set of options for a [`TypedDateTimeFormatter`] but the locale and resolution |
794 | | /// algorithm may change certain details of what actually gets resolved. |
795 | | /// |
796 | | /// # Examples |
797 | | /// |
798 | | /// ``` |
799 | | /// use icu::calendar::Gregorian; |
800 | | /// use icu::datetime::{ |
801 | | /// options::{components, length}, |
802 | | /// TypedDateTimeFormatter, |
803 | | /// }; |
804 | | /// use icu::locid::locale; |
805 | | /// |
806 | | /// let options = length::Bag::from_date_style(length::Date::Medium).into(); |
807 | | /// let dtf = TypedDateTimeFormatter::<Gregorian>::try_new( |
808 | | /// &locale!("en").into(), |
809 | | /// options, |
810 | | /// ) |
811 | | /// .expect("Failed to create TypedDateTimeFormatter instance."); |
812 | | /// |
813 | | /// let mut expected_components_bag = components::Bag::default(); |
814 | | /// expected_components_bag.year = Some(components::Year::Numeric); |
815 | | /// expected_components_bag.month = Some(components::Month::Short); |
816 | | /// expected_components_bag.day = Some(components::Day::NumericDayOfMonth); |
817 | | /// |
818 | | /// assert_eq!(dtf.resolve_components(), expected_components_bag); |
819 | | /// ``` |
820 | | #[cfg(feature = "experimental")] |
821 | | pub fn resolve_components(&self) -> crate::options::components::Bag { |
822 | | self.0.resolve_components() |
823 | | } |
824 | | } |
825 | | |
826 | | #[cfg(test)] |
827 | | #[cfg(feature = "serde")] |
828 | | #[cfg(feature = "compiled_data")] |
829 | | mod tests { |
830 | | use super::*; |
831 | | use icu_calendar::DateTime; |
832 | | use icu_calendar::Gregorian; |
833 | | |
834 | | #[test] |
835 | | fn works_with_default_options() { |
836 | | assert_eq!( |
837 | | TypedDateTimeFormatter::<Gregorian>::try_new(Default::default(), Default::default(),) |
838 | | .unwrap() |
839 | | .format_to_string( |
840 | | &DateTime::try_new_gregorian_datetime(2022, 9, 20, 0, 0, 0).unwrap() |
841 | | ), |
842 | | "2022 M09 20 00:00:00" |
843 | | ); |
844 | | } |
845 | | } |