Skip to main content

deep_time/dt/
formatting.rs

1use crate::{Dt, DtErr, Scale};
2use alloc::string::String;
3
4impl Dt {
5    /// Returns this instant as an **RFC 3339** / ISO 8601 timestamp in **UTC**
6    /// with the `Z` suffix.
7    ///
8    /// - Always uses UTC (`Z` = Zulu = UTC).
9    /// - Default = 9 digits (nanoseconds) but **automatically trims trailing zeros**.
10    /// - If fractional part is zero → no decimal point at all (e.g. `...45Z`).
11    /// - Example: `"2024-03-14T15:30:45.123Z"`
12    #[inline]
13    pub fn to_str_rfc3339(&self, current: Scale) -> Result<String, DtErr> {
14        self.to_str_rfc3339_nf(current, 9)
15    }
16
17    /// Same as [`Dt::to_str_rfc3339`](../struct.Dt.html#method.to_str_rfc3339) but
18    /// with a configurable maximum number of fractional digits (0–18). Trailing zeros are
19    /// always trimmed.
20    pub fn to_str_rfc3339_nf(&self, current: Scale, max_precision: usize) -> Result<String, DtErr> {
21        let prec = max_precision.min(18);
22        // Uses the formatter with the `~` "trim trailing zeros" flag.
23        // The formatter already handles:
24        //   - correct 4-digit years (with sign) for |yr| < 10000
25        //   - full-width years otherwise
26        //   - suppressing the decimal point entirely when the trimmed fraction is zero
27        let fmt = alloc::format!("%Y-%m-%dT%H:%M:%S%.{}~fZ", prec);
28        self.to_str_with_offset(current, &fmt, 0)
29    }
30
31    /// **ISO 8601 / RFC 3339** with **actual offset** (modern `+00:00` style).
32    ///
33    /// - Uses colon-separated offset (`%:z`) instead of forcing `Z`.
34    /// - Still trims trailing zeros in the fractional part.
35    /// - Example: `"2025-04-16T14:30:45.123+00:00"`
36    #[inline]
37    pub fn to_str_iso8601(&self, current: Scale) -> Result<String, DtErr> {
38        self.to_str_with_offset(current, "%Y-%m-%dT%H:%M:%S%.~f%:z", 0)
39    }
40
41    /// **Compact ISO 8601 basic format** (no separators).
42    ///
43    /// - Useful for filenames, URLs, database keys, etc.
44    /// - Example: `"20250416T143045.123456789Z"`
45    #[inline]
46    pub fn to_str_iso8601_basic(&self, current: Scale) -> Result<String, DtErr> {
47        self.to_str_with_offset(current, "%Y%m%dT%H%M%S%.~fZ", 0)
48    }
49
50    /// **HTTP-date** format (RFC 7231 / RFC 1123) — **always in GMT**.
51    ///
52    /// This is the format used in `Date`, `Expires`, `Last-Modified` headers.
53    /// Example: `"Wed, 16 Apr 2025 14:30:45 GMT"`
54    #[inline]
55    pub fn to_str_http(&self, current: Scale) -> Result<String, DtErr> {
56        self.to_str_with_offset(current, "%a, %d %b %Y %H:%M:%S GMT", 0)
57    }
58
59    /// **RFC 2822** date format (used in email `Date` headers).
60    ///
61    /// Example: `"Wed, 16 Apr 2025 14:30:45 +0000"`
62    #[inline]
63    pub fn to_str_rfc2822(&self, current: Scale) -> Result<String, DtErr> {
64        self.to_str_with_offset(current, "%a, %d %b %Y %H:%M:%S %z", 0)
65    }
66
67    /// **ISO 8601 week date**.
68    ///
69    /// Example: `"2025-W16-3"` (year-week-day)
70    #[inline]
71    pub fn to_str_iso_week_date(&self, current: Scale) -> Result<String, DtErr> {
72        self.to_str_with_offset(current, "%G-W%V-%u", 0)
73    }
74
75    /// Just the **ISO date** part (no time).
76    ///
77    /// Example: `"2025-04-16"`
78    #[inline]
79    pub fn to_str_iso_date(&self, current: Scale) -> Result<String, DtErr> {
80        self.to_str_with_offset(current, "%Y-%m-%d", 0)
81    }
82
83    /// Just the **time** part with fractional seconds (trimmed).
84    ///
85    /// Example: `"14:30:45.123456789"`
86    #[inline]
87    pub fn to_str_iso_time(&self, current: Scale) -> Result<String, DtErr> {
88        self.to_str_with_offset(current, "%H:%M:%S%.~f", 0)
89    }
90}