• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::fmt::format::Writer;
2 use crate::fmt::time::FormatTime;
3 
4 use std::sync::Arc;
5 
6 /// Formats [local time]s and [UTC time]s with `FormatTime` implementations
7 /// that use the [`chrono` crate].
8 ///
9 /// [local time]: [`chrono::offset::Local`]
10 /// [UTC time]: [`chrono::offset::Utc`]
11 /// [`chrono` crate]: [`chrono`]
12 
13 /// Formats the current [local time] using a [formatter] from the [`chrono`] crate.
14 ///
15 /// [local time]: chrono::Local::now()
16 /// [formatter]: chrono::format
17 #[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
18 #[derive(Debug, Clone, Eq, PartialEq, Default)]
19 pub struct ChronoLocal {
20     format: Arc<ChronoFmtType>,
21 }
22 
23 impl ChronoLocal {
24     /// Format the time using the [`RFC 3339`] format
25     /// (a subset of [`ISO 8601`]).
26     ///
27     /// [`RFC 3339`]: https://tools.ietf.org/html/rfc3339
28     /// [`ISO 8601`]: https://en.wikipedia.org/wiki/ISO_8601
rfc_3339() -> Self29     pub fn rfc_3339() -> Self {
30         Self {
31             format: Arc::new(ChronoFmtType::Rfc3339),
32         }
33     }
34 
35     /// Format the time using the given format string.
36     ///
37     /// See [`chrono::format::strftime`] for details on the supported syntax.
new(format_string: String) -> Self38     pub fn new(format_string: String) -> Self {
39         Self {
40             format: Arc::new(ChronoFmtType::Custom(format_string)),
41         }
42     }
43 }
44 
45 impl FormatTime for ChronoLocal {
format_time(&self, w: &mut Writer<'_>) -> alloc::fmt::Result46     fn format_time(&self, w: &mut Writer<'_>) -> alloc::fmt::Result {
47         let t = chrono::Local::now();
48         match self.format.as_ref() {
49             ChronoFmtType::Rfc3339 => {
50                 use chrono::format::{Fixed, Item};
51                 write!(
52                     w,
53                     "{}",
54                     t.format_with_items(core::iter::once(Item::Fixed(Fixed::RFC3339)))
55                 )
56             }
57             ChronoFmtType::Custom(fmt) => {
58                 write!(w, "{}", t.format(fmt))
59             }
60         }
61     }
62 }
63 
64 /// Formats the current [UTC time] using a [formatter] from the [`chrono`] crate.
65 ///
66 /// [UTC time]: chrono::Utc::now()
67 /// [formatter]: chrono::format
68 #[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
69 #[derive(Debug, Clone, Eq, PartialEq, Default)]
70 pub struct ChronoUtc {
71     format: Arc<ChronoFmtType>,
72 }
73 
74 impl ChronoUtc {
75     /// Format the time using the [`RFC 3339`] format
76     /// (a subset of [`ISO 8601`]).
77     ///
78     /// [`RFC 3339`]: https://tools.ietf.org/html/rfc3339
79     /// [`ISO 8601`]: https://en.wikipedia.org/wiki/ISO_8601
rfc_3339() -> Self80     pub fn rfc_3339() -> Self {
81         Self {
82             format: Arc::new(ChronoFmtType::Rfc3339),
83         }
84     }
85 
86     /// Format the time using the given format string.
87     ///
88     /// See [`chrono::format::strftime`] for details on the supported syntax.
new(format_string: String) -> Self89     pub fn new(format_string: String) -> Self {
90         Self {
91             format: Arc::new(ChronoFmtType::Custom(format_string)),
92         }
93     }
94 }
95 
96 impl FormatTime for ChronoUtc {
format_time(&self, w: &mut Writer<'_>) -> alloc::fmt::Result97     fn format_time(&self, w: &mut Writer<'_>) -> alloc::fmt::Result {
98         let t = chrono::Utc::now();
99         match self.format.as_ref() {
100             ChronoFmtType::Rfc3339 => w.write_str(&t.to_rfc3339()),
101             ChronoFmtType::Custom(fmt) => w.write_str(&format!("{}", t.format(fmt))),
102         }
103     }
104 }
105 
106 /// The RFC 3339 format is used by default but a custom format string
107 /// can be used. See [`chrono::format::strftime`]for details on
108 /// the supported syntax.
109 ///
110 /// [`chrono::format::strftime`]: https://docs.rs/chrono/0.4.9/chrono/format/strftime/index.html
111 #[derive(Debug, Clone, Eq, PartialEq)]
112 #[derive(Default)]
113 enum ChronoFmtType {
114     /// Format according to the RFC 3339 convention.
115     #[default]
116     Rfc3339,
117     /// Format according to a custom format string.
118     Custom(String),
119 }
120 
121 
122 #[cfg(test)]
123 mod tests {
124     use crate::fmt::format::Writer;
125     use crate::fmt::time::FormatTime;
126 
127     use std::sync::Arc;
128 
129     use super::ChronoFmtType;
130     use super::ChronoLocal;
131     use super::ChronoUtc;
132 
133     #[test]
test_chrono_format_time_utc_default()134     fn test_chrono_format_time_utc_default() {
135         let mut buf = String::new();
136         let mut dst: Writer<'_> = Writer::new(&mut buf);
137         assert!(FormatTime::format_time(&ChronoUtc::default(), &mut dst).is_ok());
138         // e.g. `buf` contains "2023-08-18T19:05:08.662499+00:00"
139         assert!(chrono::DateTime::parse_from_str(&buf, "%FT%H:%M:%S%.6f%z").is_ok());
140     }
141 
142     #[test]
test_chrono_format_time_utc_custom()143     fn test_chrono_format_time_utc_custom() {
144         let fmt = ChronoUtc {
145             format: Arc::new(ChronoFmtType::Custom("%a %b %e %T %Y".to_owned())),
146         };
147         let mut buf = String::new();
148         let mut dst: Writer<'_> = Writer::new(&mut buf);
149         assert!(FormatTime::format_time(&fmt, &mut dst).is_ok());
150         // e.g. `buf` contains "Wed Aug 23 15:53:23 2023"
151         assert!(chrono::NaiveDateTime::parse_from_str(&buf, "%a %b %e %T %Y").is_ok());
152     }
153 
154     #[test]
test_chrono_format_time_local_default()155     fn test_chrono_format_time_local_default() {
156         let mut buf = String::new();
157         let mut dst: Writer<'_> = Writer::new(&mut buf);
158         assert!(FormatTime::format_time(&ChronoLocal::default(), &mut dst).is_ok());
159         // e.g. `buf` contains "2023-08-18T14:59:08.662499-04:00".
160         assert!(chrono::DateTime::parse_from_str(&buf, "%FT%H:%M:%S%.6f%z").is_ok());
161     }
162 
163     #[test]
test_chrono_format_time_local_custom()164     fn test_chrono_format_time_local_custom() {
165         let fmt = ChronoLocal {
166             format: Arc::new(ChronoFmtType::Custom("%a %b %e %T %Y".to_owned())),
167         };
168         let mut buf = String::new();
169         let mut dst: Writer<'_> = Writer::new(&mut buf);
170         assert!(FormatTime::format_time(&fmt, &mut dst).is_ok());
171         // e.g. `buf` contains "Wed Aug 23 15:55:46 2023".
172         assert!(chrono::NaiveDateTime::parse_from_str(&buf, "%a %b %e %T %Y").is_ok());
173     }
174 }
175