116 lines
2.8 KiB
Rust
116 lines
2.8 KiB
Rust
use super::{DateTime, TimeZone};
|
|
|
|
pub const SECS_PER_DAY: i64 = 86400;
|
|
|
|
fn days_since_epoch(ts: i64) -> i64 {
|
|
ts / SECS_PER_DAY
|
|
}
|
|
|
|
fn is_leap(year: i64) -> bool {
|
|
year % 4 == 0 && (year % 100 != 0 || year % 16 == 0)
|
|
}
|
|
|
|
fn year_from_ts_with_remainder(ts: i64) -> (i64, i64) {
|
|
let mut year = 1970;
|
|
let mut days = days_since_epoch(ts);
|
|
loop {
|
|
let days_in_year = if is_leap(year) {
|
|
366
|
|
} else {
|
|
365
|
|
};
|
|
if days > days_in_year {
|
|
days -= days_in_year;
|
|
year += 1;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
(year, days)
|
|
}
|
|
|
|
fn days_in_month(month: u8, year: i64) -> i64 {
|
|
assert!(month < 13);
|
|
match month {
|
|
1 | 3 | 5 | 7 | 10 | 12 => 31,
|
|
2 => {
|
|
if is_leap(year) {
|
|
29
|
|
} else {
|
|
28
|
|
}
|
|
},
|
|
4 | 6 | 9 | 11 => 30,
|
|
_ => unreachable!(),
|
|
}
|
|
}
|
|
|
|
fn month_and_days_from_ordinal(days: i64, year: i64) -> (u8, i64) {
|
|
assert!(
|
|
if is_leap(year) {
|
|
days < 366
|
|
} else {
|
|
days < 365
|
|
}
|
|
);
|
|
let mut days = days;
|
|
let mut month = 1;
|
|
while days_in_month(month, year) <= days {
|
|
days -= days_in_month(month, year);
|
|
month += 1;
|
|
}
|
|
(month, days)
|
|
}
|
|
|
|
pub(super) fn date_time_from_ts(ts: i64) -> DateTime {
|
|
let (year, days) = year_from_ts_with_remainder(ts);
|
|
let (month, days) = month_and_days_from_ordinal(days, year);
|
|
let seconds = ts % SECS_PER_DAY;
|
|
println!("Seconds: {seconds}");
|
|
let minutes = seconds / 60;
|
|
println!("Minutes: {minutes}");
|
|
let second = seconds % 60;
|
|
let hour = minutes / 60;
|
|
let minute = minutes % 60;
|
|
DateTime {
|
|
year: year as u32,
|
|
month: month.try_into().unwrap(),
|
|
day: (days + 1).try_into().unwrap(),
|
|
hour: Some((hour + 1).try_into().unwrap()),
|
|
minute: Some((minute).try_into().unwrap()),
|
|
second: Some(second.try_into().unwrap()),
|
|
tz: Some(TimeZone::UTC),
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn get_year() {
|
|
let ts = 1686459092;
|
|
let (y, r) = year_from_ts_with_remainder(ts);
|
|
assert_eq!(y, 2023);
|
|
assert_eq!(r, 161);
|
|
}
|
|
|
|
#[test]
|
|
fn get_month_and_days() {
|
|
let ts = 1686459092;
|
|
let (year, days) = year_from_ts_with_remainder(ts);
|
|
let (month, days) = month_and_days_from_ordinal(days, year);
|
|
assert_eq!(month, 6);
|
|
assert_eq!(days, 10);
|
|
}
|
|
|
|
#[test]
|
|
fn get_datetime() {
|
|
let ts = 1686462068;
|
|
let dt = date_time_from_ts(ts);
|
|
assert_eq!(dt.day, 11);
|
|
assert_eq!(dt.hour, Some(6));
|
|
assert_eq!(dt.minute, Some(41));
|
|
assert_eq!(dt.second, Some(8));
|
|
}
|
|
}
|