baichun-framework-core 0.1.0

Core module for Baichun-Rust framework
Documentation
// ruoyi-common/src/utils/time.rs
//! 时间处理工具模块

use chrono::{DateTime, Local, NaiveDateTime, TimeZone, Utc};
use serde::Deserialize;
use std::time::{SystemTime, UNIX_EPOCH};

/// 时间工具
pub struct TimeUtils;

impl TimeUtils {
    /// 获取当前时间戳(秒)
    pub fn current_timestamp() -> i64 {
        SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_secs() as i64
    }

    /// 获取当前时间戳(毫秒)
    pub fn current_timestamp_millis() -> i64 {
        SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_millis() as i64
    }

    /// 获取当前日期时间字符串
    pub fn current_datetime_str() -> String {
        Local::now().format("%Y-%m-%d %H:%M:%S").to_string()
    }

    /// 获取当前日期字符串
    pub fn current_date_str() -> String {
        Local::now().format("%Y-%m-%d").to_string()
    }

    /// 获取当前时间字符串
    pub fn current_time_str() -> String {
        Local::now().format("%H:%M:%S").to_string()
    }

    /// 时间戳转日期时间字符串
    pub fn timestamp_to_datetime_str(timestamp: i64) -> String {
        DateTime::<Utc>::from_timestamp(timestamp, 0)
            .unwrap()
            .with_timezone(&Local)
            .format("%Y-%m-%d %H:%M:%S")
            .to_string()
    }

    /// 日期时间字符串转时间戳
    pub fn datetime_str_to_timestamp(datetime_str: &str) -> Option<i64> {
        let naive = NaiveDateTime::parse_from_str(datetime_str, "%Y-%m-%d %H:%M:%S").ok()?;
        let datetime = Local.from_local_datetime(&naive).single()?;
        Some(datetime.timestamp())
    }

    /// 格式化日期时间
    pub fn format_datetime(datetime: DateTime<Local>, format: &str) -> String {
        datetime.format(format).to_string()
    }

    /// 解析日期时间字符串
    pub fn parse_datetime(datetime_str: &str, format: &str) -> Option<DateTime<Local>> {
        let naive = NaiveDateTime::parse_from_str(datetime_str, format).ok()?;
        Local.from_local_datetime(&naive).single()
    }

    /// 计算两个时间的差值(秒)
    pub fn diff_seconds(start: DateTime<Local>, end: DateTime<Local>) -> i64 {
        end.timestamp() - start.timestamp()
    }

    /// 增加秒数
    pub fn add_seconds(datetime: DateTime<Local>, seconds: i64) -> DateTime<Local> {
        datetime + chrono::Duration::seconds(seconds)
    }

    /// 增加分钟
    pub fn add_minutes(datetime: DateTime<Local>, minutes: i64) -> DateTime<Local> {
        datetime + chrono::Duration::minutes(minutes)
    }

    /// 增加小时
    pub fn add_hours(datetime: DateTime<Local>, hours: i64) -> DateTime<Local> {
        datetime + chrono::Duration::hours(hours)
    }

    /// 增加天数
    pub fn add_days(datetime: DateTime<Local>, days: i64) -> DateTime<Local> {
        datetime + chrono::Duration::days(days)
    }

    /// 是否为同一天
    pub fn is_same_day(dt1: DateTime<Local>, dt2: DateTime<Local>) -> bool {
        dt1.date_naive() == dt2.date_naive()
    }

    /// 是否为今天
    pub fn is_today(dt: DateTime<Local>) -> bool {
        Self::is_same_day(dt, Local::now())
    }

    /// 获取开始时间
    pub fn start_of_day(dt: DateTime<Local>) -> DateTime<Local> {
        dt.date_naive()
            .and_hms_opt(0, 0, 0)
            .unwrap()
            .and_local_timezone(Local)
            .unwrap()
    }

    /// 获取结束时间
    pub fn end_of_day(dt: DateTime<Local>) -> DateTime<Local> {
        dt.date_naive()
            .and_hms_opt(23, 59, 59)
            .unwrap()
            .and_local_timezone(Local)
            .unwrap()
    }

    /// 获取当前时间
    #[allow(dead_code)]
    pub fn current_datetime() -> DateTime<Utc> {
        Utc::now()
    }

    /// 转换为本地时间
    pub fn to_local(dt: &DateTime<Utc>) -> DateTime<Local> {
        dt.with_timezone(&Local)
    }

    /// 序列化响应的时间格式
    pub fn serialize_optional_datetime<S>(
        value: &Option<DateTime<Utc>>,
        serializer: S,
    ) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        if let Some(dt) = value {
            serializer.serialize_str(&dt.format("%Y-%m-%d %H:%M:%S").to_string())
        } else {
            serializer.serialize_none()
        }
    }

    // 添加自定义反序列化函数,处理可选日期时间
    pub fn deserialize_optional_datetime<'de, D>(
        deserializer: D,
    ) -> Result<Option<DateTime<Utc>>, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let s: Option<String> = Option::deserialize(deserializer)?;
        if let Some(s) = s {
            if s.is_empty() {
                return Ok(None);
            }

            // 尝试解析日期字符串
            match chrono::NaiveDate::parse_from_str(&s, "%Y-%m-%d") {
                Ok(date) => {
                    // 转换为DateTime<Utc>
                    let datetime = chrono::DateTime::<Utc>::from_naive_utc_and_offset(
                        date.and_hms_opt(0, 0, 0).unwrap(),
                        Utc,
                    );
                    Ok(Some(datetime))
                }
                Err(_) => {
                    //解析失败时尝试使用带时分秒的格式解析
                    match chrono::NaiveDateTime::parse_from_str(&s, "%Y-%m-%d %H:%M:%S") {
                        Ok(datetime) => {
                            // 转换为DateTime<Utc>
                            let datetime =
                                chrono::DateTime::<Utc>::from_naive_utc_and_offset(datetime, Utc);
                            Ok(Some(datetime))
                        }
                        Err(_) => Err(serde::de::Error::custom("无法解析日期时间字符串")),
                    }
                }
            }
        } else {
            Ok(None)
        }
    }

    /// 格式化时间间隔
    pub fn format_duration(duration: std::time::Duration) -> String {
        let years = duration.as_secs() / 3600 / 24 / 365;
        let months = (duration.as_secs() % (3600 * 24 * 365)) / (3600 * 24 * 30);
        let days = (duration.as_secs() % (3600 * 24 * 365)) / (3600 * 24);
        let hours = (duration.as_secs() % (3600 * 24)) / 3600;
        let minutes = (duration.as_secs() % 3600) / 60;
        let seconds = duration.as_secs() % 60;
        if years > 0 {
            format!(
                "{}{}{}{}小时{}分钟{}",
                years, months, days, hours, minutes, seconds
            )
        } else if months > 0 {
            format!(
                "{}{}{}小时{}分钟{}",
                months, days, hours, minutes, seconds
            )
        } else if days > 0 {
            format!("{}{}小时{}分钟{}", days, hours, minutes, seconds)
        } else {
            format!("{}小时{}分钟{}", hours, minutes, seconds)
        }
    }
}