1use super::i_culture_data_provider::find_culture_data;
12use super::{CultureInfo, DayOfWeek, GregorianCalendar};
13use std::borrow::Cow;
14use std::ops::Deref;
15use std::rc::Rc;
16
17#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
20#[repr(u8)]
21pub enum CalendarWeekRule {
22 #[default]
24 FirstDay = 0,
25 FirstFullWeek = 1,
27 FirstFourDayWeek = 2,
29}
30
31const DAY_NAMES: [&str; 7] = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
32const ABBREVIATED_DAY_NAMES: [&str; 7] = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
33const SHORTEST_DAY_NAMES: [&str; 7] = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
34const MONTH_NAMES: [&str; 12] = [
35 "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November",
36 "December",
37];
38const ABBREVIATED_MONTH_NAMES: [&str; 12] =
39 ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
40
41crate::ferro_thread_local! {
42 static INVARIANT: Rc<DateTimeFormatInfo> = Rc::new(DateTimeFormatInfo::new());
43}
44
45#[derive(Clone, Debug, PartialEq, Eq)]
51pub struct DateTimeFormatInfo {
52 short_date_pattern: String,
53 long_date_pattern: String,
54 short_time_pattern: String,
55 long_time_pattern: String,
56 full_date_time_pattern: Option<String>,
57 month_day_pattern: String,
58 year_month_pattern: String,
59 am_designator: String,
60 pm_designator: String,
61 date_separator: String,
62 time_separator: String,
63 era_name: String,
64 first_day_of_week: DayOfWeek,
65 calendar_week_rule: CalendarWeekRule,
66 day_names: [String; 7],
67 abbreviated_day_names: [String; 7],
68 shortest_day_names: [String; 7],
69 month_names: [String; 13],
70 abbreviated_month_names: [String; 13],
71}
72
73fn day_strings(names: &[&str; 7]) -> [String; 7] {
74 std::array::from_fn(|index| names[index].to_owned())
75}
76
77fn month_strings(names: &[&str; 12]) -> [String; 13] {
78 std::array::from_fn(|index| names.get(index).map_or_else(String::new, |name| (*name).to_owned()))
79}
80
81impl DateTimeFormatInfo {
82 pub fn new() -> DateTimeFormatInfo {
85 DateTimeFormatInfo {
86 short_date_pattern: "MM/dd/yyyy".to_owned(),
87 long_date_pattern: "dddd, dd MMMM yyyy".to_owned(),
88 short_time_pattern: "HH:mm".to_owned(),
89 long_time_pattern: "HH:mm:ss".to_owned(),
90 full_date_time_pattern: None,
91 month_day_pattern: "MMMM dd".to_owned(),
92 year_month_pattern: "yyyy MMMM".to_owned(),
93 am_designator: "AM".to_owned(),
94 pm_designator: "PM".to_owned(),
95 date_separator: "/".to_owned(),
96 time_separator: ":".to_owned(),
97 era_name: "A.D.".to_owned(),
98 first_day_of_week: DayOfWeek::Sunday,
99 calendar_week_rule: CalendarWeekRule::FirstDay,
100 day_names: day_strings(&DAY_NAMES),
101 abbreviated_day_names: day_strings(&ABBREVIATED_DAY_NAMES),
102 shortest_day_names: day_strings(&SHORTEST_DAY_NAMES),
103 month_names: month_strings(&MONTH_NAMES),
104 abbreviated_month_names: month_strings(&ABBREVIATED_MONTH_NAMES),
105 }
106 }
107
108 pub(crate) fn for_culture(culture: &CultureInfo) -> Rc<DateTimeFormatInfo> {
112 find_culture_data(culture, |provider, name| provider.get_date_time_format(name)).unwrap_or_else(Self::invariant_info)
113 }
114
115 pub fn invariant_info() -> Rc<DateTimeFormatInfo> {
117 INVARIANT.with(Rc::clone)
118 }
119
120 pub fn current_info() -> Rc<DateTimeFormatInfo> {
122 CultureInfo::current_culture().date_time_format()
123 }
124
125 pub fn calendar(&self) -> GregorianCalendar {
127 GregorianCalendar
128 }
129
130 pub fn short_date_pattern(&self) -> &str {
132 &self.short_date_pattern
133 }
134
135 pub fn set_short_date_pattern(&mut self, value: impl Into<String>) {
137 self.short_date_pattern = value.into();
138 }
139
140 pub fn long_date_pattern(&self) -> &str {
142 &self.long_date_pattern
143 }
144
145 pub fn set_long_date_pattern(&mut self, value: impl Into<String>) {
147 self.long_date_pattern = value.into();
148 }
149
150 pub fn short_time_pattern(&self) -> &str {
152 &self.short_time_pattern
153 }
154
155 pub fn set_short_time_pattern(&mut self, value: impl Into<String>) {
157 self.short_time_pattern = value.into();
158 }
159
160 pub fn long_time_pattern(&self) -> &str {
162 &self.long_time_pattern
163 }
164
165 pub fn set_long_time_pattern(&mut self, value: impl Into<String>) {
167 self.long_time_pattern = value.into();
168 }
169
170 pub fn full_date_time_pattern(&self) -> Cow<'_, str> {
173 match &self.full_date_time_pattern {
174 Some(pattern) => Cow::Borrowed(pattern),
175 None => Cow::Owned(format!("{} {}", self.long_date_pattern, self.long_time_pattern)),
176 }
177 }
178
179 pub fn set_full_date_time_pattern(&mut self, value: impl Into<String>) {
181 self.full_date_time_pattern = Some(value.into());
182 }
183
184 pub fn month_day_pattern(&self) -> &str {
186 &self.month_day_pattern
187 }
188
189 pub fn set_month_day_pattern(&mut self, value: impl Into<String>) {
191 self.month_day_pattern = value.into();
192 }
193
194 pub fn year_month_pattern(&self) -> &str {
196 &self.year_month_pattern
197 }
198
199 pub fn set_year_month_pattern(&mut self, value: impl Into<String>) {
201 self.year_month_pattern = value.into();
202 }
203
204 pub fn rfc1123_pattern(&self) -> &'static str {
206 "ddd, dd MMM yyyy HH':'mm':'ss 'GMT'"
207 }
208
209 pub fn sortable_date_time_pattern(&self) -> &'static str {
211 "yyyy'-'MM'-'dd'T'HH':'mm':'ss"
212 }
213
214 pub fn universal_sortable_date_time_pattern(&self) -> &'static str {
216 "yyyy'-'MM'-'dd HH':'mm':'ss'Z'"
217 }
218
219 pub fn am_designator(&self) -> &str {
221 &self.am_designator
222 }
223
224 pub fn set_am_designator(&mut self, value: impl Into<String>) {
226 self.am_designator = value.into();
227 }
228
229 pub fn pm_designator(&self) -> &str {
231 &self.pm_designator
232 }
233
234 pub fn set_pm_designator(&mut self, value: impl Into<String>) {
236 self.pm_designator = value.into();
237 }
238
239 pub fn date_separator(&self) -> &str {
241 &self.date_separator
242 }
243
244 pub fn set_date_separator(&mut self, value: impl Into<String>) {
246 self.date_separator = value.into();
247 }
248
249 pub fn time_separator(&self) -> &str {
251 &self.time_separator
252 }
253
254 pub fn set_time_separator(&mut self, value: impl Into<String>) {
256 self.time_separator = value.into();
257 }
258
259 pub fn first_day_of_week(&self) -> DayOfWeek {
261 self.first_day_of_week
262 }
263
264 pub fn set_first_day_of_week(&mut self, value: DayOfWeek) {
266 self.first_day_of_week = value;
267 }
268
269 pub fn calendar_week_rule(&self) -> CalendarWeekRule {
271 self.calendar_week_rule
272 }
273
274 pub fn set_calendar_week_rule(&mut self, value: CalendarWeekRule) {
276 self.calendar_week_rule = value;
277 }
278
279 pub fn day_names(&self) -> &[String; 7] {
281 &self.day_names
282 }
283
284 pub fn set_day_names(&mut self, value: [String; 7]) {
286 self.day_names = value;
287 }
288
289 pub fn abbreviated_day_names(&self) -> &[String; 7] {
291 &self.abbreviated_day_names
292 }
293
294 pub fn set_abbreviated_day_names(&mut self, value: [String; 7]) {
296 self.abbreviated_day_names = value;
297 }
298
299 pub fn shortest_day_names(&self) -> &[String; 7] {
301 &self.shortest_day_names
302 }
303
304 pub fn set_shortest_day_names(&mut self, value: [String; 7]) {
306 self.shortest_day_names = value;
307 }
308
309 pub fn month_names(&self) -> &[String; 13] {
311 &self.month_names
312 }
313
314 pub fn set_month_names(&mut self, value: [String; 13]) {
316 self.month_names = value;
317 }
318
319 pub fn abbreviated_month_names(&self) -> &[String; 13] {
321 &self.abbreviated_month_names
322 }
323
324 pub fn set_abbreviated_month_names(&mut self, value: [String; 13]) {
326 self.abbreviated_month_names = value;
327 }
328
329 pub fn get_day_name(&self, day_of_week: DayOfWeek) -> &str {
331 &self.day_names[day_of_week as usize]
332 }
333
334 pub fn get_abbreviated_day_name(&self, day_of_week: DayOfWeek) -> &str {
336 &self.abbreviated_day_names[day_of_week as usize]
337 }
338
339 pub fn get_shortest_day_name(&self, day_of_week: DayOfWeek) -> &str {
341 &self.shortest_day_names[day_of_week as usize]
342 }
343
344 #[track_caller]
346 pub fn get_month_name(&self, month: i32) -> &str {
347 assert!((1..=13).contains(&month), "Valid values are between 1 and 13, inclusive. (Parameter 'month')");
348 &self.month_names[(month - 1) as usize]
349 }
350
351 #[track_caller]
353 pub fn get_abbreviated_month_name(&self, month: i32) -> &str {
354 assert!((1..=13).contains(&month), "Valid values are between 1 and 13, inclusive. (Parameter 'month')");
355 &self.abbreviated_month_names[(month - 1) as usize]
356 }
357
358 pub fn get_era_name(&self, _era: i32) -> &str {
360 &self.era_name
361 }
362
363 pub fn set_era_name(&mut self, value: impl Into<String>) {
365 self.era_name = value.into();
366 }
367}
368
369impl Default for DateTimeFormatInfo {
370 fn default() -> Self {
371 Self::new()
372 }
373}
374
375pub enum DateTimeFormatInfoRef<'a> {
378 Borrowed(&'a DateTimeFormatInfo),
380 Shared(Rc<DateTimeFormatInfo>),
382}
383
384impl Deref for DateTimeFormatInfoRef<'_> {
385 type Target = DateTimeFormatInfo;
386 fn deref(&self) -> &DateTimeFormatInfo {
387 match self {
388 DateTimeFormatInfoRef::Borrowed(info) => info,
389 DateTimeFormatInfoRef::Shared(info) => info,
390 }
391 }
392}
393
394pub trait DateTimeFormatProvider {
398 fn get_date_time_format(&self) -> DateTimeFormatInfoRef<'_>;
400}
401
402impl DateTimeFormatProvider for DateTimeFormatInfo {
403 fn get_date_time_format(&self) -> DateTimeFormatInfoRef<'_> {
404 DateTimeFormatInfoRef::Borrowed(self)
405 }
406}
407
408impl DateTimeFormatProvider for Rc<DateTimeFormatInfo> {
409 fn get_date_time_format(&self) -> DateTimeFormatInfoRef<'_> {
410 DateTimeFormatInfoRef::Borrowed(self)
411 }
412}
413
414impl DateTimeFormatProvider for CultureInfo {
415 fn get_date_time_format(&self) -> DateTimeFormatInfoRef<'_> {
416 DateTimeFormatInfoRef::Shared(self.date_time_format())
417 }
418}
419
420impl<T: DateTimeFormatProvider + ?Sized> DateTimeFormatProvider for &T {
421 fn get_date_time_format(&self) -> DateTimeFormatInfoRef<'_> {
422 (**self).get_date_time_format()
423 }
424}