next_web_utils/datetime/
datetime_util.rs

1use chrono::{DateTime, Datelike, Duration, Local, NaiveDate, NaiveDateTime, TimeZone, Utc, FixedOffset};
2
3/// 日期时间工具,提供全面的日期时间操作
4pub struct DateTimeUtil;
5
6impl DateTimeUtil {
7    /// 获取当前时间,格式化为 "YYYY-MM-DD HH:MM:SS.mmm"
8    pub fn now() -> String {
9        let now: DateTime<Local> = Local::now();
10        now.format("%Y-%m-%d %H:%M:%S%.3f").to_string()
11    }
12
13    /// 获取当前时间戳(毫秒)
14    pub fn timestamp() -> i64 {
15        Local::now().timestamp_millis()
16    }
17
18    /// 获取当前日期,格式化为 "YYYY-MM-DD"
19    pub fn date() -> String {
20        Local::now().format("%Y-%m-%d").to_string()
21    }
22
23    /// 获取当前时间,格式化为 "HH:MM:SS"
24    pub fn time() -> String {
25        Local::now().format("%H:%M:%S").to_string()
26    }
27
28    /// 自定义格式化当前时间
29    pub fn format_now(fmt: &str) -> String {
30        Local::now().format(fmt).to_string()
31    }
32
33    /// 将时间戳转换为日期时间字符串
34    pub fn from_timestamp(timestamp: i64, fmt: &str) -> String {
35        let dt = Local.timestamp_opt(timestamp, 0).unwrap();
36        dt.format(fmt).to_string()
37    }
38
39    /// 将字符串解析为 NaiveDateTime
40    pub fn parse(datetime_str: &str, fmt: &str) -> Option<NaiveDateTime> {
41        NaiveDateTime::parse_from_str(datetime_str, fmt).ok()
42    }
43
44    /// 检查是否为同一天
45    pub fn is_same_day(dt1: &NaiveDateTime, dt2: &NaiveDateTime) -> bool {
46        dt1.date() == dt2.date()
47    }
48
49    /// 添加天数
50    pub fn add_days(dt: &NaiveDateTime, days: i64) -> NaiveDateTime {
51        *dt + Duration::days(days)
52    }
53
54    /// 添加小时
55    pub fn add_hours(dt: &NaiveDateTime, hours: i64) -> NaiveDateTime {
56        *dt + Duration::hours(hours)
57    }
58
59    /// 添加分钟
60    pub fn add_minutes(dt: &NaiveDateTime, minutes: i64) -> NaiveDateTime {
61        *dt + Duration::minutes(minutes)
62    }
63
64    /// 计算两个日期之间的天数差
65    pub fn days_between(dt1: &NaiveDateTime, dt2: &NaiveDateTime) -> i64 {
66        let duration = *dt2 - *dt1;
67        duration.num_days()
68    }
69
70    /// 获取当月第一天
71    pub fn first_day_of_month(year: i32, month: u32) -> Option<NaiveDate> {
72        NaiveDate::from_ymd_opt(year, month, 1)
73    }
74
75    /// 获取当月最后一天
76    pub fn last_day_of_month(year: i32, month: u32) -> Option<NaiveDate> {
77        let first_of_next_month = if month == 12 {
78            NaiveDate::from_ymd_opt(year + 1, 1, 1)
79        } else {
80            NaiveDate::from_ymd_opt(year, month + 1, 1)
81        };
82        
83        first_of_next_month.map(|d| d.pred_opt().unwrap())
84    }
85
86    /// 检查是否为工作日(非周末)
87    pub fn is_weekday(dt: &NaiveDateTime) -> bool {
88        let weekday = dt.weekday().number_from_monday();
89        weekday >= 1 && weekday <= 5
90    }
91
92    /// 检查是否为周末
93    pub fn is_weekend(dt: &NaiveDateTime) -> bool {
94        let weekday = dt.weekday().number_from_monday();
95        weekday == 6 || weekday == 7
96    }
97
98    /// 转换为 UTC 时间
99    pub fn to_utc(dt: DateTime<Local>) -> DateTime<Utc> {
100        dt.with_timezone(&Utc)
101    }
102
103    /// 转换时区
104    pub fn change_timezone(dt: &DateTime<Utc>, hours: i32) -> DateTime<FixedOffset> {
105        let offset = FixedOffset::east_opt(hours * 3600).unwrap();
106        dt.with_timezone(&offset)
107    }
108
109    /// 获取季度
110    pub fn get_quarter(dt: &NaiveDateTime) -> u32 {
111        (dt.month() - 1) / 3 + 1
112    }
113
114    /// 年龄计算
115    pub fn calculate_age(birth_date: &NaiveDate) -> u32 {
116        let today = Local::now().naive_local().date();
117        let age = today.year() - birth_date.year();
118        
119        if today.month() < birth_date.month() || 
120           (today.month() == birth_date.month() && today.day() < birth_date.day()) {
121            return (age - 1) as u32;
122        }
123        
124        age as u32
125    }
126}