day.rs
1 use chrono::{DateTime, Datelike, TimeZone, Utc}; 2 3 use crate::utils::datetime::{EST, now_est}; 4 5 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 6 pub struct AocDay { 7 pub year: i32, 8 pub day: u32, 9 } 10 11 impl AocDay { 12 pub fn unlock_datetime(self) -> DateTime<Utc> { 13 EST.with_ymd_and_hms(self.year, 12, self.day, 0, 0, 0) 14 .unwrap() 15 .to_utc() 16 } 17 18 pub fn url(self) -> String { 19 format!("https://adventofcode.com/{}/day/{}", self.year, self.day) 20 } 21 22 pub fn current() -> Option<Self> { 23 let now = now_est(); 24 (now.month() == 12 && now.day() <= number_of_days(now.year())).then_some(Self { 25 year: now.year(), 26 day: now.day(), 27 }) 28 } 29 30 pub fn next() -> Self { 31 let now = now_est(); 32 let (year, day) = if now.month() != 12 { 33 // december this year 34 (now.year(), 1) 35 } else if now.day() < number_of_days(now.year()) { 36 // tomorrow 37 (now.year(), now.day() + 1) 38 } else { 39 // next year 40 (now.year() + 1, 1) 41 }; 42 Self { year, day } 43 } 44 45 pub fn most_recent() -> Self { 46 let now = now_est(); 47 let (year, day) = if now.month() != 12 { 48 // december last year 49 (now.year() - 1, number_of_days(now.year() - 1)) 50 } else { 51 // this year, today or last aoc day 52 (now.year(), now.day().min(number_of_days(now.year()))) 53 }; 54 Self { year, day } 55 } 56 } 57 58 pub fn number_of_days(year: i32) -> u32 { 59 if year >= 2025 { 12 } else { 25 } 60 } 61 62 #[cfg(test)] 63 mod tests { 64 use super::*; 65 use crate::utils::datetime::set_now; 66 67 #[test] 68 fn unlock_datetime() { 69 for (year, day, expected) in [ 70 (2024, 1, "2024-12-01T06:00:00+01:00"), 71 (2024, 2, "2024-12-02T06:00:00+01:00"), 72 (2024, 16, "2024-12-16T06:00:00+01:00"), 73 (2024, 25, "2024-12-25T06:00:00+01:00"), 74 (2025, 1, "2025-12-01T06:00:00+01:00"), 75 ] { 76 let day = AocDay { year, day }; 77 let expected = expected.parse::<DateTime<Utc>>().unwrap(); 78 assert_eq!(day.unlock_datetime(), expected); 79 } 80 } 81 82 #[test] 83 fn url() { 84 let day = |year, day| AocDay { year, day }; 85 assert_eq!(day(2023, 1).url(), "https://adventofcode.com/2023/day/1"); 86 assert_eq!(day(2018, 17).url(), "https://adventofcode.com/2018/day/17"); 87 } 88 89 #[test] 90 fn next() { 91 for (now, year, day) in [ 92 ("2024-07-17T13:37:42+01:00", 2024, 1), 93 ("2024-11-17T13:37:42+01:00", 2024, 1), 94 ("2024-12-01T05:59:07+01:00", 2024, 1), 95 ("2024-12-01T06:00:13+01:00", 2024, 2), 96 ("2024-12-15T14:17:00+01:00", 2024, 16), 97 ("2024-12-25T05:59:07+01:00", 2024, 25), 98 ("2024-12-25T06:00:07+01:00", 2025, 1), 99 ("2024-12-31T13:37:42+01:00", 2025, 1), 100 ("2025-01-07T13:37:42+01:00", 2025, 1), 101 ("2025-12-11T14:17:00+01:00", 2025, 12), 102 ("2025-12-12T14:17:00+01:00", 2026, 1), 103 ] { 104 let _guard = set_now(now.parse().unwrap()); 105 let expected = AocDay { year, day }; 106 assert_eq!(AocDay::next(), expected); 107 } 108 } 109 110 #[test] 111 fn current() { 112 for (now, expected) in [ 113 ("2024-07-17T13:37:42+01:00", None), 114 ("2024-11-17T13:37:42+01:00", None), 115 ("2024-12-01T05:59:07+01:00", None), 116 ("2024-12-01T06:00:13+01:00", Some((2024, 1))), 117 ("2024-12-15T14:17:00+01:00", Some((2024, 15))), 118 ("2024-12-25T05:59:07+01:00", Some((2024, 24))), 119 ("2024-12-25T06:00:07+01:00", Some((2024, 25))), 120 ("2024-12-31T13:37:42+01:00", None), 121 ("2025-01-07T13:37:42+01:00", None), 122 ("2025-12-12T14:17:00+01:00", Some((2025, 12))), 123 ("2025-12-13T14:17:00+01:00", None), 124 ] { 125 let _guard = set_now(now.parse().unwrap()); 126 let expected = expected.map(|(year, day)| AocDay { year, day }); 127 assert_eq!(AocDay::current(), expected); 128 } 129 } 130 131 #[test] 132 fn most_recent() { 133 for (now, year, day) in [ 134 ("2024-07-17T13:37:42+01:00", 2023, 25), 135 ("2024-11-17T13:37:42+01:00", 2023, 25), 136 ("2024-12-01T05:59:07+01:00", 2023, 25), 137 ("2024-12-01T06:00:13+01:00", 2024, 1), 138 ("2024-12-15T14:17:00+01:00", 2024, 15), 139 ("2024-12-25T05:59:07+01:00", 2024, 24), 140 ("2024-12-25T06:00:07+01:00", 2024, 25), 141 ("2024-12-31T13:37:42+01:00", 2024, 25), 142 ("2025-01-07T13:37:42+01:00", 2024, 25), 143 ("2025-12-11T14:17:00+01:00", 2025, 11), 144 ("2025-12-15T14:17:00+01:00", 2025, 12), 145 ("2026-01-07T13:37:42+01:00", 2025, 12), 146 ] { 147 let _guard = set_now(now.parse().unwrap()); 148 let expected = AocDay { year, day }; 149 assert_eq!(AocDay::most_recent(), expected); 150 } 151 } 152 }