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}