Skip to main content

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}