Parse DateTime from Unix timestamp

This commit is contained in:
Nathan Fisher 2023-06-11 01:45:15 -04:00
parent c905e20b36
commit 3dcb5b6991
2 changed files with 118 additions and 2 deletions

116
src/time/epoch.rs Normal file
View file

@ -0,0 +1,116 @@
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));
}
}

View file

@ -1,13 +1,13 @@
//! A container representing a moment in ISO-8601 format Time
use std::{cmp::Ordering, fmt, str::FromStr};
use std::{fmt, str::FromStr};
pub mod epoch;
mod error;
mod parser;
pub use {error::Error, parser::Parser};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use x509_parser::der_parser::ber::ber_read_element_header;
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]