leap_sec/error.rs
1//! Error types for leap-second conversions.
2
3use core::fmt;
4
5/// Errors that can occur during leap-second conversions or table construction.
6///
7/// All conversion methods on [`LeapSeconds`](crate::LeapSeconds) return
8/// `Result<T, Error>`. Pattern-match to handle specific cases:
9///
10/// # Example
11///
12/// ```
13/// use leap_sec::prelude::*;
14///
15/// let leaps = LeapSeconds::known();
16///
17/// match leaps.utc_to_tai(UtcUnixSeconds(0)) {
18/// Ok(tai) => println!("TAI: {tai}"),
19/// Err(Error::OutOfRange { requested, valid_start, .. }) => {
20/// println!("{requested} is before {valid_start}");
21/// }
22/// Err(e) => println!("other error: {e}"),
23/// }
24/// ```
25#[derive(Debug, Clone, PartialEq, Eq)]
26pub enum Error {
27 /// The requested timestamp is before the first entry in the leap-second table.
28 ///
29 /// Returned by [`LeapSeconds::utc_to_tai`](crate::LeapSeconds::utc_to_tai),
30 /// [`LeapSeconds::tai_to_utc`](crate::LeapSeconds::tai_to_utc), and all
31 /// other conversion and offset methods when the input is outside the table's
32 /// valid range.
33 OutOfRange {
34 /// The timestamp that was requested.
35 requested: i64,
36 /// The earliest valid timestamp in the table.
37 valid_start: i64,
38 /// The latest entry timestamp in the table.
39 valid_end: i64,
40 },
41 /// The leap-second table has expired.
42 ///
43 /// Reserved for future use when tables parsed from IERS files carry
44 /// expiration timestamps. The built-in [`LeapSeconds::known()`](crate::LeapSeconds::known)
45 /// table never produces this error.
46 TableExpired {
47 /// When the table expires, as a UTC Unix timestamp.
48 expires_at: i64,
49 },
50 /// The table data is invalid (used during builder validation).
51 ///
52 /// Returned by [`LeapSecondsBuilder::build()`](crate::LeapSecondsBuilder::build)
53 /// when the table is empty or timestamps are not monotonically increasing.
54 InvalidTable {
55 /// A description of what is wrong with the table.
56 detail: &'static str,
57 },
58}
59
60/// Formats the error with a human-readable message.
61///
62/// - `OutOfRange`: `"timestamp {requested} is outside the leap-second table range [{start}, {end}]"`
63/// - `TableExpired`: `"leap-second table expired at {expires_at}; load a newer table or update the crate"`
64/// - `InvalidTable`: `"invalid leap-second table: {detail}"`
65impl fmt::Display for Error {
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 match self {
68 Self::OutOfRange {
69 requested,
70 valid_start,
71 valid_end,
72 } => write!(
73 f,
74 "timestamp {requested} is outside the leap-second table range \
75 [{valid_start}, {valid_end}]"
76 ),
77 Self::TableExpired { expires_at } => {
78 write!(
79 f,
80 "leap-second table expired at {expires_at}; \
81 load a newer table or update the crate"
82 )
83 }
84 Self::InvalidTable { detail } => {
85 write!(f, "invalid leap-second table: {detail}")
86 }
87 }
88 }
89}
90
91/// Enables use as `Box<dyn std::error::Error>` and in error-handling chains.
92///
93/// Available only with the `std` feature (enabled by default).
94#[cfg(feature = "std")]
95impl std::error::Error for Error {}