use std::ffi::c_int;
use std::fmt::{Display, Formatter};
use std::time::{SystemTime, UNIX_EPOCH};
#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct Tm {
tm_sec: c_int, tm_min: c_int, tm_hour: c_int, tm_mday: c_int, tm_mon: c_int, tm_year: c_int, tm_wday: c_int, tm_yday: c_int, tm_isdst: c_int, }
unsafe extern "C" {
fn localtime_r(timep: *const i64, result: *mut Tm) -> *mut Tm;
}
#[derive(Debug)]
pub struct Time {
year: i32,
month: i32,
day: i32,
hour: i32,
minute: i32,
second: i32,
}
impl Time {
pub fn now() -> Result<Self, TimeError> {
let now = SystemTime::now();
Time::try_from(now)
}
pub fn new(seconds: i64) -> Result<Self, TimeError> {
let mut tm: Tm = unsafe { std::mem::zeroed() };
let result = unsafe { localtime_r(&seconds, &mut tm) };
if result.is_null() {
return Err(TimeError::InvalidTime);
}
Ok(tm.into())
}
pub fn year(&self) -> i32 {
self.year
}
pub fn month(&self) -> i32 {
self.month
}
pub fn day(&self) -> i32 {
self.day
}
pub fn hour(&self) -> i32 {
self.hour
}
pub fn minute(&self) -> i32 {
self.minute
}
pub fn second(&self) -> i32 {
self.second
}
pub fn format_time(&self) -> String {
format!(
"{:04}-{:02}-{:02} {:02}:{:02}:{:02}",
self.year, self.month, self.day, self.hour, self.minute, self.second
)
}
}
impl Display for Time {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.format_time())
}
}
impl TryFrom<SystemTime> for Time {
type Error = TimeError;
fn try_from(time: SystemTime) -> Result<Self, Self::Error> {
let seconds = time.duration_since(UNIX_EPOCH)?.as_secs() as i64;
Time::new(seconds)
}
}
impl From<Tm> for Time {
fn from(tm: Tm) -> Self {
Self {
year: tm.tm_year + 1900,
month: tm.tm_mon + 1,
day: tm.tm_mday,
hour: tm.tm_hour,
minute: tm.tm_min,
second: tm.tm_sec,
}
}
}
#[derive(Debug)]
pub enum TimeError {
SystemTimeError(std::time::SystemTimeError),
InvalidTime,
}
impl From<std::time::SystemTimeError> for TimeError {
fn from(err: std::time::SystemTimeError) -> Self {
TimeError::SystemTimeError(err)
}
}