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}