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
18    /// The date is within the range.
19    InRange,
20
21    /// The date is after the start of the range.
22    After,
23
24    /// The range is invalid, e.g., start date is after end date.
25    InvalidRange,
26}
27
28pub const fn start_of_day() -> Time {
29    Time::constant(0, 0, 0, 0)
30}
31
32/// Using a leap second to represent the end of the day
33pub const fn end_of_day() -> Time {
34    Time::constant(23, 59, 59, 999_999_999)
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40
41    #[test]
42    fn returns_start_of_day() {
43        let time = start_of_day();
44        assert!(time.hour() == 0);
45        assert!(time.minute() == 0);
46        assert!(time.second() == 0);
47    }
48
49    #[test]
50    fn returns_end_of_day() {
51        let time = end_of_day();
52        assert!(time.hour() == 23);
53        assert!(time.minute() == 59);
54        assert!(time.second() == 59);
55    }
56
57    #[test]
58    fn validates_day_boundary_constants() {
59        // Test that the constants are what we expect
60        let start = start_of_day();
61        let end = end_of_day();
62
63        assert_eq!(start.hour(), 0);
64        assert_eq!(start.minute(), 0);
65        assert_eq!(start.second(), 0);
66        assert_eq!(start.subsec_nanosecond(), 0);
67
68        assert_eq!(end.hour(), 23);
69        assert_eq!(end.minute(), 59);
70        assert_eq!(end.second(), 59);
71        assert_eq!(end.subsec_nanosecond(), 999_999_999);
72    }
73}