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}