Skip to main content

aimcal_core/datetime/
util.rs

1// SPDX-FileCopyrightText: 2025-2026 Zexin Yuan <aim@yzx9.xyz>
2//
3// SPDX-License-Identifier: Apache-2.0
4
5use jiff::civil::Time;
6
7/// NOTE: Used for storing in the database, so it should be stable across different runs.
8pub const STABLE_FORMAT_DATEONLY: &str = "%Y-%m-%d";
9pub const STABLE_FORMAT_FLOATING: &str = "%Y-%m-%dT%H:%M:%S";
10pub const STABLE_FORMAT_LOCAL: &str = "%Y-%m-%dT%H:%M:%S%z";
11
12/// The position of a date relative to a range defined by a start and optional end date.
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum RangePosition {
15    /// The date is before the start of the range.
16    Before,
17    /// The date is within the range.
18    InRange,
19    /// The date is after the start of the range.
20    After,
21    /// The range is invalid, e.g., start date is after end date.
22    InvalidRange,
23}
24
25pub const fn start_of_day() -> Time {
26    Time::constant(0, 0, 0, 0)
27}
28
29/// Using a leap second to represent the end of the day
30pub const fn end_of_day() -> Time {
31    Time::constant(23, 59, 59, 999_999_999)
32}
33
34#[cfg(test)]
35mod tests {
36    use super::*;
37
38    #[test]
39    fn returns_start_of_day() {
40        let time = start_of_day();
41        assert!(time.hour() == 0);
42        assert!(time.minute() == 0);
43        assert!(time.second() == 0);
44    }
45
46    #[test]
47    fn returns_end_of_day() {
48        let time = end_of_day();
49        assert!(time.hour() == 23);
50        assert!(time.minute() == 59);
51        assert!(time.second() == 59);
52    }
53
54    #[test]
55    fn validates_day_boundary_constants() {
56        // Test that the constants are what we expect
57        let start = start_of_day();
58        let end = end_of_day();
59
60        assert_eq!(start.hour(), 0);
61        assert_eq!(start.minute(), 0);
62        assert_eq!(start.second(), 0);
63        assert_eq!(start.subsec_nanosecond(), 0);
64
65        assert_eq!(end.hour(), 23);
66        assert_eq!(end.minute(), 59);
67        assert_eq!(end.second(), 59);
68        assert_eq!(end.subsec_nanosecond(), 999_999_999);
69    }
70}