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, }
use chrono::{DateTime, Local, TimeZone, Utc};
pub fn format_timestamp(timestamp: u64, format: DateFormat) -> String {
let utc_datetime: DateTime<Utc> = Utc.timestamp_opt(timestamp as i64, 0).unwrap();
let local_datetime: DateTime<Local> = utc_datetime.with_timezone(&Local);
match format {
DateFormat::YearMonthDay => local_datetime.format("%Y-%m-%d").to_string(),
DateFormat::YearMonthDayNoLine => local_datetime.format("%Y%m%d").to_string(),
DateFormat::YearMonthDayChinese => local_datetime.format("%Y年%m月%d日").to_string(),
DateFormat::MonthDayYear => local_datetime.format("%m/%d/%Y").to_string(),
DateFormat::DayMonthYear => local_datetime.format("%d-%m-%Y").to_string(),
DateFormat::DateTime => local_datetime.format("%Y-%m-%d %H:%M:%S").to_string(),
DateFormat::DateTimeWithMillis => local_datetime.format("%Y-%m-%d %H:%M:%S%.3f").to_string(),
}
}