hinoirisetr/src/time.rs

130 lines
3.1 KiB
Rust

use std::ffi::c_int;
use std::fmt::{Display, Formatter};
use std::time::{SystemTime, UNIX_EPOCH};
// Convert seconds since epoch to YYYY-MM-DD HH:MM:SS (UTC)
// Define the Tm struct from the C standard library
#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct Tm {
tm_sec: c_int, // Seconds (0-60)
tm_min: c_int, // Minutes (0-59)
tm_hour: c_int, // Hours (0-23)
tm_mday: c_int, // Day of the month (1-31)
tm_mon: c_int, // Month (0-11)
tm_year: c_int, // Year since 1900
tm_wday: c_int, // Day of the week (0-6, Sunday = 0)
tm_yday: c_int, // Day of the year (0-365)
tm_isdst: c_int, // Daylight saving time flag
}
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)
}
/// seconds: seconds since epoch
pub fn new(seconds: i64) -> Result<Self, TimeError> {
let mut tm: Tm = unsafe { std::mem::zeroed() };
// Call localtime_r with a pointer to our Tm struct
let result = unsafe { localtime_r(&seconds, &mut tm) };
// Check if the conversion was successful
if result.is_null() {
return Err(TimeError::InvalidTime);
}
Ok(tm.into())
}
/// Getter for year
pub fn year(&self) -> i32 {
self.year
}
/// Getter for month
pub fn month(&self) -> i32 {
self.month
}
/// Getter for day
pub fn day(&self) -> i32 {
self.day
}
/// Getter for hour
pub fn hour(&self) -> i32 {
self.hour
}
/// Getter for minute
pub fn minute(&self) -> i32 {
self.minute
}
/// Getter for second
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; // Define an appropriate error type
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)
}
}