diff --git a/src/datetime.rs b/src/datetime.rs new file mode 100644 index 0000000..6bcc19f --- /dev/null +++ b/src/datetime.rs @@ -0,0 +1,122 @@ +// This code was extracted from http://git.musl-libc.org/cgit/musl/tree/src/time?h=v0.9.15 + +pub struct Datetime { + pub year: u16, + pub month: u8, + pub day: u8, + pub hours: u8, + pub minutes: u8, + pub seconds: u8, +} + +impl Datetime { + pub fn unix_epoch(&self) -> u64 { + let mut year: i64 = self.year as i64 - 1900; + let mut month: i64 = self.month as i64 - 1; + if month >= 12 || month < 0 { + let mut adj = month / 12; + month %= 12; + if month < 0 { + adj -= 1; + month += 12; + } + year += adj as i64; + } + let (mut t, is_leap) = year_to_secs(year); + t += month_to_secs(month, is_leap); + t += 86400 * (self.day as i64 - 1); + t += 3600 * self.hours as i64; + t += 60 * self.minutes as i64; + t += self.seconds as i64; + t as u64 + } +} + +fn year_to_secs(year: i64) -> (i64, bool) { + let is_leap: bool; + let res: i64; + + if year - 2 <= 136 { + let y = year as i32; + let mut leaps = (y - 68) >> 2; + if !((y - 68) & 3 != 0) { + leaps -= 1; + is_leap = true; + } else { + is_leap = false; + } + res = 31536000 * (y - 70) as i64 + 86400 * leaps as i64; + } else { + let mut cycles: i64; + let centuries: i64; + let mut leaps: i64; + let mut rem: i64; + + cycles = (year - 100) / 400; + rem = (year - 100) % 400; + if rem < 0 { + cycles -= 1; + rem += 400; + } + if rem == 0 { + is_leap = true; + centuries = 0; + leaps = 0; + } else { + if rem >= 200 { + if rem >= 300 { + centuries = 3; + rem -= 300; + } else { + centuries = 2; + rem -= 200; + } + } else { + if rem >= 100 { + centuries = 1; + rem -= 100; + } else { + centuries = 0; + } + } + if rem == 0 { + is_leap = false; + leaps = 0; + } else { + leaps = rem / 4; + rem %= 4; + is_leap = rem == 0; + } + } + + leaps += 97 * cycles + 24 * centuries - (is_leap as i64); + + res = (year - 100) * 31536000 + leaps * 86400 + 946684800 + 86400; + } + + (res, is_leap) +} + +fn month_to_secs(month: i64, is_leap: bool) -> i64 { + const SECS_THROUGH_MONTH: [i64; 12] = [ + 0, // Jan + 31 * 86400, // Feb + 59 * 86400, // Mar + 90 * 86400, // Apr + 120 * 86400, // May + 151 * 86400, // Jun + 181 * 86400, // Jul + 212 * 86400, // Aug + 243 * 86400, // Sep + 273 * 86400, // Oct + 304 * 86400, // Nov + 334 * 86400, // Dec + ]; + + let mut t = SECS_THROUGH_MONTH[month as usize]; + if is_leap && month >= 2 { + t += 86400; + } + + t +}