data_faking/data/defaults/
date.rs1use std::ops::Sub;
2
3use crate::utils::seeder;
4use chrono::{NaiveDate, Days, Utc, Datelike};
5
6pub fn random_date(start: String, end: String, exclude: Option<Vec<String>>) -> String {
7 if start == end {
8 println!("Timestamps cannot be the same.");
9 return String::from("");
10 }
11
12 let start_validate = validate_timestamp(start);
13 if start_validate.is_none() {
14 return String::from("");
15 };
16 let start_ts = start_validate.unwrap();
17 let start_ymd = NaiveDate::from_ymd_opt(start_ts.0, start_ts.1, start_ts.2).unwrap();
18
19 let end_validate = validate_timestamp(end);
20 if end_validate.is_none() {
21 return String::from("");
22 };
23 let end_ts = end_validate.unwrap();
24 let end_ymd = NaiveDate::from_ymd_opt(end_ts.0, end_ts.1, end_ts.2).unwrap();
25
26 let ast = end_ymd.sub(start_ymd);
27 let rand_days = seeder::gen_range(0..ast.num_days());
28
29 if exclude.is_some() {
30 let exclude_list: Vec<String> = exclude.unwrap();
31 let mut rand_ymd: Option<String> = None;
32 while rand_ymd.is_none() {
33 let ymd = start_ymd.checked_add_days(Days::new(seeder::gen_range(0..ast.num_days()) as u64));
34 if !exclude_list.contains(&ymd.unwrap().to_string()){
35 rand_ymd = Some(ymd.unwrap().to_string());
36 }
37 }
38 return rand_ymd.unwrap();
39 }
40
41 let rand_ymd = start_ymd.checked_add_days(Days::new(rand_days as u64));
42 if rand_ymd.is_some() {
43 return rand_ymd.unwrap().to_string();
44 }
45 else {
46 return String::from("");
47 }
48}
49
50pub fn random_date_dow(start: String, end: String, day_of_week: String) -> String {
51 if day_of_week != String::from("Mon") &&
52 day_of_week != String::from("Tue") &&
53 day_of_week != String::from("Wed") &&
54 day_of_week != String::from("Thu") &&
55 day_of_week != String::from("Fri") &&
56 day_of_week != String::from("Sat") &&
57 day_of_week != String::from("Sun") {
58 println!("Invalid day of week provided: {}", day_of_week);
59 return String::from("");
60 }
61
62 if start == end {
63 println!("Timestamps cannot be the same.");
64 return String::from("");
65 }
66
67 let start_validate = validate_timestamp(start);
68 if start_validate.is_none() {
69 return String::from("");
70 };
71 let start_ts = start_validate.unwrap();
72 let start_ymd = NaiveDate::from_ymd_opt(start_ts.0, start_ts.1, start_ts.2).unwrap();
73
74 let mut start_dow = start_ymd;
75
76 while start_dow.weekday().to_string() != day_of_week {
77 start_dow = start_dow.checked_add_days(Days::new(1)).unwrap();
78 }
79
80 let end_validate = validate_timestamp(end);
81 if end_validate.is_none() {
82 return String::from("");
83 };
84 let end_ts = end_validate.unwrap();
85 let end_ymd = NaiveDate::from_ymd_opt(end_ts.0, end_ts.1, end_ts.2).unwrap();
86
87 if start_dow > end_ymd {
88 println!("No date available on {} between {} and {}", day_of_week, start_ymd.to_string(), end_ymd.to_string());
89 return String::from("");
90 }
91
92 let available_weeks = (end_ymd - start_dow).num_days() / 7;
93
94 if available_weeks == 0 {
95 return start_dow.to_string();
96 }
97
98 let random_week = seeder::gen_range(0..available_weeks);
99
100 let rand_days = random_week * 7;
101
102 let rand_ymd = start_dow.checked_add_days(Days::new(rand_days as u64));
103
104 if rand_ymd.is_some() {
105 return rand_ymd.unwrap().to_string();
106 }
107 else {
108 return String::from("");
109 }
110}
111
112pub fn validate_timestamp(timestamp: String) -> Option<(i32, u32, u32)> {
113 let mut date_parts = timestamp.split("-");
114 let first = date_parts.next();
115 if first.is_none() {
116 println!("Incorrect Format for timestamp: {}", timestamp);
117 return None;
118 }
119 let year_str = first.unwrap();
120 let year_validate = year_str.parse::<i32>();
121 if year_validate.is_err() {
122 println!("Invalid value for year: {}", year_str);
123 return None;
124 }
125 let year = year_validate.unwrap();
126
127 let second = date_parts.next();
128 if second.is_none() {
129 println!("Incorrect Format for timestamp: {}", timestamp);
130 return None;
131 }
132 let month_str = second.unwrap();
133 let month_validate = month_str.parse::<u32>();
134 if month_validate.is_err() {
135 println!("Invalid value for month: {}", month_str);
136 return None;
137 }
138 let month = month_validate.unwrap();
139 if month > 12 {
140 println!("Invalid value for month: {}", month_str);
141 }
142
143 let third = date_parts.next();
144 if third.is_none() {
145 println!("Incorrect Format for timestamp: {}", timestamp);
146 return None;
147 }
148 let day_str = third.unwrap();
149 let day_validate = day_str.parse::<u32>();
150 if day_validate.is_err() {
151 println!("Invalid value for day: {}", day_str);
152 return None;
153 }
154 let day = day_validate.unwrap();
155
156 let mut max_day = match month{
158 1 => 31,
159 2 => 28,
160 3 => 31,
161 4 => 30,
162 5 => 31,
163 6 => 30,
164 7 => 31,
165 8 => 31,
166 9 => 30,
167 10 => 31,
168 11 => 30,
169 12 => 31,
170 _ => 31 };
172 if month == 2 {
173 let leap_year = max_day % 4;
174 if leap_year == 0 {
175 max_day = 29;
176 }
177 }
178 if day > max_day {
179 println!("Invalid value for day {}", day_str);
180 return None;
181 }
182
183 let extra_value = date_parts.next();
184 if extra_value.is_some() {
185 println!("Trailing characters found for timestamp: {}", timestamp);
186 }
187
188 Some((year, month, day))
189}
190
191pub fn random_date_future(num_days: i32) -> String {
192 let rand_days = seeder::gen_range(0..num_days);
193
194 let naive_date_time: NaiveDate = Utc::now().checked_add_days(Days::new(rand_days.try_into().unwrap())).unwrap().naive_utc().into();
195 naive_date_time.to_string()
196}
197
198pub fn random_date_past(num_days: i32) -> String {
199 let rand_days = seeder::gen_range(0..num_days);
200
201 let naive_date_time: NaiveDate = Utc::now().checked_sub_days(Days::new(rand_days.try_into().unwrap())).unwrap().naive_utc().into();
202 naive_date_time.to_string()
203}
204
205