time_fmt/format/
time_format_item.rs1use std::slice::SliceIndex;
2
3use thiserror::Error;
4use time::format_description::{modifier, Component, FormatItem};
5
6use super::spec_parser::Collector;
7
8#[derive(Error, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
9#[non_exhaustive]
10pub enum Error {
11 #[error("Unknown specifier `%{0}`")]
12 UnknownSpecifier(char),
13 #[error("No FormatItem that represent {0}")]
14 NoCorrespondingFormatItem(&'static str),
15}
16
17struct ToFormatItemCollector<'a> {
18 fmt: &'a [u8],
19 items: Vec<FormatItem<'a>>,
20}
21
22impl<'a> ToFormatItemCollector<'a> {
23 fn new(fmt: &'a [u8]) -> Self {
24 Self {
25 fmt,
26 items: Default::default(),
27 }
28 }
29}
30
31impl<'a> Collector for ToFormatItemCollector<'a> {
32 type Output = Vec<FormatItem<'a>>;
33 type Error = Error;
34
35 #[inline]
36 fn day_of_week_name_short(&mut self) -> Result<(), Self::Error> {
37 let mut modifier = modifier::Weekday::default();
38 modifier.repr = modifier::WeekdayRepr::Short;
39 self.items
40 .push(FormatItem::Component(Component::Weekday(modifier)));
41 Ok(())
42 }
43
44 #[inline]
45 fn day_of_week_name_long(&mut self) -> Result<(), Self::Error> {
46 let mut modifier = modifier::Weekday::default();
47 modifier.repr = modifier::WeekdayRepr::Long;
48 self.items
49 .push(FormatItem::Component(Component::Weekday(modifier)));
50 Ok(())
51 }
52
53 #[inline]
54 fn month_name_short(&mut self) -> Result<(), Self::Error> {
55 let mut modifier = modifier::Month::default();
56 modifier.repr = modifier::MonthRepr::Short;
57 self.items
58 .push(FormatItem::Component(Component::Month(modifier)));
59 Ok(())
60 }
61
62 #[inline]
63 fn month_name_long(&mut self) -> Result<(), Self::Error> {
64 let mut modifier = modifier::Month::default();
65 modifier.repr = modifier::MonthRepr::Long;
66 self.items
67 .push(FormatItem::Component(Component::Month(modifier)));
68 Ok(())
69 }
70
71 #[inline]
72 fn year_prefix(&mut self) -> Result<(), Self::Error> {
73 Err(Self::Error::NoCorrespondingFormatItem("%C"))
74 }
75
76 #[inline]
77 fn day_of_month(&mut self) -> Result<(), Self::Error> {
78 let mut modifier = modifier::Day::default();
79 modifier.padding = modifier::Padding::Zero;
80 self.items
81 .push(FormatItem::Component(Component::Day(modifier)));
82 Ok(())
83 }
84
85 #[inline]
86 fn day_of_month_blank(&mut self) -> Result<(), Self::Error> {
87 let mut modifier = modifier::Day::default();
88 modifier.padding = modifier::Padding::Space;
89 self.items
90 .push(FormatItem::Component(Component::Day(modifier)));
91 Ok(())
92 }
93
94 #[inline]
95 fn iso8601_week_based_year_suffix(&mut self) -> Result<(), Self::Error> {
96 let mut modifier = modifier::Year::default();
97 modifier.iso_week_based = true;
98 modifier.repr = modifier::YearRepr::LastTwo;
99 self.items
100 .push(FormatItem::Component(Component::Year(modifier)));
101 Ok(())
102 }
103
104 #[inline]
105 fn iso8601_week_based_year(&mut self) -> Result<(), Self::Error> {
106 let mut modifier = modifier::Year::default();
107 modifier.iso_week_based = true;
108 self.items
109 .push(FormatItem::Component(Component::Year(modifier)));
110 Ok(())
111 }
112
113 #[inline]
114 fn hour_of_day(&mut self) -> Result<(), Self::Error> {
115 let modifier = modifier::Hour::default();
116 self.items
117 .push(FormatItem::Component(Component::Hour(modifier)));
118 Ok(())
119 }
120
121 #[inline]
122 fn hour_of_day_12(&mut self) -> Result<(), Self::Error> {
123 let mut modifier = modifier::Hour::default();
124 modifier.is_12_hour_clock = true;
125 self.items
126 .push(FormatItem::Component(Component::Hour(modifier)));
127 Ok(())
128 }
129
130 #[inline]
131 fn day_of_year(&mut self) -> Result<(), Self::Error> {
132 let modifier = modifier::Ordinal::default();
133 self.items
134 .push(FormatItem::Component(Component::Ordinal(modifier)));
135 Ok(())
136 }
137
138 #[inline]
139 fn hour_of_day_blank(&mut self) -> Result<(), Self::Error> {
140 let mut modifier = modifier::Hour::default();
141 modifier.padding = modifier::Padding::Space;
142 self.items
143 .push(FormatItem::Component(Component::Hour(modifier)));
144 Ok(())
145 }
146
147 #[inline]
148 fn hour_of_day_12_blank(&mut self) -> Result<(), Self::Error> {
149 let mut modifier = modifier::Hour::default();
150 modifier.padding = modifier::Padding::Space;
151 modifier.is_12_hour_clock = true;
152 self.items
153 .push(FormatItem::Component(Component::Hour(modifier)));
154 Ok(())
155 }
156
157 #[inline]
158 fn month_of_year(&mut self) -> Result<(), Self::Error> {
159 let mut modifier = modifier::Month::default();
160 modifier.repr = modifier::MonthRepr::Numerical;
161 self.items
162 .push(FormatItem::Component(Component::Month(modifier)));
163 Ok(())
164 }
165
166 #[inline]
167 fn minute_of_hour(&mut self) -> Result<(), Self::Error> {
168 let modifier = modifier::Minute::default();
169 self.items
170 .push(FormatItem::Component(Component::Minute(modifier)));
171 Ok(())
172 }
173
174 #[inline]
175 fn ampm(&mut self) -> Result<(), Self::Error> {
176 let mut modifier = modifier::Period::default();
177 modifier.is_uppercase = true;
178 self.items
179 .push(FormatItem::Component(Component::Period(modifier)));
180 Ok(())
181 }
182
183 #[inline]
184 fn ampm_lower(&mut self) -> Result<(), Self::Error> {
185 let mut modifier = modifier::Period::default();
186 modifier.is_uppercase = false;
187 self.items
188 .push(FormatItem::Component(Component::Period(modifier)));
189 Ok(())
190 }
191
192 #[inline]
193 fn second_of_minute(&mut self) -> Result<(), Self::Error> {
194 let modifier = modifier::Second::default();
195 self.items
196 .push(FormatItem::Component(Component::Second(modifier)));
197 Ok(())
198 }
199
200 #[inline]
201 fn nanosecond_of_second(&mut self) -> Result<(), Self::Error> {
202 let modifier = modifier::Subsecond::default();
203 self.items
204 .push(FormatItem::Component(Component::Subsecond(modifier)));
205 Ok(())
206 }
207
208 #[inline]
209 fn day_of_week_from_monday_as_1(&mut self) -> Result<(), Self::Error> {
210 let mut modifier = modifier::Weekday::default();
211 modifier.repr = modifier::WeekdayRepr::Monday;
212 modifier.one_indexed = true;
213 self.items
214 .push(FormatItem::Component(Component::Weekday(modifier)));
215 Ok(())
216 }
217
218 #[inline]
219 fn week_number_of_current_year_start_sunday(&mut self) -> Result<(), Self::Error> {
220 let mut modifier = modifier::WeekNumber::default();
221 modifier.repr = modifier::WeekNumberRepr::Sunday;
222 self.items
223 .push(FormatItem::Component(Component::WeekNumber(modifier)));
224 Ok(())
225 }
226
227 #[inline]
228 fn iso8601_week_number(&mut self) -> Result<(), Self::Error> {
229 let mut modifier = modifier::WeekNumber::default();
230 modifier.repr = modifier::WeekNumberRepr::Iso;
231 self.items
232 .push(FormatItem::Component(Component::WeekNumber(modifier)));
233 Ok(())
234 }
235
236 #[inline]
237 fn day_of_week_from_sunday_as_0(&mut self) -> Result<(), Self::Error> {
238 let mut modifier = modifier::Weekday::default();
239 modifier.repr = modifier::WeekdayRepr::Sunday;
240 modifier.one_indexed = false;
241 self.items
242 .push(FormatItem::Component(Component::Weekday(modifier)));
243 Ok(())
244 }
245
246 #[inline]
247 fn week_number_of_current_year_start_monday(&mut self) -> Result<(), Self::Error> {
248 let mut modifier = modifier::WeekNumber::default();
249 modifier.repr = modifier::WeekNumberRepr::Monday;
250 self.items
251 .push(FormatItem::Component(Component::WeekNumber(modifier)));
252 Ok(())
253 }
254
255 #[inline]
256 fn year_suffix(&mut self) -> Result<(), Self::Error> {
257 let mut modifier = modifier::Year::default();
258 modifier.repr = modifier::YearRepr::LastTwo;
259 self.items
260 .push(FormatItem::Component(Component::Year(modifier)));
261 Ok(())
262 }
263
264 #[inline]
265 fn year(&mut self) -> Result<(), Self::Error> {
266 let modifier = modifier::Year::default();
267 self.items
268 .push(FormatItem::Component(Component::Year(modifier)));
269 Ok(())
270 }
271
272 #[inline]
273 fn timezone(&mut self) -> Result<(), Self::Error> {
274 let mut modifier = modifier::OffsetHour::default();
275 modifier.sign_is_mandatory = true;
276 self.items
277 .push(FormatItem::Component(Component::OffsetHour(modifier)));
278 let modifier = modifier::OffsetMinute::default();
279 self.items
280 .push(FormatItem::Component(Component::OffsetMinute(modifier)));
281 Ok(())
282 }
283
284 #[inline]
285 fn timezone_name(&mut self) -> Result<(), Self::Error> {
286 Err(Self::Error::NoCorrespondingFormatItem("timezone name"))
287 }
288
289 #[inline]
290 fn static_str(&mut self, s: &'static str) -> Result<(), Self::Error> {
291 self.items.push(FormatItem::Literal(s.as_bytes()));
292 Ok(())
293 }
294
295 #[inline]
296 fn literal(
297 &mut self,
298 _lit: &str,
299 fmt_span: impl SliceIndex<[u8], Output = [u8]>,
300 ) -> Result<(), Self::Error> {
301 self.items.push(FormatItem::Literal(&self.fmt[fmt_span]));
302 Ok(())
303 }
304
305 #[inline]
306 fn unknown(&mut self, specifier: char) -> Result<(), Self::Error> {
307 Err(Self::Error::UnknownSpecifier(specifier))
308 }
309
310 #[inline]
311 fn output(self) -> Result<Self::Output, Self::Error> {
312 Ok(self.items)
313 }
314}
315
316pub fn parse_to_format_item(fmt: &str) -> Result<Vec<FormatItem>, Error> {
317 let collector = ToFormatItemCollector::new(fmt.as_bytes());
318 super::spec_parser::parse_conversion_specifications(fmt, collector)
319}
320
321#[cfg(test)]
322mod tests {
323 use time::macros::datetime;
324
325 use super::parse_to_format_item;
326
327 #[test]
328 fn it_works() -> Result<(), super::Error> {
329 assert_eq!(
330 parse_to_format_item("%Y-%m-%d")?,
331 parse_to_format_item("%F")?,
332 );
333 Ok(())
334 }
335
336 #[test]
337 fn parse_primitive_datetime() -> Result<(), Box<dyn std::error::Error>> {
338 let format_items = parse_to_format_item("%Y-%m-%d %H:%M:%S")?;
339 assert_eq!(
340 datetime!(2012-05-21 12:09:14).format(&format_items)?,
341 "2012-05-21 12:09:14"
342 );
343 Ok(())
344 }
345
346 #[test]
347 fn parse_offset_datetime() -> Result<(), Box<dyn std::error::Error>> {
348 let format_items = parse_to_format_item("%Y-%m-%d %H:%M:%S %z")?;
349 assert_eq!(
350 datetime!(2012-05-21 12:09:14 +9:00).format(&format_items)?,
351 "2012-05-21 12:09:14 +0900"
352 );
353 Ok(())
354 }
355}