deep_time/alloc_parse/types.rs
1use crate::Dt;
2use alloc::string::String;
3use alloc::vec::Vec;
4
5/// Used by [`ParseCfg`] in
6/// [`Dt::from_str_parse`](../struct.Dt.html#method.from_str_parse).
7///
8/// Controls how ambiguous numeric dates (e.g. `01/02/03`).
9///
10/// The default `Smart` variant applies a practical heuristic that prefers
11/// year-first for compact formats and uses numeric plausibility checks
12/// for other cases. The other variants force a specific ordering.
13#[derive(Clone, Copy, Debug, PartialEq, Default)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15#[cfg_attr(feature = "tsify", derive(tsify::Tsify))]
16pub enum Order {
17 /// Heuristic for **mixed data**. Uses the following rules, in this order:
18 ///
19 /// 1. **Pure-numeric compact formats** (≥ 6 digits with no separators,
20 /// e.g. `240314153045`, `20240315`, `YYMMDDHHMMSS`):
21 /// treated as **Year-first** (`%Y%m%d` / `%y%m%d`).
22 /// These are overwhelmingly used in logs, filenames, databases, APIs,
23 /// configs, and JSON for sortability.
24 ///
25 /// 2. **Delimited formats that start with a plausible 4-digit year**
26 /// (1900–2100): treated as **Year-first**.
27 ///
28 /// 3. **Numeric plausibility check** (strongest universal signal):
29 /// - First number is 13–31 → **Day-first** (international/European style).
30 /// - First number is 1–12 **and** second number is 13–31 → **Month-first**
31 /// (US style).
32 ///
33 /// 4. **Strong ISO 8601 / timestamp markers** (`T` connector, `Z`, numeric
34 /// offsets, or IANA timezone names) → **Year-first**.
35 ///
36 /// 5. **Fallback**:
37 /// - With the `locale` feature enabled: respects the system locale
38 /// preference (Day-first in most of the world).
39 /// - Without the `locale` feature: **Day-first** (global majority).
40 ///
41 /// The `/` separator is deliberately ignored in the plausibility step
42 /// because it is culturally ambiguous.
43 ///
44 /// Once the preferred ordering is determined, the parser tries the
45 /// corresponding ambiguous candidate formats (Year-first → Day-first →
46 /// Month-first, or the reverse, depending on the detected order) and falls
47 /// back gracefully.
48 #[default]
49 Smart,
50 /// Force **Year-first** only (YYYY/MM/DD or YY/MM/DD)
51 Year,
52 /// Force **Day-first** only (DD/MM/YYYY)
53 Day,
54 /// Force **Month-first** only (MM/DD/YYYY)
55 Month,
56}
57
58#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
59#[cfg_attr(feature = "tsify", derive(tsify::Tsify))]
60#[derive(Clone, Copy, Debug, Default, PartialEq)]
61/// Only relevant for purely numeric dates.
62pub enum Mode {
63 /// **Default mode** — Smart heuristic:
64 /// - 5/7-digit pure-numeric inside `LEGACY_ORDINAL_YEAR_RANGE` → treated as business ordinal (YYYYDDD / YYDDD)
65 /// - Outside that range or invalid ordinal → treated as MJD or JD
66 #[default]
67 Auto,
68 /// When combined with a provided Vec of formats in parse no other formats are tried.
69 Explicit,
70 /// It's some sort of unix timestamp
71 UnixTimestamp,
72 /// Business/legacy-only mode:
73 /// Only accepts ordinal dates (YYYYDDD / YYDDD). No astronomy (JD/MJD) support.
74 /// Strict and predictable for ERP/mainframe data.
75 Legacy,
76 /// Scientific / astronomy-first mode:
77 /// Prioritizes MJD (5-digit) and JD (7-digit). Ordinals are only fallback.
78 /// Use this when parsing data from astronomy tools or large numeric epochs.
79 Scientific,
80}
81
82/// Configuration options for
83/// [`Dt::from_str_parse`](../struct.Dt.html#method.from_str_parse).
84///
85/// Controls language, ambiguous date order, numeric parsing mode,
86/// explicit `strptime` formats, relative-date support, and reference time.
87///
88/// These settings will not persist between parse calls and have to be used
89/// as an arg every time you want them.
90#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
91#[cfg_attr(feature = "tsify", derive(tsify::Tsify))]
92#[derive(Clone, Debug, PartialEq)]
93pub struct ParseCfg {
94 /// Explicit list of formats to try **in the exact order given**.
95 ///
96 /// If this is provided and the vec is non-empty and the mode is Explicit
97 /// then only these formats are tried and `mode` and `order` are ignored.
98 ///
99 /// If the mode is not Explicit then after trying the formats in parse the
100 /// rest of the parser will continue as normal, using `mode` and `order`.
101 ///
102 /// Example:
103 /// ```js
104 /// parse: ["%Y-%m-%d", "%d/%m/%Y", "%m/%d/%Y", "%d.%m.%Y"]
105 /// ```
106 #[cfg_attr(feature = "serde", serde(default))]
107 pub parse: Option<Vec<String>>,
108
109 /// Controls which preset format sets are used (astronomy/scientific formats,
110 /// legacy business rules, etc.).
111 #[cfg_attr(feature = "serde", serde(default))]
112 pub mode: Mode,
113
114 /// Controls ambiguous numeric dates.
115 #[cfg_attr(feature = "serde", serde(default))]
116 pub order: Order,
117
118 /// Sets language to use for a particular parse call.
119 #[cfg_attr(feature = "serde", serde(default))]
120 pub lang: Lang,
121
122 /// Whether to lowercase the input:
123 /// ONLY set to `false` if the &str is already lowercase.
124 #[cfg_attr(feature = "serde", serde(default = "default_true"))]
125 pub to_lower: bool,
126
127 /// Whether to parse relative dates as well as normal dates.
128 #[cfg_attr(feature = "serde", serde(default = "default_true"))]
129 pub relative: bool,
130
131 /// **Reference ("current") time** used for relative expressions:
132 /// - "tomorrow", "next Friday", "in 3 days", "next week"
133 /// - If `Some`, this `Dt` is used as "now" (overrides everything).
134 /// - If `None` + `std` feature enabled: automatically uses real system time.
135 /// - If `None` + no `std`: parsing relative dates will fail with a clear error.
136 #[cfg_attr(feature = "serde", serde(default))]
137 pub ref_time: Option<Dt>,
138}
139
140#[cfg(feature = "serde")]
141fn default_true() -> bool {
142 true
143}
144
145impl Default for ParseCfg {
146 fn default() -> Self {
147 Self {
148 parse: None,
149 mode: Mode::default(),
150 order: Order::default(),
151 lang: Lang::default(),
152 to_lower: true,
153 relative: true,
154 ref_time: None,
155 }
156 }
157}
158
159#[derive(Debug, Clone, Copy, PartialEq, Eq)]
160pub(crate) enum OrderFirst {
161 /// Year-Month-Day ordering (ISO 8601 style, `YYYY-MM-DD`, `20240315`, etc.)
162 Year,
163 /// Month-Day-Year ordering (US / some English locales, `MM/DD/YYYY`)
164 Month,
165 /// Day-Month-Year ordering (most of the world, `DD/MM/YYYY`, `DD.MM.YYYY`)
166 Day,
167}
168
169#[derive(Clone)]
170pub(crate) struct AmBuilder {
171 pub pieces: Vec<&'static str>,
172 pub seen_year: bool,
173 pub seen_month: bool,
174 pub seen_day: bool,
175}
176
177#[inline]
178pub(crate) fn append_to_all(builders: &mut Vec<AmBuilder>, s: &'static str) {
179 for b in builders {
180 b.pieces.push(s);
181 }
182}
183
184/// Language codes following ISO 639-1 standard (two-letter codes).
185/// Default is En (English)
186#[allow(dead_code)]
187#[non_exhaustive]
188#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
189#[cfg_attr(feature = "tsify", derive(tsify::Tsify))]
190#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
191pub enum Lang {
192 /// English (default)
193 #[default]
194 En,
195 /// Afar
196 Aa,
197 /// Abkhazian
198 Ab,
199 /// Avestan
200 Ae,
201 /// Afrikaans
202 Af,
203 /// Akan
204 Ak,
205 /// Amharic
206 Am,
207 /// Aragonese
208 An,
209 /// Arabic
210 Ar,
211 /// Assamese
212 As,
213 /// Avaric
214 Av,
215 /// Aymara
216 Ay,
217 /// Azerbaijani
218 Az,
219 /// Bashkir
220 Ba,
221 /// Belarusian
222 Be,
223 /// Bulgarian
224 Bg,
225 /// Bihari languages
226 Bh,
227 /// Bislama
228 Bi,
229 /// Bambara
230 Bm,
231 /// Bengali
232 Bn,
233 /// Tibetan
234 Bo,
235 /// Breton
236 Br,
237 /// Bosnian
238 Bs,
239 /// Catalan
240 Ca,
241 /// Chechen
242 Ce,
243 /// Chamorro
244 Ch,
245 /// Corsican
246 Co,
247 /// Cree
248 Cr,
249 /// Czech
250 Cs,
251 /// Church Slavic
252 Cu,
253 /// Chuvash
254 Cv,
255 /// Welsh
256 Cy,
257 /// Danish
258 Da,
259 /// German
260 De,
261 /// Divehi
262 Dv,
263 /// Dzongkha
264 Dz,
265 /// Ewe
266 Ee,
267 /// Greek
268 El,
269 /// Esperanto
270 Eo,
271 /// Spanish
272 Es,
273 /// Estonian
274 Et,
275 /// Basque
276 Eu,
277 /// Persian
278 Fa,
279 /// Fulah
280 Ff,
281 /// Finnish
282 Fi,
283 /// Fijian
284 Fj,
285 /// Faroese
286 Fo,
287 /// French
288 Fr,
289 /// Western Frisian
290 Fy,
291 /// Irish
292 Ga,
293 /// Scottish Gaelic
294 Gd,
295 /// Galician
296 Gl,
297 /// Guarani
298 Gn,
299 /// Gujarati
300 Gu,
301 /// Manx
302 Gv,
303 /// Hausa
304 Ha,
305 /// Hebrew
306 He,
307 /// Hindi
308 Hi,
309 /// Hiri Motu
310 Ho,
311 /// Croatian
312 Hr,
313 /// Haitian Creole
314 Ht,
315 /// Hungarian
316 Hu,
317 /// Armenian
318 Hy,
319 /// Herero
320 Hz,
321 /// Interlingua
322 Ia,
323 /// Indonesian
324 Id,
325 /// Interlingue
326 Ie,
327 /// Igbo
328 Ig,
329 /// Sichuan Yi
330 Ii,
331 /// Inupiaq
332 Ik,
333 /// Ido
334 Io,
335 /// Icelandic
336 Is,
337 /// Italian
338 It,
339 /// Inuktitut
340 Iu,
341 /// Japanese
342 Ja,
343 /// Javanese
344 Jv,
345 /// Georgian
346 Ka,
347 /// Kongo
348 Kg,
349 /// Kikuyu
350 Ki,
351 /// Kuanyama
352 Kj,
353 /// Kazakh
354 Kk,
355 /// Greenlandic
356 Kl,
357 /// Khmer
358 Km,
359 /// Kannada
360 Kn,
361 /// Korean
362 Ko,
363 /// Kanuri
364 Kr,
365 /// Kashmiri
366 Ks,
367 /// Kurdish
368 Ku,
369 /// Komi
370 Kv,
371 /// Cornish
372 Kw,
373 /// Kyrgyz
374 Ky,
375 /// Latin
376 La,
377 /// Luxembourgish
378 Lb,
379 /// Ganda
380 Lg,
381 /// Limburgish
382 Li,
383 /// Lingala
384 Ln,
385 /// Lao
386 Lo,
387 /// Lithuanian
388 Lt,
389 /// Luba-Katanga
390 Lu,
391 /// Latvian
392 Lv,
393 /// Malagasy
394 Mg,
395 /// Marshallese
396 Mh,
397 /// Maori
398 Mi,
399 /// Macedonian
400 Mk,
401 /// Malayalam
402 Ml,
403 /// Mongolian
404 Mn,
405 /// Marathi
406 Mr,
407 /// Malay
408 Ms,
409 /// Maltese
410 Mt,
411 /// Burmese
412 My,
413 /// Nauru
414 Na,
415 /// Norwegian Bokmål
416 Nb,
417 /// North Ndebele
418 Nd,
419 /// Nepali
420 Ne,
421 /// Ndonga
422 Ng,
423 /// Dutch
424 Nl,
425 /// Norwegian Nynorsk
426 Nn,
427 /// Norwegian
428 No,
429 /// South Ndebele
430 Nr,
431 /// Navajo
432 Nv,
433 /// Chichewa
434 Ny,
435 /// Occitan
436 Oc,
437 /// Ojibwa
438 Oj,
439 /// Oromo
440 Om,
441 /// Oriya
442 Or,
443 /// Ossetian
444 Os,
445 /// Punjabi
446 Pa,
447 /// Pali
448 Pi,
449 /// Polish
450 Pl,
451 /// Pashto
452 Ps,
453 /// Portuguese
454 Pt,
455 /// Quechua
456 Qu,
457 /// Romansh
458 Rm,
459 /// Rundi
460 Rn,
461 /// Romanian
462 Ro,
463 /// Russian
464 Ru,
465 /// Kinyarwanda
466 Rw,
467 /// Sanskrit
468 Sa,
469 /// Sardinian
470 Sc,
471 /// Sindhi
472 Sd,
473 /// Northern Sami
474 Se,
475 /// Sango
476 Sg,
477 /// Sinhala
478 Si,
479 /// Slovak
480 Sk,
481 /// Slovenian
482 Sl,
483 /// Samoan
484 Sm,
485 /// Shona
486 Sn,
487 /// Somali
488 So,
489 /// Albanian
490 Sq,
491 /// Serbian
492 Sr,
493 /// Swati
494 Ss,
495 /// Southern Sotho
496 St,
497 /// Sundanese
498 Su,
499 /// Swedish
500 Sv,
501 /// Swahili
502 Sw,
503 /// Tamil
504 Ta,
505 /// Telugu
506 Te,
507 /// Tajik
508 Tg,
509 /// Thai
510 Th,
511 /// Tigrinya
512 Ti,
513 /// Turkmen
514 Tk,
515 /// Tagalog
516 Tl,
517 /// Tswana
518 Tn,
519 /// Tonga
520 To,
521 /// Turkish
522 Tr,
523 /// Tsonga
524 Ts,
525 /// Tatar
526 Tt,
527 /// Twi
528 Tw,
529 /// Tahitian
530 Ty,
531 /// Uyghur
532 Ug,
533 /// Ukrainian
534 Uk,
535 /// Urdu
536 Ur,
537 /// Uzbek
538 Uz,
539 /// Venda
540 Ve,
541 /// Vietnamese
542 Vi,
543 /// Volapük
544 Vo,
545 /// Walloon
546 Wa,
547 /// Wolof
548 Wo,
549 /// Xhosa
550 Xh,
551 /// Yiddish
552 Yi,
553 /// Yoruba
554 Yo,
555 /// Zhuang
556 Za,
557 /// Chinese
558 Zh,
559 /// Zulu
560 Zu,
561}
562
563impl alloc::fmt::Display for Lang {
564 fn fmt(&self, f: &mut alloc::fmt::Formatter<'_>) -> alloc::fmt::Result {
565 write!(f, "{:?}", self)
566 }
567}