1 use std::{fmt, io}; 2 3 mod day; 4 mod day_of_week; 5 mod month; 6 mod parser; 7 mod year; 8 9 use day::Day; 10 pub(crate) use day_of_week::DayOfWeek; 11 pub(crate) use month::Month; 12 use year::Year; 13 14 use crate::{error::FendError, ident::Ident, result::FResult, value::Value, Interrupt}; 15 16 #[derive(Copy, Clone, Eq, PartialEq)] 17 pub(crate) struct Date { 18 year: Year, 19 month: Month, 20 day: Day, 21 } 22 23 impl Date { today(context: &crate::Context) -> FResult<Self>24 pub(crate) fn today(context: &crate::Context) -> FResult<Self> { 25 let Some(current_time_info) = &context.current_time else { 26 return Err(FendError::UnableToGetCurrentDate); 27 }; 28 let mut ms_since_epoch: i64 = current_time_info.elapsed_unix_time_ms.try_into().unwrap(); 29 ms_since_epoch -= current_time_info.timezone_offset_secs * 1000; 30 let mut days = ms_since_epoch / 86_400_000; // no leap seconds 31 let mut year = Year::new(1970); 32 while days >= year.number_of_days().into() { 33 year = year.next(); 34 days -= i64::from(year.number_of_days()); 35 } 36 let mut month = Month::January; 37 while days >= month.number_of_days(year).into() { 38 month = month.next(); 39 days -= i64::from(month.number_of_days(year)); 40 } 41 Ok(Self { 42 year, 43 month, 44 day: Day::new(days.try_into().unwrap()), 45 }) 46 } 47 day_of_week(self) -> DayOfWeek48 fn day_of_week(self) -> DayOfWeek { 49 let d1 = (1 50 + 5 * ((self.year.value() - 1) % 4) 51 + 4 * ((self.year.value() - 1) % 100) 52 + 6 * ((self.year.value() - 1) % 400)) 53 % 7; 54 let ms = match self.month { 55 Month::January => (0, 0), 56 Month::February => (3, 3), 57 Month::March | Month::November => (3, 4), 58 Month::April | Month::July => (6, 0), 59 Month::May => (1, 2), 60 Month::June => (4, 5), 61 Month::August => (2, 3), 62 Month::September | Month::December => (5, 6), 63 Month::October => (0, 1), 64 }; 65 let m = if self.year.is_leap_year() { ms.1 } else { ms.0 }; 66 match (d1 + m + i32::from(self.day.value() - 1)) % 7 { 67 0 => DayOfWeek::Sunday, 68 1 => DayOfWeek::Monday, 69 2 => DayOfWeek::Tuesday, 70 3 => DayOfWeek::Wednesday, 71 4 => DayOfWeek::Thursday, 72 5 => DayOfWeek::Friday, 73 6 => DayOfWeek::Saturday, 74 _ => unreachable!(), 75 } 76 } 77 next(self) -> Self78 pub(crate) fn next(self) -> Self { 79 if self.day.value() < Month::number_of_days(self.month, self.year) { 80 Self { 81 day: Day::new(self.day.value() + 1), 82 month: self.month, 83 year: self.year, 84 } 85 } else if self.month == Month::December { 86 Self { 87 day: Day::new(1), 88 month: Month::January, 89 year: self.year.next(), 90 } 91 } else { 92 Self { 93 day: Day::new(1), 94 month: self.month.next(), 95 year: self.year, 96 } 97 } 98 } 99 prev(self) -> Self100 pub(crate) fn prev(self) -> Self { 101 if self.day.value() > 1 { 102 Self { 103 day: Day::new(self.day.value() - 1), 104 month: self.month, 105 year: self.year, 106 } 107 } else if self.month == Month::January { 108 Self { 109 day: Day::new(31), 110 month: Month::December, 111 year: self.year.prev(), 112 } 113 } else { 114 let month = self.month.prev(); 115 Self { 116 day: Day::new(Month::number_of_days(month, self.year)), 117 month, 118 year: self.year, 119 } 120 } 121 } 122 diff_months(self, mut months: i64) -> FResult<Self>123 pub(crate) fn diff_months(self, mut months: i64) -> FResult<Self> { 124 let mut result = self; 125 while months >= 12 { 126 result.year = result.year.next(); 127 months -= 12; 128 } 129 while months <= -12 { 130 result.year = result.year.prev(); 131 months += 12; 132 } 133 while months > 0 { 134 if result.month == Month::December { 135 result.month = Month::January; 136 result.year = result.year.next(); 137 } else { 138 result.month = result.month.next(); 139 } 140 months -= 1; 141 } 142 while months < 0 { 143 if result.month == Month::January { 144 result.month = Month::December; 145 result.year = result.year.prev(); 146 } else { 147 result.month = result.month.prev(); 148 } 149 months += 1; 150 } 151 if result.day.value() > Month::number_of_days(result.month, result.year) { 152 let mut before = result; 153 before.day = Day::new(Month::number_of_days(before.month, before.year)); 154 let mut after = result; 155 if after.month == Month::December { 156 after.month = Month::January; 157 after.year = after.year.next(); 158 } else { 159 after.month = after.month.next(); 160 } 161 after.day = Day::new(1); 162 return Err(FendError::NonExistentDate { 163 year: result.year.value(), 164 month: result.month, 165 expected_day: result.day.value(), 166 before, 167 after, 168 }); 169 } 170 Ok(result) 171 } 172 parse(s: &str) -> FResult<Self>173 pub(crate) fn parse(s: &str) -> FResult<Self> { 174 parser::parse_date(s) 175 } 176 serialize(self, write: &mut impl io::Write) -> FResult<()>177 pub(crate) fn serialize(self, write: &mut impl io::Write) -> FResult<()> { 178 self.year.serialize(write)?; 179 self.month.serialize(write)?; 180 self.day.serialize(write)?; 181 Ok(()) 182 } 183 deserialize(read: &mut impl io::Read) -> FResult<Self>184 pub(crate) fn deserialize(read: &mut impl io::Read) -> FResult<Self> { 185 Ok(Self { 186 year: Year::deserialize(read)?, 187 month: Month::deserialize(read)?, 188 day: Day::deserialize(read)?, 189 }) 190 } 191 get_object_member(self, key: &Ident) -> FResult<crate::value::Value>192 pub(crate) fn get_object_member(self, key: &Ident) -> FResult<crate::value::Value> { 193 Ok(match key.as_str() { 194 "month" => Value::Month(self.month), 195 "day_of_week" => Value::DayOfWeek(self.day_of_week()), 196 _ => return Err(FendError::CouldNotFindKey(key.to_string())), 197 }) 198 } 199 add<I: Interrupt>(self, rhs: Value, int: &I) -> FResult<Value>200 pub(crate) fn add<I: Interrupt>(self, rhs: Value, int: &I) -> FResult<Value> { 201 let rhs = rhs.expect_num()?; 202 if rhs.unit_equal_to("day", int)? { 203 let num_days = rhs.try_as_usize_unit(int)?; 204 let mut result = self; 205 for _ in 0..num_days { 206 result = result.next(); 207 } 208 Ok(Value::Date(result)) 209 } else { 210 Err(FendError::ExpectedANumber) 211 } 212 } 213 sub<I: Interrupt>(self, rhs: Value, int: &I) -> FResult<Value>214 pub(crate) fn sub<I: Interrupt>(self, rhs: Value, int: &I) -> FResult<Value> { 215 let rhs = rhs.expect_num()?; 216 217 if rhs.unit_equal_to("day", int)? { 218 let num_days = rhs.try_as_usize_unit(int)?; 219 let mut result = self; 220 for _ in 0..num_days { 221 result = result.prev(); 222 } 223 Ok(Value::Date(result)) 224 } else if rhs.unit_equal_to("week", int)? { 225 let num_weeks = rhs.try_as_usize_unit(int)?; 226 let mut result = self; 227 for _ in 0..num_weeks { 228 for _ in 0..7 { 229 result = result.prev(); 230 } 231 } 232 Ok(Value::Date(result)) 233 } else if rhs.unit_equal_to("month", int)? { 234 let num_months = rhs.try_as_usize_unit(int)?; 235 let result = self 236 .diff_months(-i64::try_from(num_months).map_err(|_| FendError::ValueTooLarge)?)?; 237 Ok(Value::Date(result)) 238 } else if rhs.unit_equal_to("year", int)? { 239 let num_years = rhs.try_as_usize_unit(int)?; 240 let num_months = num_years * 12; 241 let result = self 242 .diff_months(-i64::try_from(num_months).map_err(|_| FendError::ValueTooLarge)?)?; 243 Ok(Value::Date(result)) 244 } else { 245 Err(FendError::ExpectedANumber) 246 } 247 } 248 } 249 250 impl fmt::Debug for Date { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result251 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 252 write!( 253 f, 254 "{}, {} {} {}", 255 self.day_of_week(), 256 self.day, 257 self.month, 258 self.year 259 ) 260 } 261 } 262 263 impl fmt::Display for Date { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result264 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 265 write!(f, "{self:?}") 266 } 267 } 268