warlocks_cauldron/providers/date.rs
1use super::dependencies::*;
2pub use chrono::{prelude::*, Duration};
3use chrono_tz::Tz;
4
5
6pub enum TimestampType {
7 POSIX(i64),
8 RFC3339(String),
9}
10
11/// Struct for generating data related to the date and time
12pub struct Datetime<'a>(pub &'a Locale);
13
14impl<'a> Datetime<'a> {
15 /// Private. Return global parsed data from own locale
16 fn data(&self) -> &ParsedData { self.0.get_data() }
17
18 /// Private
19 fn get_days_from_month(year: i32, month: u32) -> u32 {
20 NaiveDate::from_ymd_opt(
21 match month {
22 12 => year + 1,
23 _ => year,
24 },
25 match month {
26 12 => 1,
27 _ => month + 1,
28 },
29 1,
30 ).unwrap()
31 .signed_duration_since(NaiveDate::from_ymd_opt(year, month, 1).unwrap())
32 .num_days() as u32
33 }
34
35 /// Bulk create datetime structs
36 ///
37 /// This method creates list of datetime objects from
38 /// ``date_start`` to ``date_end``
39 ///
40 /// return example: vec!\[DateTime, \]
41 ///
42 /// # Arguments
43 /// * `date_start` - Begin of the range
44 /// * `date_end` - End of the range
45 /// * `delta` - Range delimetr
46 pub fn bulk_create_datetimes<Tz: TimeZone>(date_start: DateTime<Tz>, date_end: DateTime<Tz>, delta: Duration) -> Vec<DateTime<Tz>>{
47 if date_start > date_end {
48 panic!("date_end must be greater than date_start!")
49 }
50
51 if delta.is_zero() {
52 panic!("delta must not be zero!")
53 }
54
55 let mut v = vec![];
56 let mut last_date = date_start;
57
58 while last_date < date_end {
59 last_date = last_date.checked_add_signed(delta).expect("Cant calculate delta!");
60 if last_date < date_end {
61 v.push(last_date.clone())
62 }
63 }
64
65 v
66 }
67
68 /// Get a random periodicity string.
69 ///
70 /// return example: Periodicity
71 pub fn periodicity(&self) -> &str {
72 get_random_element(self.data().datetime.periodicity.iter())
73 }
74
75 /// Get a random century
76 ///
77 /// return example: XIII
78 pub fn century() -> &'static str {
79 get_random_element(ROMAN_NUMS.iter())
80 }
81
82 /// Generate a random year
83 ///
84 /// return example: 2013
85 ///
86 /// # Arguments
87 /// * `minimum` - Minimum value
88 /// * `maximum` - Maximum value
89 pub fn year(minimum: i32, maximum: i32) -> i32 {
90 randint(minimum, maximum)
91 }
92
93 /// Get a random month
94 ///
95 /// return example: Month name or abbr
96 ///
97 /// # Arguments
98 /// * `abbr` - Abbreviated month name
99 pub fn month(&self, abbr: bool) -> &str {
100 get_random_element(match abbr {
101 true => self.data().datetime.month.abbr.iter(),
102 false => self.data().datetime.month.name.iter(),
103 })
104 }
105
106 /// Get a random day of week
107 ///
108 /// return example: Day name or abbr
109 ///
110 /// # Arguments
111 /// * `abbr` - Abbreviated month name
112 pub fn day_of_week(&self, abbr: bool) -> &str {
113 get_random_element(match abbr {
114 true => self.data().datetime.day.abbr.iter(),
115 false => self.data().datetime.day.name.iter(),
116 })
117 }
118
119 /// Get week number with year
120 ///
121 /// return example: 2013-W13
122 ///
123 /// # Arguments
124 /// * `start` - From start
125 /// * `end` - To end
126 pub fn week_data(&self, start: i32, end: i32) -> String {
127 format!("{}-W{}", Self::year(start, end), randint(1, 52))
128 }
129
130 /// Generate random naive date
131 ///
132 /// return example: NaiveDate
133 ///
134 /// # Arguments
135 /// * `start` - Minimum value of year
136 /// * `end` - Maximum value of year
137 pub fn date(start: i32, end: i32) -> NaiveDate {
138 let year = randint(start, end);
139 let month = randint(1, 12);
140 let day = randint(1, Self::get_days_from_month(year, month));
141 NaiveDate::from_ymd_opt(year, month, day).unwrap()
142 }
143
144 /// Generate random date as string
145 ///
146 /// return example: Formatted date
147 ///
148 /// # Arguments
149 /// * `fmt` - The format of date, if None then use standard accepted in the current locale
150 /// * `start` - Minimum value of year
151 /// * `end` - Maximum value of year
152 pub fn formatted_date(&self, fmt: Option<&str>, start: i32, end: i32) -> String {
153 let fmt = fmt.unwrap_or_else(|| &self.data().datetime.formats.date);
154 Self::date(start, end).format(fmt).to_string()
155 }
156
157 /// Generate a random naive time
158 ///
159 /// return example: NaiveTime
160 pub fn time() -> NaiveTime {
161 NaiveTime::from_hms_micro_opt(randint(0, 23), randint(0, 59), randint(0, 59), randint(0, 999999))
162 .unwrap()
163 }
164
165 /// Generate string formatted time
166 ///
167 /// return example: formatted time
168 ///
169 /// # Arguments
170 /// * `fmt` - The format of time, if None then use standard accepted in the current locale
171 pub fn formatted_time(&self, fmt: Option<&str>) -> String {
172 let fmt = fmt.unwrap_or_else(|| &self.data().datetime.formats.time);
173 Self::time().format(fmt).to_string()
174 }
175
176 /// Generate a random day of month, from 1 to 31
177 ///
178 /// return example: 13
179 pub fn day_of_month() -> i32 {
180 randint(1, 31)
181 }
182
183 /// Get a random timezone
184 ///
185 /// return example: Antarctica/Troll
186 ///
187 /// # Arguments
188 /// * `region` - Timezone region
189 pub fn timezone(region: Option<TimezoneRegion>) -> &'static str {
190 let region_name = validate_enum(region, None);
191 get_random_element(TIMEZONES.iter().filter(|tz| tz.starts_with(region_name)))
192 }
193
194 /// Get a random GMT offset value
195 ///
196 /// return example: UTC +13:00
197 pub fn gmt_offset() -> &'static str {
198 get_random_element(GMT_OFFSETS.iter())
199 }
200
201 /// Generate random datetime
202 ///
203 /// return example: DateTime<Utc>
204 ///
205 /// # Arguments
206 /// * `start` - Minimum value of year
207 /// * `end` - Maximum value of year
208 pub fn datetime(start: i32, end: i32) -> DateTime<Utc> {
209 DateTime::<Utc>::from_utc(
210 NaiveDateTime::new(Self::date(start, end), Self::time()), Utc,
211 )
212 }
213
214 /// Generate datetime string in human readable format
215 ///
216 /// return example: formatted datetime
217 ///
218 /// # Arguments
219 /// * `fmt` - The format of datetime, if None then use standard accepted in the current locale
220 /// * `start` - Minimum value of year
221 /// * `end` - Maximum value of year
222 pub fn formatted_datetime(&self, fmt: Option<&str>, start: i32, end: i32) -> String {
223 let full_format = {
224 let data = self.data();
225 format!("{} {}", &data.datetime.formats.date, &data.datetime.formats.time)
226 };
227
228 let fmt = fmt.unwrap_or_else(|| &full_format);
229 Self::datetime(start, end).format(fmt).to_string()
230 }
231
232 /// Generate random timestamp
233 ///
234 /// return example: TimestampType::POSIX(133333333333)
235 ///
236 /// # Arguments
237 /// * `posix` - Use POSIX time
238 /// * `start` - Minimum value of year
239 /// * `end` - Maximum value of year
240 pub fn timestamp(posix: bool, start: i32, end: i32) -> TimestampType {
241 match posix {
242 true => TimestampType::POSIX(Self::datetime(start, end).timestamp()),
243 false => TimestampType::RFC3339(Self::datetime(start, end).to_rfc3339()),
244 }
245 }
246}