#[derive(Debug, Clone)]
pub struct Timestamp {
pub year: i32,
pub month: u8,
pub day: u8,
pub hour: u8,
pub minute: u8,
pub second: u8,
pub weekday: u8,
}
impl Timestamp {
pub fn as_string(&self) -> String {
let mut sign = "";
if self.year.is_negative() {
sign = "-";
}
format!(
"{sign}{year:0>4}-{month:0>2}-{day:0>2} {hour:0>2}:{minute:0>2}:{second:0>2}",
year = self.year.abs(),
month = self.month,
day = self.day,
hour = self.hour,
minute = self.minute,
second = self.second
)
}
pub fn as_string_utc(&self) -> String {
format!("{v} +0000", v = self.as_string())
}
pub fn year(&self) -> i32 {
self.year
}
pub fn month(&self) -> u8 {
self.month
}
pub fn day(&self) -> u8 {
self.day
}
pub fn hour(&self) -> u8 {
self.hour
}
pub fn minute(&self) -> u8 {
self.minute
}
pub fn second(&self) -> u8 {
self.second
}
pub fn weekday(&self) -> u8 {
self.weekday
}
}
pub fn uts2ts(seconds: i64) -> Timestamp {
const LEAPOCH: i64 = 946684800 + 86400 * (31 + 29);
const DAYS_PER_400Y: i64 = 365 * 400 + 97;
const DAYS_PER_100Y: i64 = 365 * 100 + 24;
const DAYS_PER_4Y: i64 = 365 * 4 + 1;
let secs = seconds - LEAPOCH;
let mut days = secs / 86400;
let mut remsecs = secs % 86400;
if remsecs < 0 {
remsecs += 86400;
days -= 1;
}
let mut wday = (3 + days) % 7;
if wday < 0 {
wday += 7;
}
let mut qc_cycles = days / DAYS_PER_400Y;
let mut remdays = days % DAYS_PER_400Y;
if remdays < 0 {
remdays += DAYS_PER_400Y;
qc_cycles -= 1;
}
let mut c_cycles = remdays / DAYS_PER_100Y;
if c_cycles == 4 {
c_cycles -= 1;
}
remdays -= c_cycles * DAYS_PER_100Y;
let mut q_cycles = remdays / DAYS_PER_4Y;
if q_cycles == 25 {
q_cycles -= 1;
}
remdays -= q_cycles * DAYS_PER_4Y;
let mut remyears = remdays / 365;
if remyears == 4 {
remyears -= 1;
}
remdays -= remyears * 365;
let years = remyears + 4 * q_cycles + 100 * c_cycles + 400 * qc_cycles;
let mut months: i64 = 0;
const DAYS_IN_MONTH: [i64; 12] = [31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29];
while DAYS_IN_MONTH[months as usize] <= remdays {
remdays -= DAYS_IN_MONTH[months as usize];
months += 1;
}
let mut ret_year = years + 2000;
let mut ret_month = months + 2;
if ret_month >= 12 {
ret_month -= 12;
ret_year += 1;
}
ret_month += 1;
let ret_day = remdays + 1;
let ret_weekday = wday;
let ret_hour = remsecs / 3600;
let ret_minute = remsecs / 60 % 60;
let ret_second = remsecs % 60;
Timestamp {
year: ret_year as i32,
month: ret_month as u8,
day: ret_day as u8,
hour: ret_hour as u8,
minute: ret_minute as u8,
second: ret_second as u8,
weekday: ret_weekday as u8,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_uts2ts() {
let ts = uts2ts(204158100);
assert_eq!(ts.year, 1976);
assert_eq!(ts.month, 6);
assert_eq!(ts.day, 20);
assert_eq!(ts.hour, 22);
assert_eq!(ts.minute, 35);
assert_eq!(ts.second, 0);
assert_eq!(ts.weekday, 0);
}
#[test]
fn test_uts2ts_as_string() {
assert_eq!("1976-06-20 22:35:00", uts2ts(204158100).as_string());
assert_eq!("2022-12-31 23:59:59", uts2ts(1672531199).as_string());
assert_eq!("2023-01-01 00:00:00", uts2ts(1672531200).as_string());
assert_eq!("2024-02-29 12:34:56", uts2ts(1709210096).as_string());
assert_eq!("2525-06-20 22:35:00", uts2ts(17528913300).as_string());
assert_eq!("-0001-12-31 23:59:59", uts2ts(-62167219201).as_string());
assert_eq!("0000-01-01 00:00:00", uts2ts(-62167219200).as_string());
assert_eq!("1948-03-19 15:15:15", uts2ts(-687516285).as_string());
assert_eq!("1949-04-27 18:18:18", uts2ts(-652599702).as_string());
}
#[test]
fn test_uts2ts_as_string_utc() {
assert_eq!(
"1976-06-20 22:35:00 +0000",
uts2ts(204158100).as_string_utc()
);
assert_eq!(
"2022-12-31 23:59:59 +0000",
uts2ts(1672531199).as_string_utc()
);
assert_eq!(
"2023-01-01 00:00:00 +0000",
uts2ts(1672531200).as_string_utc()
);
assert_eq!(
"2024-02-29 12:34:56 +0000",
uts2ts(1709210096).as_string_utc()
);
assert_eq!(
"2525-06-20 22:35:00 +0000",
uts2ts(17528913300).as_string_utc()
);
assert_eq!(
"-0001-12-31 23:59:59 +0000",
uts2ts(-62167219201).as_string_utc()
);
assert_eq!(
"0000-01-01 00:00:00 +0000",
uts2ts(-62167219200).as_string_utc()
);
assert_eq!(
"1948-03-19 15:15:15 +0000",
uts2ts(-687516285).as_string_utc()
);
assert_eq!(
"1949-04-27 18:18:18 +0000",
uts2ts(-652599702).as_string_utc()
);
}
#[test]
fn test_uts2ts_getters() {
let ts = uts2ts(204158100);
assert_eq!(ts.year(), 1976);
assert_eq!(ts.month(), 6);
assert_eq!(ts.day(), 20);
assert_eq!(ts.hour(), 22);
assert_eq!(ts.minute(), 35);
assert_eq!(ts.second(), 0);
assert_eq!(ts.weekday(), 0);
}
}