icu_datetime/pattern/
mod.rs

1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5//! Lower-level, power-user APIs for formatting datetimes with pattern strings.
6//!
7//! ❗ This module forgoes most internationalization functionality of the datetime crate.
8//! It assumes that the pattern is already localized for the customer's locale. Most clients
9//! should use [`DateTimeFormatter`] instead of directly formatting with patterns.
10//!
11//! [`DateTimeFormatter`]: crate::DateTimeFormatter
12
13mod formatter;
14mod names;
15#[allow(clippy::module_inception)] // the file pattern.rs should contain DateTimePattern
16mod pattern;
17
18pub use crate::error::ErrorField;
19use crate::unchecked::MissingInputFieldKind;
20pub use formatter::DateTimePatternFormatter;
21pub use formatter::FormattedDateTimePattern;
22use icu_calendar::types::MonthCode;
23use icu_calendar::AnyCalendarKind;
24use icu_pattern::SinglePlaceholderPattern;
25pub use names::DateTimeNames;
26pub(crate) use names::DateTimeNamesMetadata;
27pub use names::DayPeriodNameLength;
28pub use names::FixedCalendarDateTimeNames;
29pub use names::MonthNameLength;
30pub(crate) use names::RawDateTimeNames;
31pub(crate) use names::RawDateTimeNamesBorrowed;
32pub(crate) use names::TimeZoneDataPayloadsBorrowed;
33pub use names::WeekdayNameLength;
34pub use names::YearNameLength;
35pub use pattern::DateTimePattern;
36use tinystr::TinyStr16;
37
38#[cfg(doc)]
39use icu_calendar::types::CyclicYear;
40#[cfg(doc)]
41use icu_decimal::DecimalFormatter;
42#[cfg(doc)]
43use writeable::TryWriteable;
44
45pub(crate) enum GetNameForMonthError {
46    InvalidMonthCode,
47    InvalidFieldLength,
48    NotLoaded,
49}
50pub(crate) enum GetNameForWeekdayError {
51    InvalidFieldLength,
52    NotLoaded,
53}
54
55pub(crate) enum GetNameForEraError {
56    InvalidEraCode,
57    InvalidFieldLength,
58    NotLoaded,
59}
60
61pub(crate) enum GetNameForCyclicYearError {
62    InvalidYearNumber { max: u8 },
63    InvalidFieldLength,
64    NotLoaded,
65}
66
67pub(crate) enum GetNameForDayPeriodError {
68    InvalidFieldLength,
69    NotLoaded,
70}
71
72/// Internal enum to represent the kinds of month symbols for interpolation
73pub(crate) enum MonthPlaceholderValue<'a> {
74    PlainString(&'a str),
75    Numeric,
76    NumericPattern(&'a SinglePlaceholderPattern),
77}
78
79/// Error returned from [`FixedCalendarDateTimeNames`]'s pattern load methods.
80#[derive(Debug, Clone, Copy, PartialEq, displaydoc::Display)]
81#[non_exhaustive]
82pub enum PatternLoadError {
83    /// A field conflicts with a previous field.
84    ///
85    /// Fields conflict if they require the same type of data, for example the
86    /// `EEE` and `EEEE` fields (short vs long weekday) conflict, or the `M`
87    /// and `L` (format vs standalone month) conflict.
88    #[displaydoc("A field {field:?} conflicts with a previously loaded field {previous_field:?}.")]
89    ConflictingField {
90        /// The field that was not able to be loaded.
91        field: ErrorField,
92        /// The field that prevented the new field from being loaded.
93        previous_field: ErrorField,
94    },
95    /// The field symbol is not supported in that length.
96    ///
97    /// Some fields, such as `O` are not defined for all lengths (e.g. `OO`).
98    #[displaydoc("The field {0:?} symbol is not supported in that length.")]
99    UnsupportedLength(ErrorField),
100    /// The specific formatter does not support this field.
101    ///
102    /// This happens for example when trying to load a month field
103    /// on a [`FixedCalendarDateTimeNames<Gregorian, ZoneFieldSet>`].
104    #[displaydoc("The specific formatter does not support the field {0:?}.")]
105    FormatterTooSpecific(ErrorField),
106    /// An error arising from the [`data provider`](icu_provider) for loading names.
107    #[displaydoc("Problem loading data for field {1:?}: {0}")]
108    Data(icu_provider::DataError, ErrorField),
109}
110
111impl core::error::Error for PatternLoadError {}
112
113/// Error returned from constructors that map from AnyCalendar to a formatter.
114#[derive(Debug, Clone, Copy, PartialEq, displaydoc::Display)]
115#[displaydoc("The calendar {kind:?} is not supported in DateTimeFormatter")]
116#[non_exhaustive]
117pub struct UnsupportedCalendarError {
118    /// The calendar kind that is not supported.
119    pub kind: AnyCalendarKind,
120}
121
122impl core::error::Error for UnsupportedCalendarError {}
123
124#[non_exhaustive]
125#[derive(Debug, PartialEq, Copy, Clone, displaydoc::Display)]
126/// Error for the [`TryWriteable`] implementation of [`FormattedDateTimePattern`].
127///
128/// There are 3 general conditions for these errors to occur:
129///
130/// 1. Invariants of **unchecked functions** are not upheld
131/// 2. Invariants of **locale data** are not upheld
132/// 3. Invariants of **trait impls** are not upheld (including [scaffolding traits])
133///
134/// It is not always possible to distinguish the source of the errors. Each variant is documented
135/// with rules of thumb for when they might occur.
136///
137/// [unstable scaffolding traits]: crate::scaffold
138pub enum FormattedDateTimePatternError {
139    /// The [`MonthCode`] of the input is not valid for this calendar.
140    ///
141    /// Error conditions:
142    ///
143    /// - **Locale data:** for example, datetime names don't match the formatter's calendar
144    /// - **Trait impls:** for example, the date returns fields for the wrong calendar
145    ///
146    /// The output will contain the raw [`MonthCode`] as a fallback value.
147    #[displaydoc("Invalid month {0:?}")]
148    InvalidMonthCode(MonthCode),
149    /// The era code of the input is not valid for this calendar.
150    ///
151    /// Same error conditions as [`FormattedDateTimePatternError::InvalidMonthCode`].
152    ///
153    /// The output will contain the era code as the fallback.
154    #[displaydoc("Invalid era {0:?}")]
155    InvalidEra(TinyStr16),
156    /// The [`CyclicYear::year`] of the input is not valid for this calendar.
157    ///
158    /// Same error conditions as [`FormattedDateTimePatternError::InvalidMonthCode`].
159    ///
160    /// The output will contain [`CyclicYear::related_iso`] as a fallback value.
161    #[displaydoc("Invalid cyclic year {value} (maximum {max})")]
162    InvalidCyclicYear {
163        /// Value
164        value: u8,
165        /// Max
166        max: u8,
167    },
168
169    /// The localized names for a field have not been loaded.
170    ///
171    /// Error conditions:
172    ///
173    /// - **Unchecked functions:** for example, the pattern in [`with_pattern_unchecked`] contains fields that haven't been loaded
174    /// - **Trait impls:** for example, a custom field set does not include the correct names data
175    ///
176    /// The output will contain fallback values using field identifiers (such as `tue` for `Weekday::Tuesday`,
177    /// `M02` for month 2, etc.).
178    ///
179    /// [`with_pattern_unchecked`]: FixedCalendarDateTimeNames::with_pattern_unchecked
180    #[displaydoc("Names for {0:?} not loaded")]
181    NamesNotLoaded(ErrorField),
182    /// The [`DecimalFormatter`] has not been loaded.
183    ///
184    /// Same error conditions as [`FormattedDateTimePatternError::NamesNotLoaded`].
185    ///
186    /// The output will contain fallback values using Latin numerals.
187    #[displaydoc("DecimalFormatter not loaded")]
188    DecimalFormatterNotLoaded,
189
190    /// An input field (such as "hour" or "month") is missing.
191    ///
192    /// Error conditions:
193    ///
194    /// - **Unchecked functions:** for example, the pattern in [`with_pattern_unchecked`] contains fields that aren't in the fieldset
195    /// - **Trait impls:** for example, a custom field set does not require the correct fields
196    ///
197    /// The output will contain the string `{X}` instead, where `X` is the symbol for which the input is missing.
198    ///
199    /// [`with_pattern_unchecked`]: FixedCalendarDateTimeNames::with_pattern_unchecked
200    #[displaydoc("Incomplete input, missing value for {0:?}")]
201    MissingInputField(MissingInputFieldKind),
202
203    /// The pattern contains a field symbol for which formatting is unsupported.
204    ///
205    /// Error conditions:
206    ///
207    /// - **Unchecked functions:** for example, the pattern in [`with_pattern_unchecked`] contains an unsupported field
208    ///
209    /// The output will contain the string `{unsupported:X}`, where `X` is the symbol of the unsupported field.
210    ///
211    /// [`with_pattern_unchecked`]: FixedCalendarDateTimeNames::with_pattern_unchecked
212    #[displaydoc("Unsupported field {0:?}")]
213    UnsupportedField(ErrorField),
214    /// The pattern contains a field that has a valid symbol but invalid length.
215    ///
216    /// Same error conditions as [`FormattedDateTimePatternError::UnsupportedField`].
217    ///
218    /// The output will contain fallback values similar to [`FormattedDateTimePatternError::NamesNotLoaded`].
219    #[displaydoc("Field length for {0:?} is invalid")]
220    UnsupportedLength(ErrorField),
221}