1use chrono::{NaiveDate, NaiveDateTime, Utc};
2
3pub struct DateHelper;
5
6impl DateHelper {
7 pub fn time_ago(date: &NaiveDateTime) -> String {
9 let now = Utc::now().naive_utc();
10 let diff = now.signed_duration_since(*date);
11
12 let seconds = diff.num_seconds();
13 let minutes = diff.num_minutes();
14 let hours = diff.num_hours();
15 let days = diff.num_days();
16
17 if seconds < 0 {
18 return "Dans le futur".to_string();
19 }
20
21 if seconds < 60 {
22 "A l'instant".to_string()
23 } else if minutes < 60 {
24 format!("Il y a {} min", minutes)
25 } else if hours < 24 {
26 format!("Il y a {} h", hours)
27 } else if days < 30 {
28 format!("Il y a {} j", days)
29 } else if days < 365 {
30 let months = days / 30;
31 format!("Il y a {} mois", months)
32 } else {
33 let years = days / 365;
34 if years == 1 {
35 "Il y a 1 an".to_string()
36 } else {
37 format!("Il y a {} ans", years)
38 }
39 }
40 }
41
42 pub fn format(date: &NaiveDateTime, fmt: &str) -> String {
44 date.format(fmt).to_string()
45 }
46
47 pub fn format_fr(date: &NaiveDateTime) -> String {
49 date.format("%d/%m/%Y").to_string()
50 }
51
52 pub fn format_fr_time(date: &NaiveDateTime) -> String {
54 date.format("%d/%m/%Y %H:%M").to_string()
55 }
56
57 pub fn format_iso(date: &NaiveDateTime) -> String {
59 date.format("%Y-%m-%d").to_string()
60 }
61
62 pub fn format_iso_time(date: &NaiveDateTime) -> String {
64 date.format("%Y-%m-%d %H:%M:%S").to_string()
65 }
66
67 pub fn is_past(date: &NaiveDateTime) -> bool {
69 *date < Utc::now().naive_utc()
70 }
71
72 pub fn is_future(date: &NaiveDateTime) -> bool {
74 *date > Utc::now().naive_utc()
75 }
76
77 pub fn is_today(date: &NaiveDate) -> bool {
79 *date == Utc::now().date_naive()
80 }
81
82 pub fn diff_in_days(from: &NaiveDateTime, to: &NaiveDateTime) -> i64 {
84 to.signed_duration_since(*from).num_days()
85 }
86
87 pub fn diff_in_hours(from: &NaiveDateTime, to: &NaiveDateTime) -> i64 {
89 to.signed_duration_since(*from).num_hours()
90 }
91
92 pub fn diff_in_minutes(from: &NaiveDateTime, to: &NaiveDateTime) -> i64 {
94 to.signed_duration_since(*from).num_minutes()
95 }
96
97 pub fn now() -> NaiveDateTime {
99 Utc::now().naive_utc()
100 }
101
102 pub fn today() -> NaiveDate {
104 Utc::now().date_naive()
105 }
106
107 pub fn start_of_day(date: &NaiveDate) -> NaiveDateTime {
109 date.and_hms_opt(0, 0, 0).unwrap()
110 }
111
112 pub fn end_of_day(date: &NaiveDate) -> NaiveDateTime {
114 date.and_hms_opt(23, 59, 59).unwrap()
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121
122 fn make_dt(y: i32, m: u32, d: u32, h: u32, mi: u32, s: u32) -> NaiveDateTime {
123 NaiveDate::from_ymd_opt(y, m, d)
124 .unwrap()
125 .and_hms_opt(h, mi, s)
126 .unwrap()
127 }
128
129 #[test]
130 fn test_format_fr() {
131 let dt = make_dt(2024, 3, 15, 14, 30, 0);
132 assert_eq!(DateHelper::format_fr(&dt), "15/03/2024");
133 }
134
135 #[test]
136 fn test_format_fr_time() {
137 let dt = make_dt(2024, 3, 15, 14, 30, 0);
138 assert_eq!(DateHelper::format_fr_time(&dt), "15/03/2024 14:30");
139 }
140
141 #[test]
142 fn test_format_iso() {
143 let dt = make_dt(2024, 3, 15, 14, 30, 0);
144 assert_eq!(DateHelper::format_iso(&dt), "2024-03-15");
145 }
146
147 #[test]
148 fn test_format_iso_time() {
149 let dt = make_dt(2024, 3, 15, 14, 30, 0);
150 assert_eq!(DateHelper::format_iso_time(&dt), "2024-03-15 14:30:00");
151 }
152
153 #[test]
154 fn test_format_custom() {
155 let dt = make_dt(2024, 3, 15, 14, 30, 0);
156 assert_eq!(DateHelper::format(&dt, "%H:%M"), "14:30");
157 }
158
159 #[test]
160 fn test_is_past() {
161 let past = make_dt(2020, 1, 1, 0, 0, 0);
162 assert!(DateHelper::is_past(&past));
163 }
164
165 #[test]
166 fn test_is_future() {
167 let future = make_dt(2099, 1, 1, 0, 0, 0);
168 assert!(DateHelper::is_future(&future));
169 }
170
171 #[test]
172 fn test_diff_in_days() {
173 let from = make_dt(2024, 1, 1, 0, 0, 0);
174 let to = make_dt(2024, 1, 11, 0, 0, 0);
175 assert_eq!(DateHelper::diff_in_days(&from, &to), 10);
176 }
177
178 #[test]
179 fn test_diff_in_hours() {
180 let from = make_dt(2024, 1, 1, 0, 0, 0);
181 let to = make_dt(2024, 1, 1, 5, 0, 0);
182 assert_eq!(DateHelper::diff_in_hours(&from, &to), 5);
183 }
184
185 #[test]
186 fn test_diff_in_minutes() {
187 let from = make_dt(2024, 1, 1, 0, 0, 0);
188 let to = make_dt(2024, 1, 1, 1, 30, 0);
189 assert_eq!(DateHelper::diff_in_minutes(&from, &to), 90);
190 }
191
192 #[test]
193 fn test_start_of_day() {
194 let date = NaiveDate::from_ymd_opt(2024, 3, 15).unwrap();
195 let start = DateHelper::start_of_day(&date);
196 assert_eq!(start, make_dt(2024, 3, 15, 0, 0, 0));
197 }
198
199 #[test]
200 fn test_end_of_day() {
201 let date = NaiveDate::from_ymd_opt(2024, 3, 15).unwrap();
202 let end = DateHelper::end_of_day(&date);
203 assert_eq!(end, make_dt(2024, 3, 15, 23, 59, 59));
204 }
205
206 #[test]
207 fn test_time_ago_future() {
208 let future = make_dt(2099, 1, 1, 0, 0, 0);
209 assert_eq!(DateHelper::time_ago(&future), "Dans le futur");
210 }
211}