1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//! *Real Time* -- [`Point`], [`Span`], [`Frame`] & [`Scale`]
pub use ParseSpanError;
/// *Point* in Time
///
/// This is simply a timestamp according to UNIX convention, that is, the number of seconds since 1970-01-01 00:00:00.
/// Negative values represent time before that epoch, obviously.
///
/// Because it is an [`i64`], the date range that can be represented is very large, roughly from the *year* `-292_277_022_657` to `+292_277_026_596`.
/// However, working with [`Point`]s close to end of this range is a bad idea, as date math operations might overflow.
///
/// Note that the [calendar time](crate::calendar) counterpart to this, [`DateTime`](crate::calendar::DateTime), can represent an even larger range, since it has an entire [`i64`] for just the year.
/// Timespan (Duration)
///
/// Simply an unsigned count of seconds.
/// [`Debug`], [`Display`](std::fmt::Display) and [`FromStr`](std::str::FromStr) implementations break this number, which is often incomprehensibly large, down into understandable units.
/// So instead of `Span { seconds: 108030 }` you get `1d6h30s`.
///
/// These are the units used:
///
/// | [`Scale`] | unit | seconds |
/// |-----------|------|-----------:|
/// | Years | `y` | `31556952` |
/// | Months | `mo` | `2629746` |
/// | Weeks | `w` | `604800` |
/// | Days | `d` | `86400` |
/// | Hours | `h` | `3600` |
/// | Minutes | `m` | `60` |
/// | Seconds | `s` | `1` |
///
/// As explained in the documentation for [`Scale`], the amount of seconds for `y` and `mo` is the average for each of these scales.
///
/// The Span can be parsed from the terse duration format using [`parse`](Self::parse) or [`try_parse`](Self::try_parse).
/// These methods are also `const`, so they can be used to define constants.
///
/// ```
/// use greg::Span;
///
/// const TIMEOUT: Span = Span::parse("30s");
///
/// assert_eq!(Span::parse("0s"), Span::from_seconds(0));
/// assert_eq!(Span::parse("1m30s"), Span::MINUTE + Span::SECOND * 30);
/// assert_eq!(Span::parse("1d10h"), Span::DAY + Span::HOUR * 10);
/// assert_eq!(Span::try_parse("48h"), Ok(Span::DAY * 2));
/// assert_eq!(
/// Span::parse("3w2h10m30s"),
/// Span::WEEK * 3 + Span::HOUR * 2 + Span::MINUTE * 10 + Span::SECOND * 30
/// );
/// ```
/// The alternate form for [`Display`](std::fmt::Display) (with `{:#}`) produces a string where each number/unit pair is separated by a space.
/// Additionally, if a precision is specified (with `{:.2}`), at most the requested number of number/unit pairs are printed, truncating smaller units.
/// ```
/// use greg::Span;
/// let span = Span::parse("1w2d8h33m12s");
///
/// assert_eq!(span.to_string(), "1w2d8h33m12s");
/// assert_eq!(format!("{span:#}"), "1w 2d 8h 33m 12s");
/// assert_eq!(format!("{span:#.2}"), "1w 2d");
/// ```
/// Timeframe: half-open range of [`Point`]s `start..stop` (`stop` is excluded)
///
/// This is essentially a [`Range`](std::ops::Range)`<`[`Point`]`>`, but the `end` field is called `stop`.
/// Timescale
///
/// This enum represents various "scales" of time, and with the exception of [`Scale::Years`] and [`Scale::Months`] they are precisely defined as a number of seconds.
/// For [`Scale::Years`] and [`Scale::Months`] such a precise definition is obviously not available.
/// Nonetheless, it is often useful to treat them as a concrete number of seconds, such as when formatting a time [`Span`] not anchored to a particular [`Point`] in time.
/// For a human to comprehend a long length of time, it's better to express it in terms of years and months, instead of just weeks, which is the highest precisely defined [`Scale`], even if that is somewhat ill-defined.
/// To do this, the [`Scale`] must be expressed as a fixed number of seconds (a [`Span`]).
/// There are a few different values that could reasonably be chosen for the length of [`Scale::Years`] and [`Scale::Months`] respectively.
/// This library simply copies [helper types](https://en.cppreference.com/w/cpp/chrono/duration#Helper_types) of [`std::chrono::duration`](https://en.cppreference.com/w/cpp/chrono/duration) provided in C++ since C++20.
/// Accordingly, "years is equal to 365.2425 days (the average length of a Gregorian year)" and "months is equal to 30.436875 days (exactly 1/12 of years)".
/// Conveniently, both of these work out to an integral number of seconds.
///
/// | Scale | unit | seconds |
/// |---------|------|-----------:|
/// | Years | `y` | `31556952` |
/// | Months | `mo` | `2629746` |
/// | Weeks | `w` | `604800` |
/// | Days | `d` | `86400` |
/// | Hours | `h` | `3600` |
/// | Minutes | `m` | `60` |
/// | Seconds | `s` | `1` |
///
/// All this is not to say that a [`Scale`] represents just a specific number of seconds.
/// For instance, the [`Calendar::date_floor`](crate::Calendar::date_floor) and [`Calendar::frames`](crate::Calendar::frames) functions use it with "calendar semantics".