baichun_framework_core/utils/
time.rs1use chrono::{DateTime, Local, NaiveDateTime, TimeZone, Utc};
5use serde::Deserialize;
6use std::time::{SystemTime, UNIX_EPOCH};
7
8pub struct TimeUtils;
10
11impl TimeUtils {
12 pub fn current_timestamp() -> i64 {
14 SystemTime::now()
15 .duration_since(UNIX_EPOCH)
16 .unwrap()
17 .as_secs() as i64
18 }
19
20 pub fn current_timestamp_millis() -> i64 {
22 SystemTime::now()
23 .duration_since(UNIX_EPOCH)
24 .unwrap()
25 .as_millis() as i64
26 }
27
28 pub fn current_datetime_str() -> String {
30 Local::now().format("%Y-%m-%d %H:%M:%S").to_string()
31 }
32
33 pub fn current_date_str() -> String {
35 Local::now().format("%Y-%m-%d").to_string()
36 }
37
38 pub fn current_time_str() -> String {
40 Local::now().format("%H:%M:%S").to_string()
41 }
42
43 pub fn timestamp_to_datetime_str(timestamp: i64) -> String {
45 DateTime::<Utc>::from_timestamp(timestamp, 0)
46 .unwrap()
47 .with_timezone(&Local)
48 .format("%Y-%m-%d %H:%M:%S")
49 .to_string()
50 }
51
52 pub fn datetime_str_to_timestamp(datetime_str: &str) -> Option<i64> {
54 let naive = NaiveDateTime::parse_from_str(datetime_str, "%Y-%m-%d %H:%M:%S").ok()?;
55 let datetime = Local.from_local_datetime(&naive).single()?;
56 Some(datetime.timestamp())
57 }
58
59 pub fn format_datetime(datetime: DateTime<Local>, format: &str) -> String {
61 datetime.format(format).to_string()
62 }
63
64 pub fn parse_datetime(datetime_str: &str, format: &str) -> Option<DateTime<Local>> {
66 let naive = NaiveDateTime::parse_from_str(datetime_str, format).ok()?;
67 Local.from_local_datetime(&naive).single()
68 }
69
70 pub fn diff_seconds(start: DateTime<Local>, end: DateTime<Local>) -> i64 {
72 end.timestamp() - start.timestamp()
73 }
74
75 pub fn add_seconds(datetime: DateTime<Local>, seconds: i64) -> DateTime<Local> {
77 datetime + chrono::Duration::seconds(seconds)
78 }
79
80 pub fn add_minutes(datetime: DateTime<Local>, minutes: i64) -> DateTime<Local> {
82 datetime + chrono::Duration::minutes(minutes)
83 }
84
85 pub fn add_hours(datetime: DateTime<Local>, hours: i64) -> DateTime<Local> {
87 datetime + chrono::Duration::hours(hours)
88 }
89
90 pub fn add_days(datetime: DateTime<Local>, days: i64) -> DateTime<Local> {
92 datetime + chrono::Duration::days(days)
93 }
94
95 pub fn is_same_day(dt1: DateTime<Local>, dt2: DateTime<Local>) -> bool {
97 dt1.date_naive() == dt2.date_naive()
98 }
99
100 pub fn is_today(dt: DateTime<Local>) -> bool {
102 Self::is_same_day(dt, Local::now())
103 }
104
105 pub fn start_of_day(dt: DateTime<Local>) -> DateTime<Local> {
107 dt.date_naive()
108 .and_hms_opt(0, 0, 0)
109 .unwrap()
110 .and_local_timezone(Local)
111 .unwrap()
112 }
113
114 pub fn end_of_day(dt: DateTime<Local>) -> DateTime<Local> {
116 dt.date_naive()
117 .and_hms_opt(23, 59, 59)
118 .unwrap()
119 .and_local_timezone(Local)
120 .unwrap()
121 }
122
123 #[allow(dead_code)]
125 pub fn current_datetime() -> DateTime<Utc> {
126 Utc::now()
127 }
128
129 pub fn to_local(dt: &DateTime<Utc>) -> DateTime<Local> {
131 dt.with_timezone(&Local)
132 }
133
134 pub fn serialize_optional_datetime<S>(
136 value: &Option<DateTime<Utc>>,
137 serializer: S,
138 ) -> Result<S::Ok, S::Error>
139 where
140 S: serde::Serializer,
141 {
142 if let Some(dt) = value {
143 serializer.serialize_str(&dt.format("%Y-%m-%d %H:%M:%S").to_string())
144 } else {
145 serializer.serialize_none()
146 }
147 }
148
149 pub fn deserialize_optional_datetime<'de, D>(
151 deserializer: D,
152 ) -> Result<Option<DateTime<Utc>>, D::Error>
153 where
154 D: serde::Deserializer<'de>,
155 {
156 let s: Option<String> = Option::deserialize(deserializer)?;
157 if let Some(s) = s {
158 if s.is_empty() {
159 return Ok(None);
160 }
161
162 match chrono::NaiveDate::parse_from_str(&s, "%Y-%m-%d") {
164 Ok(date) => {
165 let datetime = chrono::DateTime::<Utc>::from_naive_utc_and_offset(
167 date.and_hms_opt(0, 0, 0).unwrap(),
168 Utc,
169 );
170 Ok(Some(datetime))
171 }
172 Err(_) => {
173 match chrono::NaiveDateTime::parse_from_str(&s, "%Y-%m-%d %H:%M:%S") {
175 Ok(datetime) => {
176 let datetime =
178 chrono::DateTime::<Utc>::from_naive_utc_and_offset(datetime, Utc);
179 Ok(Some(datetime))
180 }
181 Err(_) => Err(serde::de::Error::custom("无法解析日期时间字符串")),
182 }
183 }
184 }
185 } else {
186 Ok(None)
187 }
188 }
189
190 pub fn format_duration(duration: std::time::Duration) -> String {
192 let years = duration.as_secs() / 3600 / 24 / 365;
193 let months = (duration.as_secs() % (3600 * 24 * 365)) / (3600 * 24 * 30);
194 let days = (duration.as_secs() % (3600 * 24 * 365)) / (3600 * 24);
195 let hours = (duration.as_secs() % (3600 * 24)) / 3600;
196 let minutes = (duration.as_secs() % 3600) / 60;
197 let seconds = duration.as_secs() % 60;
198 if years > 0 {
199 format!(
200 "{}年{}月{}日 {}小时{}分钟{}秒",
201 years, months, days, hours, minutes, seconds
202 )
203 } else if months > 0 {
204 format!(
205 "{}月{}日 {}小时{}分钟{}秒",
206 months, days, hours, minutes, seconds
207 )
208 } else if days > 0 {
209 format!("{}日 {}小时{}分钟{}秒", days, hours, minutes, seconds)
210 } else {
211 format!("{}小时{}分钟{}秒", hours, minutes, seconds)
212 }
213 }
214}