time/format_description/
modifier.rs

1//! Various modifiers for components.
2
3use core::num::NonZeroU16;
4
5// region: date modifiers
6/// Day of the month.
7#[non_exhaustive]
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub struct Day {
10    /// The padding to obtain the minimum width.
11    pub padding: Padding,
12}
13
14/// The representation of a month.
15#[non_exhaustive]
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum MonthRepr {
18    /// The number of the month (January is 1, December is 12).
19    Numerical,
20    /// The long form of the month name (e.g. "January").
21    Long,
22    /// The short form of the month name (e.g. "Jan").
23    Short,
24}
25
26/// Month of the year.
27#[non_exhaustive]
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29pub struct Month {
30    /// The padding to obtain the minimum width.
31    pub padding: Padding,
32    /// What form of representation should be used?
33    pub repr: MonthRepr,
34    /// Is the value case sensitive when parsing?
35    pub case_sensitive: bool,
36}
37
38/// Ordinal day of the year.
39#[non_exhaustive]
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41pub struct Ordinal {
42    /// The padding to obtain the minimum width.
43    pub padding: Padding,
44}
45
46/// The representation used for the day of the week.
47#[non_exhaustive]
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49pub enum WeekdayRepr {
50    /// The short form of the weekday (e.g. "Mon").
51    Short,
52    /// The long form of the weekday (e.g. "Monday").
53    Long,
54    /// A numerical representation using Sunday as the first day of the week.
55    ///
56    /// Sunday is either 0 or 1, depending on the other modifier's value.
57    Sunday,
58    /// A numerical representation using Monday as the first day of the week.
59    ///
60    /// Monday is either 0 or 1, depending on the other modifier's value.
61    Monday,
62}
63
64/// Day of the week.
65#[non_exhaustive]
66#[derive(Debug, Clone, Copy, PartialEq, Eq)]
67pub struct Weekday {
68    /// What form of representation should be used?
69    pub repr: WeekdayRepr,
70    /// When using a numerical representation, should it be zero or one-indexed?
71    pub one_indexed: bool,
72    /// Is the value case sensitive when parsing?
73    pub case_sensitive: bool,
74}
75
76/// The representation used for the week number.
77#[non_exhaustive]
78#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79pub enum WeekNumberRepr {
80    /// Week 1 is the week that contains January 4.
81    Iso,
82    /// Week 1 begins on the first Sunday of the calendar year.
83    Sunday,
84    /// Week 1 begins on the first Monday of the calendar year.
85    Monday,
86}
87
88/// Week within the year.
89#[non_exhaustive]
90#[derive(Debug, Clone, Copy, PartialEq, Eq)]
91pub struct WeekNumber {
92    /// The padding to obtain the minimum width.
93    pub padding: Padding,
94    /// What kind of representation should be used?
95    pub repr: WeekNumberRepr,
96}
97
98/// The representation used for a year value.
99#[non_exhaustive]
100#[derive(Debug, Clone, Copy, PartialEq, Eq)]
101pub enum YearRepr {
102    /// The full value of the year.
103    Full,
104    /// Only the last two digits of the year.
105    LastTwo,
106}
107
108/// Year of the date.
109#[non_exhaustive]
110#[derive(Debug, Clone, Copy, PartialEq, Eq)]
111pub struct Year {
112    /// The padding to obtain the minimum width.
113    pub padding: Padding,
114    /// What kind of representation should be used?
115    pub repr: YearRepr,
116    /// Whether the value is based on the ISO week number or the Gregorian calendar.
117    pub iso_week_based: bool,
118    /// Whether the `+` sign is present when a positive year contains fewer than five digits.
119    pub sign_is_mandatory: bool,
120}
121// endregion date modifiers
122
123// region: time modifiers
124/// Hour of the day.
125#[non_exhaustive]
126#[derive(Debug, Clone, Copy, PartialEq, Eq)]
127pub struct Hour {
128    /// The padding to obtain the minimum width.
129    pub padding: Padding,
130    /// Is the hour displayed using a 12 or 24-hour clock?
131    pub is_12_hour_clock: bool,
132}
133
134/// Minute within the hour.
135#[non_exhaustive]
136#[derive(Debug, Clone, Copy, PartialEq, Eq)]
137pub struct Minute {
138    /// The padding to obtain the minimum width.
139    pub padding: Padding,
140}
141
142/// AM/PM part of the time.
143#[non_exhaustive]
144#[derive(Debug, Clone, Copy, PartialEq, Eq)]
145pub struct Period {
146    /// Is the period uppercase or lowercase?
147    pub is_uppercase: bool,
148    /// Is the value case sensitive when parsing?
149    ///
150    /// Note that when `false`, the `is_uppercase` field has no effect on parsing behavior.
151    pub case_sensitive: bool,
152}
153
154/// Second within the minute.
155#[non_exhaustive]
156#[derive(Debug, Clone, Copy, PartialEq, Eq)]
157pub struct Second {
158    /// The padding to obtain the minimum width.
159    pub padding: Padding,
160}
161
162/// The number of digits present in a subsecond representation.
163#[non_exhaustive]
164#[derive(Debug, Clone, Copy, PartialEq, Eq)]
165pub enum SubsecondDigits {
166    /// Exactly one digit.
167    One,
168    /// Exactly two digits.
169    Two,
170    /// Exactly three digits.
171    Three,
172    /// Exactly four digits.
173    Four,
174    /// Exactly five digits.
175    Five,
176    /// Exactly six digits.
177    Six,
178    /// Exactly seven digits.
179    Seven,
180    /// Exactly eight digits.
181    Eight,
182    /// Exactly nine digits.
183    Nine,
184    /// Any number of digits (up to nine) that is at least one. When formatting, the minimum digits
185    /// necessary will be used.
186    OneOrMore,
187}
188
189/// Subsecond within the second.
190#[non_exhaustive]
191#[derive(Debug, Clone, Copy, PartialEq, Eq)]
192pub struct Subsecond {
193    /// How many digits are present in the component?
194    pub digits: SubsecondDigits,
195}
196// endregion time modifiers
197
198// region: offset modifiers
199/// Hour of the UTC offset.
200#[non_exhaustive]
201#[derive(Debug, Clone, Copy, PartialEq, Eq)]
202pub struct OffsetHour {
203    /// Whether the `+` sign is present on positive values.
204    pub sign_is_mandatory: bool,
205    /// The padding to obtain the minimum width.
206    pub padding: Padding,
207}
208
209/// Minute within the hour of the UTC offset.
210#[non_exhaustive]
211#[derive(Debug, Clone, Copy, PartialEq, Eq)]
212pub struct OffsetMinute {
213    /// The padding to obtain the minimum width.
214    pub padding: Padding,
215}
216
217/// Second within the minute of the UTC offset.
218#[non_exhaustive]
219#[derive(Debug, Clone, Copy, PartialEq, Eq)]
220pub struct OffsetSecond {
221    /// The padding to obtain the minimum width.
222    pub padding: Padding,
223}
224// endregion offset modifiers
225
226/// Type of padding to ensure a minimum width.
227#[non_exhaustive]
228#[derive(Debug, Clone, Copy, PartialEq, Eq)]
229pub enum Padding {
230    /// A space character (` `) should be used as padding.
231    Space,
232    /// A zero character (`0`) should be used as padding.
233    Zero,
234    /// There is no padding. This can result in a width below the otherwise minimum number of
235    /// characters.
236    None,
237}
238
239/// Ignore some number of bytes.
240///
241/// This has no effect when formatting.
242#[non_exhaustive]
243#[derive(Debug, Clone, Copy, PartialEq, Eq)]
244pub struct Ignore {
245    /// The number of bytes to ignore.
246    pub count: NonZeroU16,
247}
248
249// Needed as `Default` is deliberately not implemented for `Ignore`. The number of bytes to ignore
250// must be explicitly provided.
251impl Ignore {
252    /// Create an instance of `Ignore` with the provided number of bytes to ignore.
253    pub const fn count(count: NonZeroU16) -> Self {
254        Self { count }
255    }
256}
257
258/// The precision of a Unix timestamp.
259#[non_exhaustive]
260#[derive(Debug, Clone, Copy, PartialEq, Eq)]
261pub enum UnixTimestampPrecision {
262    /// Seconds since the Unix epoch.
263    Second,
264    /// Milliseconds since the Unix epoch.
265    Millisecond,
266    /// Microseconds since the Unix epoch.
267    Microsecond,
268    /// Nanoseconds since the Unix epoch.
269    Nanosecond,
270}
271
272/// A Unix timestamp.
273#[non_exhaustive]
274#[derive(Debug, Clone, Copy, PartialEq, Eq)]
275pub struct UnixTimestamp {
276    /// The precision of the timestamp.
277    pub precision: UnixTimestampPrecision,
278    /// Whether the `+` sign must be present for a non-negative timestamp.
279    pub sign_is_mandatory: bool,
280}
281
282/// The end of input.
283///
284/// There is currently not customization for this modifier.
285#[non_exhaustive]
286#[derive(Debug, Clone, Copy, PartialEq, Eq)]
287pub struct End;
288
289/// Generate the provided code if and only if `pub` is present.
290macro_rules! if_pub {
291    (pub $(#[$attr:meta])*; $($x:tt)*) => {
292        $(#[$attr])*
293        ///
294        /// This function exists since [`Default::default()`] cannot be used in a `const` context.
295        /// It may be removed once that becomes possible. As the [`Default`] trait is in the
296        /// prelude, removing this function in the future will not cause any resolution failures for
297        /// the overwhelming majority of users; only users who use `#![no_implicit_prelude]` will be
298        /// affected. As such it will not be considered a breaking change.
299        $($x)*
300    };
301    ($($_:tt)*) => {};
302}
303
304/// Implement `Default` for the given type. This also generates an inherent implementation of a
305/// `default` method that is `const fn`, permitting the default value to be used in const contexts.
306// Every modifier should use this macro rather than a derived `Default`.
307macro_rules! impl_const_default {
308    ($($(#[$doc:meta])* $(@$pub:ident)? $type:ty => $default:expr;)*) => {$(
309        impl $type {
310            if_pub! {
311                $($pub)?
312                $(#[$doc])*;
313                pub const fn default() -> Self {
314                    $default
315                }
316            }
317        }
318
319        $(#[$doc])*
320        impl Default for $type {
321            fn default() -> Self {
322                $default
323            }
324        }
325    )*};
326}
327
328impl_const_default! {
329    /// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
330    @pub Day => Self { padding: Padding::Zero };
331    /// Creates a modifier that indicates the value uses the
332    /// [`Numerical`](Self::Numerical) representation.
333    MonthRepr => Self::Numerical;
334    /// Creates an instance of this type that indicates the value uses the
335    /// [`Numerical`](MonthRepr::Numerical) representation, is [padded with zeroes](Padding::Zero),
336    /// and is case-sensitive when parsing.
337    @pub Month => Self {
338        padding: Padding::Zero,
339        repr: MonthRepr::Numerical,
340        case_sensitive: true,
341    };
342    /// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
343    @pub Ordinal => Self { padding: Padding::Zero };
344    /// Creates a modifier that indicates the value uses the [`Long`](Self::Long) representation.
345    WeekdayRepr => Self::Long;
346    /// Creates a modifier that indicates the value uses the [`Long`](WeekdayRepr::Long)
347    /// representation and is case-sensitive when parsing. If the representation is changed to a
348    /// numerical one, the instance defaults to one-based indexing.
349    @pub Weekday => Self {
350        repr: WeekdayRepr::Long,
351        one_indexed: true,
352        case_sensitive: true,
353    };
354    /// Creates a modifier that indicates that the value uses the [`Iso`](Self::Iso) representation.
355    WeekNumberRepr => Self::Iso;
356    /// Creates a modifier that indicates that the value is [padded with zeroes](Padding::Zero)
357            /// and uses the [`Iso`](WeekNumberRepr::Iso) representation.
358    @pub WeekNumber => Self {
359        padding: Padding::Zero,
360        repr: WeekNumberRepr::Iso,
361    };
362    /// Creates a modifier that indicates the value uses the [`Full`](Self::Full) representation.
363    YearRepr => Self::Full;
364    /// Creates a modifier that indicates the value uses the [`Full`](YearRepr::Full)
365    /// representation, is [padded with zeroes](Padding::Zero), uses the Gregorian calendar as its
366    /// base, and only includes the year's sign if necessary.
367    @pub Year => Self {
368        padding: Padding::Zero,
369        repr: YearRepr::Full,
370        iso_week_based: false,
371        sign_is_mandatory: false,
372    };
373    /// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero) and
374    /// has the 24-hour representation.
375    @pub Hour => Self {
376        padding: Padding::Zero,
377        is_12_hour_clock: false,
378    };
379    /// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
380    @pub Minute => Self { padding: Padding::Zero };
381    /// Creates a modifier that indicates the value uses the upper-case representation and is
382    /// case-sensitive when parsing.
383    @pub Period => Self {
384        is_uppercase: true,
385        case_sensitive: true,
386    };
387    /// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
388    @pub Second => Self { padding: Padding::Zero };
389    /// Creates a modifier that indicates the stringified value contains [one or more
390    /// digits](Self::OneOrMore).
391    SubsecondDigits => Self::OneOrMore;
392    /// Creates a modifier that indicates the stringified value contains [one or more
393    /// digits](SubsecondDigits::OneOrMore).
394    @pub Subsecond => Self { digits: SubsecondDigits::OneOrMore };
395    /// Creates a modifier that indicates the value only uses a sign for negative values and is
396    /// [padded with zeroes](Padding::Zero).
397    @pub OffsetHour => Self {
398        sign_is_mandatory: false,
399        padding: Padding::Zero,
400    };
401    /// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
402    @pub OffsetMinute => Self { padding: Padding::Zero };
403    /// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
404    @pub OffsetSecond => Self { padding: Padding::Zero };
405    /// Creates a modifier that indicates the value is [padded with zeroes](Self::Zero).
406    Padding => Self::Zero;
407    /// Creates a modifier that indicates the value represents the [number of seconds](Self::Second)
408    /// since the Unix epoch.
409    UnixTimestampPrecision => Self::Second;
410    /// Creates a modifier that indicates the value represents the [number of
411    /// seconds](UnixTimestampPrecision::Second) since the Unix epoch. The sign is not mandatory.
412    @pub UnixTimestamp => Self {
413        precision: UnixTimestampPrecision::Second,
414        sign_is_mandatory: false,
415    };
416    /// Creates a modifier used to represent the end of input.
417    @pub End => End;
418}