dataforge/generators/
datetime.rs1use chrono::{DateTime, Duration, NaiveDate, Utc, Datelike};
4use rand::Rng;
5use rand::seq::SliceRandom;
6
7pub fn datetime_range(start: DateTime<Utc>, end: DateTime<Utc>) -> DateTime<Utc> {
9 let mut rng = rand::thread_rng();
10 let secs = end.timestamp() - start.timestamp();
11 let random_secs = rng.gen_range(0..secs);
12 start + Duration::seconds(random_secs)
13}
14
15pub fn datetime_past_days(days: i64) -> DateTime<Utc> {
17 let now = Utc::now();
18 let past = now - Duration::days(days);
19 datetime_range(past, now)
20}
21
22pub fn datetime_future_days(days: i64) -> DateTime<Utc> {
24 let now = Utc::now();
25 let future = now + Duration::days(days);
26 datetime_range(now, future)
27}
28
29pub fn datetime_this_year() -> DateTime<Utc> {
31 let now = Utc::now();
32 let year = now.year();
33 let start = NaiveDate::from_ymd_opt(year, 1, 1)
34 .unwrap()
35 .and_hms_opt(0, 0, 0)
36 .unwrap()
37 .and_utc();
38 let end = NaiveDate::from_ymd_opt(year, 12, 31)
39 .unwrap()
40 .and_hms_opt(23, 59, 59)
41 .unwrap()
42 .and_utc();
43 datetime_range(start, end)
44}
45
46pub fn birthday() -> String {
48 let now = Utc::now();
49 let min_age = 18;
50 let max_age = 80;
51
52 let mut rng = rand::thread_rng();
53 let age = rng.gen_range(min_age..=max_age);
54
55 let birth_year = now.year() - age;
56 let birth_month = rng.gen_range(1..=12);
57 let birth_day = rng.gen_range(1..=28); NaiveDate::from_ymd_opt(birth_year, birth_month, birth_day)
60 .unwrap()
61 .format("%Y-%m-%d")
62 .to_string()
63}
64
65pub fn work_time() -> String {
67 let mut rng = rand::thread_rng();
68 let hour = rng.gen_range(9..18);
69 let minute = rng.gen_range(0..60);
70 format!("{:02}:{:02}", hour, minute)
71}
72
73pub fn timestamp() -> i64 {
75 Utc::now().timestamp()
76}
77
78pub fn rfc2822() -> String {
80 Utc::now().to_rfc2822()
81}
82
83pub fn date_between(start: &str, end: &str) -> String {
85 let mut rng = rand::thread_rng();
86 let start_date = NaiveDate::parse_from_str(start, "%Y-%m-%d").unwrap();
87 let end_date = NaiveDate::parse_from_str(end, "%Y-%m-%d").unwrap();
88 let days_diff = end_date.signed_duration_since(start_date).num_days();
89 let random_days = rng.gen_range(0..=days_diff);
90 let result_date = start_date + chrono::Duration::days(random_days);
91 result_date.format("%Y-%m-%d").to_string()
92}
93
94pub fn time() -> String {
96 let mut rng = rand::thread_rng();
97 let hour = rng.gen_range(0..24);
98 let minute = rng.gen_range(0..60);
99 let second = rng.gen_range(0..60);
100 format!("{:02}:{:02}:{:02}", hour, minute, second)
101}
102
103pub fn datetime() -> String {
105 let date = birthday();
106 let time_str = time();
107 format!("{} {}", date, time_str)
108}
109
110pub fn weekday() -> String {
112 let mut rng = rand::thread_rng();
113 let weekdays = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
114 weekdays.choose(&mut rng).unwrap().to_string()
115}
116
117pub fn month() -> String {
119 let mut rng = rand::thread_rng();
120 let months = ["January", "February", "March", "April", "May", "June",
121 "July", "August", "September", "October", "November", "December"];
122 months.choose(&mut rng).unwrap().to_string()
123}
124
125pub fn iso8601() -> String {
127 Utc::now().to_rfc3339()
128}
129
130pub fn random_date_between(start: &str, end: &str) -> String {
132 date_between(start, end)
133}
134
135pub fn date_iso() -> String {
137 Utc::now().format("%Y-%m-%d").to_string()
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143
144 #[test]
145 fn test_datetime_past_days() {
146 let dt = datetime_past_days(30);
147 let now = Utc::now();
148 assert!(dt < now);
149 assert!(dt > now - Duration::days(30));
150 }
151
152 #[test]
153 fn test_birthday() {
154 let birth_str = birthday();
155 let birth_date = NaiveDate::parse_from_str(&birth_str, "%Y-%m-%d").unwrap();
156 let now = Utc::now();
157 let age = now.year() - birth_date.year();
158 assert!(age >= 18 && age <= 80);
159 }
160
161 #[test]
162 fn test_work_time() {
163 let time = work_time();
164 assert!(time.contains(':'));
165 let parts: Vec<&str> = time.split(':').collect();
166 assert_eq!(parts.len(), 2);
167
168 let hour: u32 = parts[0].parse().unwrap();
169 assert!(hour >= 9 && hour < 18);
170 }
171}