🛈 Note: This is pre-release documentation for the upcoming tracing 0.2.0 ecosystem.

For the release documentation, please see docs.rs, instead.

tracing_subscriber/fmt/time/
time_crate.rs

1use crate::fmt::{format::Writer, time::FormatTime, writer::WriteAdaptor};
2use std::fmt;
3use time::{format_description::well_known, formatting::Formattable, OffsetDateTime};
4
5/// Formats the current [local time] using a [formatter] from the [`time` crate].
6///
7/// To format the current [UTC time] instead, use the [`UtcTime`] type.
8///
9/// <div class="example-wrap" style="display:inline-block">
10/// <pre class="compile_fail" style="white-space:normal;font:inherit;">
11///     <strong>Warning</strong>: The <a href = "https://docs.rs/time/0.3/time/"><code>time</code>
12///     crate</a> must be compiled with <code>--cfg unsound_local_offset</code> in order to use
13///     local timestamps. When this cfg is not enabled, local timestamps cannot be recorded, and
14///     events will be logged without timestamps.
15///
16///    See the <a href="https://docs.rs/time/0.3.4/time/#feature-flags"><code>time</code>
17///    documentation</a> for more details.
18/// </pre></div>
19///
20/// [local time]: https://docs.rs/time/0.3/time/struct.OffsetDateTime.html#method.now_local
21/// [UTC time]: https://docs.rs/time/0.3/time/struct.OffsetDateTime.html#method.now_utc
22/// [formatter]: https://docs.rs/time/0.3/time/formatting/trait.Formattable.html
23/// [`time` crate]: https://docs.rs/time/0.3/time/
24#[derive(Clone, Debug)]
25#[cfg_attr(
26    docsrs,
27    doc(cfg(all(unsound_local_offset, feature = "time", feature = "local-time")))
28)]
29#[cfg(feature = "local-time")]
30pub struct LocalTime<F> {
31    format: F,
32}
33
34/// Formats the current [UTC time] using a [formatter] from the [`time` crate].
35///
36/// To format the current [local time] instead, use the [`LocalTime`] type.
37///
38/// [local time]: https://docs.rs/time/0.3/time/struct.OffsetDateTime.html#method.now_local
39/// [UTC time]: https://docs.rs/time/0.3/time/struct.OffsetDateTime.html#method.now_utc
40/// [formatter]: https://docs.rs/time/0.3/time/formatting/trait.Formattable.html
41/// [`time` crate]: https://docs.rs/time/0.3/time/
42#[cfg_attr(docsrs, doc(cfg(feature = "time")))]
43#[derive(Clone, Debug)]
44pub struct UtcTime<F> {
45    format: F,
46}
47
48// === impl LocalTime ===
49
50#[cfg(feature = "local-time")]
51impl LocalTime<well_known::Rfc3339> {
52    /// Returns a formatter that formats the current [local time] in the
53    /// [RFC 3339] format (a subset of the [ISO 8601] timestamp format).
54    ///
55    /// # Examples
56    ///
57    /// ```
58    /// use tracing_subscriber::fmt::{self, time};
59    ///
60    /// let collector = tracing_subscriber::fmt()
61    ///     .with_timer(time::LocalTime::rfc_3339());
62    /// # drop(collector);
63    /// ```
64    ///
65    /// [local time]: https://docs.rs/time/0.3/time/struct.OffsetDateTime.html#method.now_local
66    /// [RFC 3339]: https://datatracker.ietf.org/doc/html/rfc3339
67    /// [ISO 8601]: https://en.wikipedia.org/wiki/ISO_8601
68    pub fn rfc_3339() -> Self {
69        Self::new(well_known::Rfc3339)
70    }
71}
72
73#[cfg(feature = "local-time")]
74impl<F: Formattable> LocalTime<F> {
75    /// Returns a formatter that formats the current [local time] using the
76    /// [`time` crate] with the provided provided format. The format may be any
77    /// type that implements the [`Formattable`] trait.
78    ///
79    ///
80    /// <div class="example-wrap" style="display:inline-block">
81    /// <pre class="compile_fail" style="white-space:normal;font:inherit;">
82    ///     <strong>Warning</strong>: The <a href = "https://docs.rs/time/0.3/time/">
83    ///     <code>time</code> crate</a> must be compiled with <code>--cfg
84    ///     unsound_local_offset</code> in order to use local timestamps. When this
85    ///     cfg is not enabled, local timestamps cannot be recorded, and
86    ///     events will be logged without timestamps.
87    ///
88    ///    See the <a href="https://docs.rs/time/0.3.4/time/#feature-flags">
89    ///    <code>time</code> documentation</a> for more details.
90    /// </pre></div>
91    ///
92    /// Typically, the format will be a format description string, or one of the
93    /// `time` crate's [well-known formats].
94    ///
95    /// If the format description is statically known, then the
96    /// [`format_description!`] macro should be used. This is identical to the
97    /// [`time::format_description::parse`] method, but runs at compile-time,
98    /// throwing an error if the format description is invalid. If the desired format
99    /// is not known statically (e.g., a user is providing a format string), then the
100    /// [`time::format_description::parse`] method should be used. Note that this
101    /// method is fallible.
102    ///
103    /// See the [`time` book] for details on the format description syntax.
104    ///
105    /// # Examples
106    ///
107    /// Using the [`format_description!`] macro:
108    ///
109    /// ```
110    /// use tracing_subscriber::fmt::{self, time::LocalTime};
111    /// use time::macros::format_description;
112    ///
113    /// let timer = LocalTime::new(format_description!("[hour]:[minute]:[second]"));
114    /// let collector = tracing_subscriber::fmt()
115    ///     .with_timer(timer);
116    /// # drop(collector);
117    /// ```
118    ///
119    /// Using [`time::format_description::parse`]:
120    ///
121    /// ```
122    /// use tracing_subscriber::fmt::{self, time::LocalTime};
123    ///
124    /// let time_format = time::format_description::parse("[hour]:[minute]:[second]")
125    ///     .expect("format string should be valid!");
126    /// let timer = LocalTime::new(time_format);
127    /// let collector = tracing_subscriber::fmt()
128    ///     .with_timer(timer);
129    /// # drop(collector);
130    /// ```
131    ///
132    /// Using the [`format_description!`] macro requires enabling the `time`
133    /// crate's "macros" feature flag.
134    ///
135    /// Using a [well-known format][well-known formats] (this is equivalent to
136    /// [`LocalTime::rfc_3339`]):
137    ///
138    /// ```
139    /// use tracing_subscriber::fmt::{self, time::LocalTime};
140    ///
141    /// let timer = LocalTime::new(time::format_description::well_known::Rfc3339);
142    /// let collector = tracing_subscriber::fmt()
143    ///     .with_timer(timer);
144    /// # drop(collector);
145    /// ```
146    ///
147    /// [local time]: https://docs.rs/time/latest/time/struct.OffsetDateTime.html#method.now_local
148    /// [`time` crate]: https://docs.rs/time/0.3/time/
149    /// [`Formattable`]: https://docs.rs/time/0.3/time/formatting/trait.Formattable.html
150    /// [well-known formats]: https://docs.rs/time/0.3/time/format_description/well_known/index.html
151    /// [`format_description!`]: https://docs.rs/time/0.3/time/macros/macro.format_description.html
152    /// [`time::format_description::parse`]: https://docs.rs/time/0.3/time/format_description/fn.parse.html
153    /// [`time` book]: https://time-rs.github.io/book/api/format-description.html
154    pub fn new(format: F) -> Self {
155        Self { format }
156    }
157}
158
159#[cfg(feature = "local-time")]
160impl<F> FormatTime for LocalTime<F>
161where
162    F: Formattable,
163{
164    fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result {
165        let now = OffsetDateTime::now_local().map_err(|_| fmt::Error)?;
166        format_datetime(now, w, &self.format)
167    }
168}
169
170#[cfg(feature = "local-time")]
171impl<F> Default for LocalTime<F>
172where
173    F: Formattable + Default,
174{
175    fn default() -> Self {
176        Self::new(F::default())
177    }
178}
179
180// === impl UtcTime ===
181
182impl UtcTime<well_known::Rfc3339> {
183    /// Returns a formatter that formats the current [UTC time] in the
184    /// [RFC 3339] format, which is a subset of the [ISO 8601] timestamp format.
185    ///
186    /// # Examples
187    ///
188    /// ```
189    /// use tracing_subscriber::fmt::{self, time};
190    ///
191    /// let collector = tracing_subscriber::fmt()
192    ///     .with_timer(time::UtcTime::rfc_3339());
193    /// # drop(collector);
194    /// ```
195    ///
196    /// [local time]: https://docs.rs/time/0.3/time/struct.OffsetDateTime.html#method.now_utc
197    /// [RFC 3339]: https://datatracker.ietf.org/doc/html/rfc3339
198    /// [ISO 8601]: https://en.wikipedia.org/wiki/ISO_8601
199    pub fn rfc_3339() -> Self {
200        Self::new(well_known::Rfc3339)
201    }
202}
203
204impl<F: Formattable> UtcTime<F> {
205    /// Returns a formatter that formats the current [UTC time] using the
206    /// [`time` crate], with the provided provided format. The format may be any
207    /// type that implements the [`Formattable`] trait.
208    ///
209    /// Typically, the format will be a format description string, or one of the
210    /// `time` crate's [well-known formats].
211    ///
212    /// If the format description is statically known, then the
213    /// [`format_description!`] macro should be used. This is identical to the
214    /// [`time::format_description::parse`] method, but runs at compile-time,
215    /// failing  an error if the format description is invalid. If the desired format
216    /// is not known statically (e.g., a user is providing a format string), then the
217    /// [`time::format_description::parse`] method should be used. Note that this
218    /// method is fallible.
219    ///
220    /// See the [`time` book] for details on the format description syntax.
221    ///
222    /// # Examples
223    ///
224    /// Using the [`format_description!`] macro:
225    ///
226    /// ```
227    /// use tracing_subscriber::fmt::{self, time::UtcTime};
228    /// use time::macros::format_description;
229    ///
230    /// let timer = UtcTime::new(format_description!("[hour]:[minute]:[second]"));
231    /// let collector = tracing_subscriber::fmt()
232    ///     .with_timer(timer);
233    /// # drop(collector);
234    /// ```
235    ///
236    /// Using the [`format_description!`] macro requires enabling the `time`
237    /// crate's "macros" feature flag.
238    ///
239    /// Using [`time::format_description::parse`]:
240    ///
241    /// ```
242    /// use tracing_subscriber::fmt::{self, time::UtcTime};
243    ///
244    /// let time_format = time::format_description::parse("[hour]:[minute]:[second]")
245    ///     .expect("format string should be valid!");
246    /// let timer = UtcTime::new(time_format);
247    /// let collector = tracing_subscriber::fmt()
248    ///     .with_timer(timer);
249    /// # drop(collector);
250    /// ```
251    ///
252    /// Using a [well-known format][well-known formats] (this is equivalent to
253    /// [`UtcTime::rfc_3339`]):
254    ///
255    /// ```
256    /// use tracing_subscriber::fmt::{self, time::UtcTime};
257    ///
258    /// let timer = UtcTime::new(time::format_description::well_known::Rfc3339);
259    /// let collector = tracing_subscriber::fmt()
260    ///     .with_timer(timer);
261    /// # drop(collector);
262    /// ```
263    ///
264    /// [UTC time]: https://docs.rs/time/latest/time/struct.OffsetDateTime.html#method.now_utc
265    /// [`time` crate]: https://docs.rs/time/0.3/time/
266    /// [`Formattable`]: https://docs.rs/time/0.3/time/formatting/trait.Formattable.html
267    /// [well-known formats]: https://docs.rs/time/0.3/time/format_description/well_known/index.html
268    /// [`format_description!`]: https://docs.rs/time/0.3/time/macros/macro.format_description.html
269    /// [`time::format_description::parse`]: https://docs.rs/time/0.3/time/format_description/fn.parse.html
270    /// [`time` book]: https://time-rs.github.io/book/api/format-description.html
271    pub fn new(format: F) -> Self {
272        Self { format }
273    }
274}
275
276impl<F> FormatTime for UtcTime<F>
277where
278    F: Formattable,
279{
280    fn format_time(&self, w: &mut Writer<'_>) -> fmt::Result {
281        format_datetime(OffsetDateTime::now_utc(), w, &self.format)
282    }
283}
284
285impl<F> Default for UtcTime<F>
286where
287    F: Formattable + Default,
288{
289    fn default() -> Self {
290        Self::new(F::default())
291    }
292}
293
294fn format_datetime(
295    now: OffsetDateTime,
296    into: &mut Writer<'_>,
297    fmt: &impl Formattable,
298) -> fmt::Result {
299    let mut into = WriteAdaptor::new(into);
300    now.format_into(&mut into, fmt)
301        .map_err(|_| fmt::Error)
302        .map(|_| ())
303}