Skip to main content

fluent_datetime/
length.rs

1//! Length is a model of encoding information on how to format date and time by
2//! specifying the preferred length ! of date and time fields.
3//!
4//! It is intended to represent dateStyle and timeStyle from
5//! ECMA 402 DateTimeFormat constructor options.
6//!
7//! If either of the fields is omitted, the value will be formatted according to
8//! the pattern associated with the ! preferred length of the present field in a
9//! given locale.
10//!
11//! If both fields are present, both parts of the value will be formatted and an
12//! additional connector pattern ! will be used to construct a full result.
13//! The type of the connector is determined by the length of the [`Date`] field.
14
15// Restored from icu_datetime 1
16// https://docs.rs/icu_datetime/1.5.1/src/icu_datetime/options/length.rs.html
17
18use icu_datetime::fieldsets::builder::{DateFields, FieldSetBuilder, ZoneStyle};
19use icu_datetime::options::{Length, TimePrecision};
20
21/// Represents different lengths a date part can be formatted into.
22/// Each length has associated best pattern for it for a given locale.
23///
24/// The available lengths correspond to [`UTS #35: Unicode LDML 4. Dates`], section 2.4 [`Element dateFormats`].
25///
26/// [`UTS #35: Unicode LDML 4. Dates`]: https://unicode.org/reports/tr35/tr35-dates.html
27/// [`Element dateFormats`]: https://unicode.org/reports/tr35/tr35-dates.html#dateFormats
28#[derive(Debug, Clone, Copy, PartialEq)]
29#[non_exhaustive]
30pub enum Date {
31    /// Full length, usually with weekday name.
32    ///
33    /// # Examples
34    ///
35    /// * Tuesday, January 21, 2020 (`en-US`)
36    /// * wtorek, 21 stycznia, 2020 (`pl`)
37    /// * الثلاثاء، ٢١ يناير ٢٠٢٠ (`ar`)
38    /// * вторник, 21 января 2020 г. (`ru`)
39    /// * 2020年1月21日火曜日 (`ja`)
40    Full,
41    /// Long length, with wide month name.
42    ///
43    /// # Examples
44    ///
45    /// * September 10, 2020 (`en-US`)
46    /// * 10 września 2020 (`pl`)
47    /// * ١٠ سبتمبر ٢٠٢٠ (`ar`)
48    /// * 10 сентября 2020 г. (`ru`)
49    /// * 2020年9月10日 (`ja`)
50    Long,
51    /// Medium length.
52    ///
53    /// # Examples
54    ///
55    /// * Feb 20, 2020 (`en-US`)
56    /// * 20 lut 2020 (`pl`)
57    /// * ٢٠‏/٠٢‏/٢٠٢٠ (`ar`)
58    /// * 20 февр. 2020 г. (`ru`)
59    /// * 2020/02/20 (`ja`)
60    Medium,
61    /// Short length, usually with numeric month.
62    ///
63    /// # Examples
64    ///
65    /// * 1/30/20 (`en-US`)
66    /// * 30.01.2020 (`pl`)
67    /// * ٣٠‏/١‏/٢٠٢٠ (`ar`)
68    /// * 30.01.2020 (`ru`)
69    /// * 2020/01/30 (`ja`)
70    Short,
71}
72
73/// Represents different length lengths a time part can be formatted into.
74/// Each length has associated best pattern for it for a given locale.
75///
76/// The available lengths correspond to [`UTS #35: Unicode LDML 4. Dates`], section 2.4 [`Element timeFormats`].
77///
78/// [`UTS #35: Unicode LDML 4. Dates`]: https://unicode.org/reports/tr35/tr35-dates.html
79/// [`Element dateFormats`]: https://unicode.org/reports/tr35/tr35-dates.html#timeFormats
80#[derive(Debug, Clone, Copy, PartialEq)]
81#[non_exhaustive]
82pub enum Time {
83    /// Full length, with spelled out time zone name.
84    ///
85    /// # Examples
86    ///
87    /// * 8:25:07 AM Pacific Standard Time (`en-US`)
88    /// * 08:25:07 czas pacyficzny standardowy (`pl`)
89    /// * ٨:٢٥:٠٧ ص توقيت المحيط الهادي الرسمي (`ar`)
90    /// * 08:25:07 Тихоокеанское стандартное время (`ru`)
91    /// * 8時25分07秒 アメリカ太平洋標準時 (`ja`)
92    Full,
93    /// Full length, usually with short time-zone code.
94    ///
95    /// # Examples
96    ///
97    /// * 8:25:07 AM PST (`en-US`)
98    /// * 08:25:07 GMT-8 (`pl`)
99    /// * ٨:٢٥:٠٧ ص غرينتش-٨ (`ar`)
100    /// * 08:25:07 GMT-8 (`ru`)
101    /// * 8:25:07 GMT-8 (`ja`)
102    Long,
103    /// Full length, usually with seconds.
104    ///
105    /// # Examples
106    ///
107    /// * 8:25:07 AM (`en-US`)
108    /// * 08:25:07 (`pl`)
109    /// * ٨:٢٥:٠٧ ص (`ar`)
110    /// * 08:25:07 (`ru`)
111    /// * 8:25:07 (`ja`)
112    Medium,
113    /// Full length, usually without seconds.
114    ///
115    /// # Examples
116    ///
117    /// * 8:25 AM (`en-US`)
118    /// * 08:25 (`pl`)
119    /// * ٨:٢٥ ص (`ar`)
120    /// * 08:25 (`ru`)
121    /// * 8:25 (`ja`)
122    Short,
123}
124
125#[derive(Debug, Clone, Copy, PartialEq)]
126#[non_exhaustive]
127pub(super) struct Bag {
128    /// Configure the date part of the datetime.
129    pub date: Option<Date>,
130    /// Configure the time part of the datetime.
131    pub time: Option<Time>,
132}
133
134impl Bag {
135    /// Constructs a `Bag` with all fields set to `None`.
136    ///
137    /// Note that the [`Default`] implementation returns medium date and time options
138    pub fn empty() -> Self {
139        Self {
140            date: None,
141            time: None,
142        }
143    }
144
145    // For a Copy type, is it as_ or to_?
146    // https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv
147    pub(super) fn to_fieldset_builder(self) -> FieldSetBuilder {
148        let (date, time) = if self == Self::empty() {
149            (Some(Date::Short), None)
150        } else {
151            (self.date, self.time)
152        };
153        let mut builder = FieldSetBuilder::new();
154        if let Some(date) = date {
155            builder.date_fields = Some(if date == Date::Full {
156                DateFields::YMDE
157            } else {
158                DateFields::YMD
159            });
160            builder.length = Some(match date {
161                Date::Full | Date::Long => Length::Long,
162                Date::Medium => Length::Medium,
163                Date::Short => Length::Short,
164            });
165        }
166        if let Some(time) = time {
167            builder.time_precision = Some(if time == Time::Short {
168                TimePrecision::Minute
169            } else {
170                TimePrecision::Second
171            });
172            if time == Time::Full {
173                builder.zone_style = Some(ZoneStyle::SpecificLong);
174            } else if time == Time::Long {
175                builder.zone_style = Some(ZoneStyle::SpecificShort)
176            }
177        }
178        builder
179    }
180}