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    /// All digits except the last two. Includes the sign, if any.
105    Century,
106    /// Only the last two digits of the year.
107    LastTwo,
108}
109
110/// The range of years that are supported.
111///
112/// This modifier has no effect when the year repr is [`LastTwo`](YearRepr::LastTwo).
113#[non_exhaustive]
114#[derive(Debug, Clone, Copy, PartialEq, Eq)]
115pub enum YearRange {
116    /// Years between -9999 and 9999 are supported.
117    Standard,
118    /// Years between -999_999 and 999_999 are supported, with the sign being required if the year
119    /// contains more than four digits.
120    ///
121    /// If the `large-dates` feature is not enabled, this variant is equivalent to `Standard`.
122    Extended,
123}
124
125/// Year of the date.
126#[non_exhaustive]
127#[derive(Debug, Clone, Copy, PartialEq, Eq)]
128pub struct Year {
129    /// The padding to obtain the minimum width.
130    pub padding: Padding,
131    /// What kind of representation should be used?
132    pub repr: YearRepr,
133    /// What range of years is supported?
134    pub range: YearRange,
135    /// Whether the value is based on the ISO week number or the Gregorian calendar.
136    pub iso_week_based: bool,
137    /// Whether the `+` sign is present when a positive year contains fewer than five digits.
138    pub sign_is_mandatory: bool,
139}
140// endregion date modifiers
141
142// region: time modifiers
143/// Hour of the day.
144#[non_exhaustive]
145#[derive(Debug, Clone, Copy, PartialEq, Eq)]
146pub struct Hour {
147    /// The padding to obtain the minimum width.
148    pub padding: Padding,
149    /// Is the hour displayed using a 12 or 24-hour clock?
150    pub is_12_hour_clock: bool,
151}
152
153/// Minute within the hour.
154#[non_exhaustive]
155#[derive(Debug, Clone, Copy, PartialEq, Eq)]
156pub struct Minute {
157    /// The padding to obtain the minimum width.
158    pub padding: Padding,
159}
160
161/// AM/PM part of the time.
162#[non_exhaustive]
163#[derive(Debug, Clone, Copy, PartialEq, Eq)]
164pub struct Period {
165    /// Is the period uppercase or lowercase?
166    pub is_uppercase: bool,
167    /// Is the value case sensitive when parsing?
168    ///
169    /// Note that when `false`, the `is_uppercase` field has no effect on parsing behavior.
170    pub case_sensitive: bool,
171}
172
173/// Second within the minute.
174#[non_exhaustive]
175#[derive(Debug, Clone, Copy, PartialEq, Eq)]
176pub struct Second {
177    /// The padding to obtain the minimum width.
178    pub padding: Padding,
179}
180
181/// The number of digits present in a subsecond representation.
182#[non_exhaustive]
183#[derive(Debug, Clone, Copy, PartialEq, Eq)]
184pub enum SubsecondDigits {
185    /// Exactly one digit.
186    One,
187    /// Exactly two digits.
188    Two,
189    /// Exactly three digits.
190    Three,
191    /// Exactly four digits.
192    Four,
193    /// Exactly five digits.
194    Five,
195    /// Exactly six digits.
196    Six,
197    /// Exactly seven digits.
198    Seven,
199    /// Exactly eight digits.
200    Eight,
201    /// Exactly nine digits.
202    Nine,
203    /// Any number of digits (up to nine) that is at least one. When formatting, the minimum digits
204    /// necessary will be used.
205    OneOrMore,
206}
207
208/// Subsecond within the second.
209#[non_exhaustive]
210#[derive(Debug, Clone, Copy, PartialEq, Eq)]
211pub struct Subsecond {
212    /// How many digits are present in the component?
213    pub digits: SubsecondDigits,
214}
215// endregion time modifiers
216
217// region: offset modifiers
218/// Hour of the UTC offset.
219#[non_exhaustive]
220#[derive(Debug, Clone, Copy, PartialEq, Eq)]
221pub struct OffsetHour {
222    /// Whether the `+` sign is present on positive values.
223    pub sign_is_mandatory: bool,
224    /// The padding to obtain the minimum width.
225    pub padding: Padding,
226}
227
228/// Minute within the hour of the UTC offset.
229#[non_exhaustive]
230#[derive(Debug, Clone, Copy, PartialEq, Eq)]
231pub struct OffsetMinute {
232    /// The padding to obtain the minimum width.
233    pub padding: Padding,
234}
235
236/// Second within the minute of the UTC offset.
237#[non_exhaustive]
238#[derive(Debug, Clone, Copy, PartialEq, Eq)]
239pub struct OffsetSecond {
240    /// The padding to obtain the minimum width.
241    pub padding: Padding,
242}
243// endregion offset modifiers
244
245/// Type of padding to ensure a minimum width.
246#[non_exhaustive]
247#[derive(Debug, Clone, Copy, PartialEq, Eq)]
248pub enum Padding {
249    /// A space character (` `) should be used as padding.
250    Space,
251    /// A zero character (`0`) should be used as padding.
252    Zero,
253    /// There is no padding. This can result in a width below the otherwise minimum number of
254    /// characters.
255    None,
256}
257
258/// Ignore some number of bytes.
259///
260/// This has no effect when formatting.
261#[non_exhaustive]
262#[derive(Debug, Clone, Copy, PartialEq, Eq)]
263pub struct Ignore {
264    /// The number of bytes to ignore.
265    pub count: NonZeroU16,
266}
267
268// Needed as `Default` is deliberately not implemented for `Ignore`. The number of bytes to ignore
269// must be explicitly provided.
270impl Ignore {
271    /// Create an instance of `Ignore` with the provided number of bytes to ignore.
272    pub const fn count(count: NonZeroU16) -> Self {
273        Self { count }
274    }
275}
276
277/// The precision of a Unix timestamp.
278#[non_exhaustive]
279#[derive(Debug, Clone, Copy, PartialEq, Eq)]
280pub enum UnixTimestampPrecision {
281    /// Seconds since the Unix epoch.
282    Second,
283    /// Milliseconds since the Unix epoch.
284    Millisecond,
285    /// Microseconds since the Unix epoch.
286    Microsecond,
287    /// Nanoseconds since the Unix epoch.
288    Nanosecond,
289}
290
291/// A Unix timestamp.
292#[non_exhaustive]
293#[derive(Debug, Clone, Copy, PartialEq, Eq)]
294pub struct UnixTimestamp {
295    /// The precision of the timestamp.
296    pub precision: UnixTimestampPrecision,
297    /// Whether the `+` sign must be present for a non-negative timestamp.
298    pub sign_is_mandatory: bool,
299}
300
301/// The end of input.
302///
303/// There is currently not customization for this modifier.
304#[non_exhaustive]
305#[derive(Debug, Clone, Copy, PartialEq, Eq)]
306pub struct End;
307
308/// Generate the provided code if and only if `pub` is present.
309macro_rules! if_pub {
310    (pub $(#[$attr:meta])*; $($x:tt)*) => {
311        $(#[$attr])*
312        ///
313        /// This function exists since [`Default::default()`] cannot be used in a `const` context.
314        /// It may be removed once that becomes possible. As the [`Default`] trait is in the
315        /// prelude, removing this function in the future will not cause any resolution failures for
316        /// the overwhelming majority of users; only users who use `#![no_implicit_prelude]` will be
317        /// affected. As such it will not be considered a breaking change.
318        $($x)*
319    };
320    ($($_:tt)*) => {};
321}
322
323/// Implement `Default` for the given type. This also generates an inherent implementation of a
324/// `default` method that is `const fn`, permitting the default value to be used in const contexts.
325// Every modifier should use this macro rather than a derived `Default`.
326macro_rules! impl_const_default {
327    ($($(#[$doc:meta])* $(@$pub:ident)? $type:ty => $default:expr;)*) => {$(
328        impl $type {
329            if_pub! {
330                $($pub)?
331                $(#[$doc])*;
332                pub const fn default() -> Self {
333                    $default
334                }
335            }
336        }
337
338        $(#[$doc])*
339        impl Default for $type {
340            fn default() -> Self {
341                $default
342            }
343        }
344    )*};
345}
346
347impl_const_default! {
348    /// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
349    @pub Day => Self { padding: Padding::Zero };
350    /// Creates a modifier that indicates the value uses the
351    /// [`Numerical`](Self::Numerical) representation.
352    MonthRepr => Self::Numerical;
353    /// Creates an instance of this type that indicates the value uses the
354    /// [`Numerical`](MonthRepr::Numerical) representation, is [padded with zeroes](Padding::Zero),
355    /// and is case-sensitive when parsing.
356    @pub Month => Self {
357        padding: Padding::Zero,
358        repr: MonthRepr::Numerical,
359        case_sensitive: true,
360    };
361    /// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
362    @pub Ordinal => Self { padding: Padding::Zero };
363    /// Creates a modifier that indicates the value uses the [`Long`](Self::Long) representation.
364    WeekdayRepr => Self::Long;
365    /// Creates a modifier that indicates the value uses the [`Long`](WeekdayRepr::Long)
366    /// representation and is case-sensitive when parsing. If the representation is changed to a
367    /// numerical one, the instance defaults to one-based indexing.
368    @pub Weekday => Self {
369        repr: WeekdayRepr::Long,
370        one_indexed: true,
371        case_sensitive: true,
372    };
373    /// Creates a modifier that indicates that the value uses the [`Iso`](Self::Iso) representation.
374    WeekNumberRepr => Self::Iso;
375    /// Creates a modifier that indicates that the value is [padded with zeroes](Padding::Zero)
376            /// and uses the [`Iso`](WeekNumberRepr::Iso) representation.
377    @pub WeekNumber => Self {
378        padding: Padding::Zero,
379        repr: WeekNumberRepr::Iso,
380    };
381    /// Creates a modifier that indicates the value uses the [`Full`](Self::Full) representation.
382    YearRepr => Self::Full;
383    /// Creates a modifier that indicates the value uses the [`Extended`](Self::Extended) range.
384    YearRange => Self::Extended;
385    /// Creates a modifier that indicates the value uses the [`Full`](YearRepr::Full)
386    /// representation, is [padded with zeroes](Padding::Zero), uses the Gregorian calendar as its
387    /// base, and only includes the year's sign if necessary.
388    @pub Year => Self {
389        padding: Padding::Zero,
390        repr: YearRepr::Full,
391        range: YearRange::Extended,
392        iso_week_based: false,
393        sign_is_mandatory: false,
394    };
395    /// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero) and
396    /// has the 24-hour representation.
397    @pub Hour => Self {
398        padding: Padding::Zero,
399        is_12_hour_clock: false,
400    };
401    /// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
402    @pub Minute => Self { padding: Padding::Zero };
403    /// Creates a modifier that indicates the value uses the upper-case representation and is
404    /// case-sensitive when parsing.
405    @pub Period => Self {
406        is_uppercase: true,
407        case_sensitive: true,
408    };
409    /// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
410    @pub Second => Self { padding: Padding::Zero };
411    /// Creates a modifier that indicates the stringified value contains [one or more
412    /// digits](Self::OneOrMore).
413    SubsecondDigits => Self::OneOrMore;
414    /// Creates a modifier that indicates the stringified value contains [one or more
415    /// digits](SubsecondDigits::OneOrMore).
416    @pub Subsecond => Self { digits: SubsecondDigits::OneOrMore };
417    /// Creates a modifier that indicates the value only uses a sign for negative values and is
418    /// [padded with zeroes](Padding::Zero).
419    @pub OffsetHour => Self {
420        sign_is_mandatory: false,
421        padding: Padding::Zero,
422    };
423    /// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
424    @pub OffsetMinute => Self { padding: Padding::Zero };
425    /// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
426    @pub OffsetSecond => Self { padding: Padding::Zero };
427    /// Creates a modifier that indicates the value is [padded with zeroes](Self::Zero).
428    Padding => Self::Zero;
429    /// Creates a modifier that indicates the value represents the [number of seconds](Self::Second)
430    /// since the Unix epoch.
431    UnixTimestampPrecision => Self::Second;
432    /// Creates a modifier that indicates the value represents the [number of
433    /// seconds](UnixTimestampPrecision::Second) since the Unix epoch. The sign is not mandatory.
434    @pub UnixTimestamp => Self {
435        precision: UnixTimestampPrecision::Second,
436        sign_is_mandatory: false,
437    };
438    /// Creates a modifier used to represent the end of input.
439    @pub End => End;
440}