greg/
real.rs

1//! *Real Time* -- [`Point`], [`Span`], [`Frame`] & [`Scale`]
2
3#![cfg_attr(
4	feature = "rusqlite",
5	doc = "\n",
6	doc = "The `rusqlite` feature implements the [`rusqlite`] traits [`FromSql`](rusqlite::types::FromSql) and [`ToSql`](rusqlite::types::ToSql) for [`Point`] and [`Span`]."
7)]
8
9mod point;
10mod span;
11mod frame;
12
13#[cfg(feature = "serde")]
14mod serde;
15
16#[cfg(feature = "rusqlite")]
17mod sql;
18
19pub use span::ParseSpanError;
20
21/// *Point* in Time
22///
23/// This is simply a timestamp according to UNIX convention, that is, the number of seconds since 1970-01-01 00:00:00.
24/// Negative values represent time before that epoch, obviously.
25///
26/// 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`.
27/// However, working with [`Point`]s close to end of this range is a bad idea, as date math operations might overflow.
28///
29/// 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.
30#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
31pub struct Point {
32	/// Count of seconds since 1970-01-01 00:00:00
33	pub timestamp: i64
34}
35
36/// Timespan (Duration)
37///
38/// Simply an unsigned count of seconds.
39/// [`Debug`], [`Display`](std::fmt::Display) and [`FromStr`](std::str::FromStr) implementations break this number, which is often incomprehensibly large, down into understandable units.
40/// So instead of `Span { seconds: 108030 }` you get `1d6h30s`.
41///
42/// These are the units used:
43///
44/// | [`Scale`] | unit |    seconds |
45/// |-----------|------|-----------:|
46/// | Years     | `y`  | `31556952` |
47/// | Months    | `mo` |  `2629746` |
48/// | Weeks     | `w`  |   `604800` |
49/// | Days      | `d`  |    `86400` |
50/// | Hours     | `h`  |     `3600` |
51/// | Minutes   | `m`  |       `60` |
52/// | Seconds   | `s`  |        `1` |
53///
54/// As explained in the documentation for [`Scale`], the amount of seconds for `y` and `mo` is the average for each of these scales.
55///
56/// The Span can be parsed from the terse duration format using [`parse`](Self::parse) or [`try_parse`](Self::try_parse).
57/// These methods are also `const`, so they can be used to define constants.
58///
59/// ```
60/// use greg::Span;
61///
62/// const TIMEOUT: Span = Span::parse("30s");
63///
64/// assert_eq!(Span::parse("0s"), Span::from_seconds(0));
65/// assert_eq!(Span::parse("1m30s"), Span::MINUTE + Span::SECOND * 30);
66/// assert_eq!(Span::parse("1d10h"), Span::DAY + Span::HOUR * 10);
67/// assert_eq!(Span::try_parse("48h"), Ok(Span::DAY * 2));
68/// assert_eq!(
69///     Span::parse("3w2h10m30s"),
70///     Span::WEEK * 3 + Span::HOUR * 2 + Span::MINUTE * 10 + Span::SECOND * 30
71/// );
72/// ```
73/// The alternate form for [`Display`](std::fmt::Display) (with `{:#}`) produces a string where each number/unit pair is separated by a space.
74/// Additionally, if a precision is specified (with `{:.2}`), at most the requested number of number/unit pairs are printed, truncating smaller units.
75/// ```
76/// use greg::Span;
77/// let span = Span::parse("1w2d8h33m12s");
78///
79/// assert_eq!(span.to_string(), "1w2d8h33m12s");
80/// assert_eq!(format!("{span:#}"), "1w 2d 8h 33m 12s");
81/// assert_eq!(format!("{span:#.2}"), "1w 2d");
82/// ```
83#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
84pub struct Span {
85	/// Duration in seconds
86	pub seconds: u64
87}
88
89/// Timeframe: half-open range of [`Point`]s `start..stop` (`stop` is excluded)
90///
91/// This is essentially a [`Range`](std::ops::Range)`<`[`Point`]`>`, but the `end` field is called `stop`.
92#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
93pub struct Frame {
94	/// The first included [`Point`]
95	pub start: Point,
96	/// The first [`Point`] no longer included
97	pub stop: Point
98}
99
100/// Timescale
101///
102/// 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.
103/// For [`Scale::Years`] and [`Scale::Months`] such a precise definition is obviously not available.
104/// 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.
105/// 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.
106/// To do this, the [`Scale`] must be expressed as a fixed number of seconds (a [`Span`]).  
107/// There are a few different values that could reasonably be chosen for the length of [`Scale::Years`] and [`Scale::Months`] respectively.
108/// 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.  
109/// 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)".
110/// Conveniently, both of these work out to an integral number of seconds.
111///
112/// | Scale   | unit |    seconds |
113/// |---------|------|-----------:|
114/// | Years   | `y`  | `31556952` |
115/// | Months  | `mo` |  `2629746` |
116/// | Weeks   | `w`  |   `604800` |
117/// | Days    | `d`  |    `86400` |
118/// | Hours   | `h`  |     `3600` |
119/// | Minutes | `m`  |       `60` |
120/// | Seconds | `s`  |        `1` |
121///
122/// All this is not to say that a [`Scale`] represents just a specific number of seconds.
123/// For instance, the [`Calendar::date_floor`](crate::Calendar::date_floor) and [`Calendar::frames`](crate::Calendar::frames) functions use it with "calendar semantics".
124#[allow(missing_docs)]
125#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
126pub enum Scale {
127	Seconds,
128	Minutes,
129	Hours,
130	Days,
131	Weeks,
132	Months,
133	Years
134}
135
136impl Scale {
137	/// The (average) amount of seconds, see [`Scale`] for details
138	pub const fn as_seconds(self) -> u64 {
139		match self {
140			Self::Years =>   31556952,
141			Self::Months =>   2629746,
142			Self::Weeks =>     604800,
143			Self::Days =>       86400,
144			Self::Hours =>       3600,
145			Self::Minutes =>       60,
146			Self::Seconds =>        1
147		}
148	}
149}