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