1use chrono::{DateTime, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone};
2use crate::errors::JourneyError;
3
4pub struct DateTimeHandler {
5 pub locale: String,
6}
7
8impl DateTimeHandler {
9 pub fn new(locale: String) -> Self {
10 Self { locale }
11 }
12
13 pub fn parse_date(&self, date_str: &str) -> Result<NaiveDate, JourneyError> {
14 self.parse_date_with_format_override(date_str, None)
15 }
16
17 pub fn parse_date_with_format_override(&self, date_str: &str, format_override: Option<&str>) -> Result<NaiveDate, JourneyError> {
18 if let Some(override_format) = format_override {
20 let format_str = match override_format {
22 "YYYY-MM-DD" => "%Y-%m-%d",
23 "MM/DD/YYYY" => "%m/%d/%Y",
24 "DD.MM.YYYY" => "%d.%m.%Y",
25 "DD/MM/YYYY" => "%d/%m/%Y",
26 "MM-DD-YYYY" => "%m-%d-%Y",
27 "DD-MM-YYYY" => "%d-%m-%Y",
28 _ => override_format, };
30
31 if let Ok(date) = NaiveDate::parse_from_str(date_str, format_str) {
32 return Ok(date);
33 }
34
35 return Err(JourneyError::InvalidDateFormat(format!(
36 "Could not parse date: {} with format override: {}",
37 date_str, override_format
38 )));
39 }
40
41 let formats: Vec<&str> = if self.locale.starts_with("en") {
43 vec![
45 "%Y-%m-%d", "%m/%d/%Y", "%m-%d-%Y", "%B %d, %Y", "%b %d, %Y", ]
51 } else if self.locale.starts_with("no") || self.locale.starts_with("nb") || self.locale.starts_with("nn") {
52 vec![
54 "%Y-%m-%d", "%d.%m.%Y", "%d/%m/%Y", "%d-%m-%Y", "%d. %B %Y", "%d. %b %Y", ]
61 } else {
62 vec![
64 "%Y-%m-%d", "%m/%d/%Y", "%d/%m/%Y", ]
68 };
69
70 for format in &formats {
71 if let Ok(date) = NaiveDate::parse_from_str(date_str, format) {
72 return Ok(date);
73 }
74 }
75
76 Err(JourneyError::InvalidDateFormat(format!(
77 "Could not parse date: {} for locale: {}",
78 date_str, self.locale
79 )))
80 }
81
82 pub fn parse_time(&self, time_str: &str) -> Result<NaiveTime, JourneyError> {
83 self.parse_time_with_format_override(time_str, None)
84 }
85
86 pub fn parse_time_with_format_override(&self, time_str: &str, format_override: Option<&str>) -> Result<NaiveTime, JourneyError> {
87 if let Some(override_format) = format_override {
89 let formats = match override_format {
90 "12h" => vec![
91 "%I:%M %p", "%I:%M:%S %p", "%I:%M%p", "%I:%M:%S%p", ],
96 "24h" => vec![
97 "%H:%M", "%H:%M:%S", ],
100 _ => return Err(JourneyError::InvalidTimeFormat(format!(
101 "Invalid time format override: {}. Use '12h' or '24h'", override_format
102 )))
103 };
104
105 for format in &formats {
106 if let Ok(time) = NaiveTime::parse_from_str(time_str, format) {
107 return Ok(time);
108 }
109 }
110
111 return Err(JourneyError::InvalidTimeFormat(format!(
112 "Could not parse time: {} with format override: {}",
113 time_str, override_format
114 )));
115 }
116
117 let formats: Vec<&str> = if self.locale.starts_with("en") {
119 vec![
121 "%H:%M", "%H:%M:%S", "%I:%M %p", "%I:%M:%S %p", "%I:%M%p", "%I:%M:%S%p", ]
128 } else if self.locale.starts_with("no") || self.locale.starts_with("nb") || self.locale.starts_with("nn") {
129 vec![
131 "%H:%M", "%H:%M:%S", "%I:%M %p", "%I:%M:%S %p", "%I:%M%p", "%I:%M:%S%p", ]
138 } else {
139 vec![
141 "%H:%M", "%H:%M:%S", "%I:%M %p", "%I:%M:%S %p", "%I:%M%p", "%I:%M:%S%p", ]
148 };
149
150 for format in &formats {
151 if let Ok(time) = NaiveTime::parse_from_str(time_str, format) {
152 return Ok(time);
153 }
154 }
155
156 Err(JourneyError::InvalidTimeFormat(format!(
157 "Could not parse time: {} for locale: {}",
158 time_str, self.locale
159 )))
160 }
161
162 pub fn parse_relative_date(&self, days_offset: i64) -> NaiveDate {
163 let now = Local::now().date_naive();
164 now - chrono::Duration::days(days_offset)
165 }
166
167 pub fn format_date(&self, date: NaiveDate) -> String {
168 date.format("%Y-%m-%d").to_string()
169 }
170
171 pub fn format_datetime(&self, datetime: DateTime<Local>) -> String {
172 datetime.format("%H:%M:%S").to_string()
173 }
174
175 pub fn format_time(&self, time: chrono::NaiveTime) -> String {
176 time.format("%H:%M:%S").to_string()
177 }
178
179 pub fn get_current_datetime(&self) -> DateTime<Local> {
180 Local::now()
181 }
182
183 pub fn combine_date_time(&self, date: NaiveDate, time: NaiveTime) -> DateTime<Local> {
184 let naive_dt = NaiveDateTime::new(date, time);
185 Local.from_local_datetime(&naive_dt).single().unwrap_or_else(|| Local::now())
186 }
187}
188