use std::time::{SystemTime, UNIX_EPOCH};
use std::fmt;
#[derive(Debug)]
pub struct Date {
year: u16,
month: u8,
day: u8,
}
impl Date {
pub fn new(year: u16, month: u8, day: u8) -> Option<Self> {
if month < 1 || month > 12 || day < 1 || day > 31 {
return None;
}
Some(Date { year, month, day })
}
}
impl fmt::Display for Date {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:04}-{:02}-{:02}", self.year, self.month, self.day)
}
}
fn system_time_to_units(time: SystemTime) -> (u16, u8, u8, u8, u8, u8, u16) {
let duration = time.duration_since(UNIX_EPOCH).expect("Time went backwards");
let secs = duration.as_secs();
let nanos = duration.subsec_nanos();
let days_since_epoch = secs / 86400;
let remaining_secs = secs % 86400;
let mut year = 1970;
let mut remaining_days = days_since_epoch as i64;
loop {
let is_leap_year = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
let days_in_year = if is_leap_year { 366 } else { 365 };
if remaining_days < days_in_year {
break;
}
remaining_days -= days_in_year;
year += 1;
}
let is_leap_year = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
let days_in_month = [
31,
if is_leap_year { 29 } else { 28 },
31,
30,
31,
30,
31,
31,
30,
31,
30,
31,
];
let mut month = 1;
for &days in &days_in_month {
if remaining_days < days as i64 {
break;
}
remaining_days -= days as i64;
month += 1;
}
let day = remaining_days as u8 + 1;
let hour = (remaining_secs / 3600) as u8;
let minute = ((remaining_secs % 3600) / 60) as u8;
let second = (remaining_secs % 60) as u8;
let millisecond = (nanos / 1_000_000) as u16;
(year as u16, month as u8, day, hour, minute, second, millisecond)
}
pub fn format_date(time: SystemTime, format: &str) -> String {
let (year, month, day,_,_,_,_) = system_time_to_units(time);
format
.replace("%Y", &year.to_string())
.replace("%m", &format!("{:02}", month))
.replace("%d", &format!("{:02}", day))
}
pub fn parse_date(date_str: &str) -> Result<Date, &'static str> {
let parts: Vec<&str> = date_str.split('-').collect();
if parts.len() != 3 {
return Err("Invalid date format");
}
let year = parts[0].parse().map_err(|_| "Invalid year")?;
let month = parts[1].parse().map_err(|_| "Invalid month")?;
let day = parts[2].parse().map_err(|_| "Invalid day")?;
Date::new(year, month, day).ok_or("Invalid date")
}
pub fn days_between(time1: SystemTime, time2: SystemTime) -> i64 {
let duration1 = time1
.duration_since(UNIX_EPOCH)
.expect("Time went backwards");
let duration2 = time2
.duration_since(UNIX_EPOCH)
.expect("Time went backwards");
let secs1 = duration1.as_secs();
let secs2 = duration2.as_secs();
let days1 = secs1 / 86400;
let days2 = secs2 / 86400;
(days1 as i64 - days2 as i64).abs()
}
pub enum DateFormat {
YearMonthDay, YearMonthDayNoLine, YearMonthDayChinese, MonthDayYear, DayMonthYear, DateTime, DateTimeWithMillis, }
pub fn format_timestamp(timestamp: u64, format: DateFormat) -> String {
let datetime = UNIX_EPOCH + std::time::Duration::from_secs(timestamp);
let (year, month, day, hour, minute, second, millisecond) = system_time_to_units(datetime);
match format {
DateFormat::YearMonthDay => format!("{:04}-{:02}-{:02}", year, month, day),
DateFormat::YearMonthDayNoLine => format!("{:04}{:02}{:02}", year, month, day),
DateFormat::YearMonthDayChinese => format!("{:04}年{:02}月{:02}日", year, month, day),
DateFormat::MonthDayYear => format!("{:02}/{:02}/{:04}", month, day, year),
DateFormat::DayMonthYear => format!("{:02}-{:02}-{:04}", day, month, year),
DateFormat::DateTime => format!(
"{:04}-{:02}-{:02} {:02}:{:02}:{:02}",
year, month, day, hour, minute, second
),
DateFormat::DateTimeWithMillis => format!(
"{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:03}",
year, month, day, hour, minute, second, millisecond
),
}
}