date-formatter 0.2.1

A date formatter crate implemented without chrono.
Documentation
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)
    }
}


/// 将 SystemTime 转换为年、月、日、时、分、秒、毫秒
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;

    // 从 1970-01-01 开始计算
    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)
}

/// 将 SystemTime 格式化为字符串 年月日
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))
}

/// 将字符串解析为日期Date
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")
}

/// 计算两个 SystemTime 之间的天数差异
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,       // %Y-%m-%d
    YearMonthDayNoLine,   // %Y%m%d
    YearMonthDayChinese, // %Y年%m月%d日
    MonthDayYear,       // %m/%d/%Y
    DayMonthYear,       // %d-%m-%Y
    DateTime,           // %Y-%m-%d %H:%M:%S
    DateTimeWithMillis, // %Y-%m-%d %H:%M:%S.%f
}

/// 根据时间戳和格式化模板返回格式化后的日期字符串
use chrono::{DateTime, Local, TimeZone, Utc};
pub fn format_timestamp(timestamp: u64, format: DateFormat) -> String {
    // 将时间戳转换为 UTC 时间
    let utc_datetime: DateTime<Utc> = Utc.timestamp_opt(timestamp as i64, 0).unwrap();
    // 将 UTC 时间转换为本地时间(自动获取系统时区)
    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(),
    }
}