simple_datetime_rs/utils/
date_util.rs

1use crate::constants::MONTH_DAYS;
2
3#[inline]
4pub fn next_leap_year(year: u64) -> u64 {
5    recent_leap_year(year + 4)
6}
7#[inline]
8pub fn recent_leap_year(year: u64) -> u64 {
9    year - (year % 4)
10}
11#[inline]
12pub fn leap_year(year: u64) -> bool {
13    (year & 3) == 0 && (year % 100 != 0 || year % 400 == 0)
14}
15#[inline]
16pub fn month_index(month: u64) -> usize {
17    (month.saturating_sub(1)) as usize
18}
19
20pub fn month_days(month: u64, leap_year: bool) -> u64 {
21    if leap_year && month == 2 {
22        return MONTH_DAYS[month_index(month)] + 1;
23    }
24    MONTH_DAYS[month_index(month)]
25}
26#[inline]
27pub fn before_leap(month: u64) -> bool {
28    month < 3
29}
30
31#[cfg(test)]
32mod tests {
33    use super::*;
34
35    #[test]
36    fn test_date_leap_year() {
37        assert!(leap_year(2020));
38        assert!(!leap_year(2018));
39        assert!(leap_year(2016));
40    }
41
42    #[test]
43    fn test_date_recent_leap_year() {
44        assert_eq!(recent_leap_year(2020), 2020);
45        assert_eq!(recent_leap_year(2019), 2016);
46    }
47
48    #[test]
49    fn test_date_next_leap_year() {
50        assert_eq!(next_leap_year(2020), 2024);
51        assert_eq!(next_leap_year(2019), 2020);
52    }
53
54    #[test]
55    fn test_month_days() {
56        assert_eq!(month_days(1, false), 31); // January
57        assert_eq!(month_days(3, false), 31); // March
58        assert_eq!(month_days(4, false), 30); // April
59        assert_eq!(month_days(6, false), 30); // June
60        assert_eq!(month_days(9, false), 30); // September
61        assert_eq!(month_days(11, false), 30); // November
62        assert_eq!(month_days(12, false), 31); // December
63
64        assert_eq!(month_days(2, false), 28);
65
66        assert_eq!(month_days(2, true), 29);
67
68        for month in 1..=12 {
69            if month != 2 {
70                assert_eq!(month_days(month, true), month_days(month, false));
71            }
72        }
73    }
74
75    #[test]
76    fn test_before_leap() {
77        assert!(before_leap(1)); // January
78        assert!(before_leap(2)); // February
79        assert!(!before_leap(3)); // March
80        assert!(!before_leap(4)); // April
81        assert!(!before_leap(12)); // December
82    }
83
84    #[test]
85    fn test_month_index() {
86        assert_eq!(month_index(1), 0);
87        assert_eq!(month_index(6), 5);
88        assert_eq!(month_index(12), 11);
89    }
90
91    #[test]
92    fn test_leap_year_edge_cases() {
93        assert!(leap_year(2000)); // Divisible by 400
94        assert!(!leap_year(1900)); // Divisible by 100 but not 400
95        assert!(!leap_year(1800)); // Divisible by 100 but not 400
96        assert!(!leap_year(1700)); // Divisible by 100 but not 400
97
98        assert!(leap_year(2004)); // Divisible by 4
99        assert!(leap_year(2008)); // Divisible by 4
100        assert!(!leap_year(2001)); // Not divisible by 4
101        assert!(!leap_year(2002)); // Not divisible by 4
102        assert!(!leap_year(2003)); // Not divisible by 4
103    }
104
105    #[test]
106    fn test_recent_leap_year_edge_cases() {
107        assert_eq!(recent_leap_year(2020), 2020); // Already a leap year
108        assert_eq!(recent_leap_year(2021), 2020); // Previous leap year
109        assert_eq!(recent_leap_year(2022), 2020); // Previous leap year
110        assert_eq!(recent_leap_year(2023), 2020); // Previous leap year
111        assert_eq!(recent_leap_year(2024), 2024); // Next leap year
112    }
113
114    #[test]
115    fn test_next_leap_year_edge_cases() {
116        assert_eq!(next_leap_year(2020), 2024); // Current leap year
117        assert_eq!(next_leap_year(2021), 2024); // Next leap year
118        assert_eq!(next_leap_year(2022), 2024); // Next leap year
119        assert_eq!(next_leap_year(2023), 2024); // Next leap year
120        assert_eq!(next_leap_year(2024), 2028); // Next leap year after current
121    }
122}