use crate::{
fields::FieldSymbol,
format::datetime,
options::DateTimeFormatOptions,
pattern::PatternItem,
provider::{gregory::DatesV1, helpers::DateTimePatterns},
};
use icu_locid::Locale;
use icu_provider::{DataProvider, DataRequest, ResourceOptions, ResourcePath};
use std::borrow::Cow;
use crate::{
date::DateTimeInput, pattern::Pattern, provider, DateTimeFormatError, FormattedDateTime,
};
pub struct DateTimeFormat<'d> {
pub(super) locale: Locale,
pub(super) pattern: Pattern,
pub(super) symbols: Cow<'d, provider::gregory::DateSymbolsV1>,
}
impl<'d> DateTimeFormat<'d> {
pub fn try_new<T: Into<Locale>, D: DataProvider<'d, provider::gregory::DatesV1> + ?Sized>(
locale: T,
data_provider: &D,
options: &DateTimeFormatOptions,
) -> Result<Self, DateTimeFormatError> {
let locale = locale.into();
let data = data_provider
.load_payload(&DataRequest {
resource_path: ResourcePath {
key: provider::key::GREGORY_V1,
options: ResourceOptions {
variant: None,
langid: Some(locale.clone().into()),
},
},
})?
.payload
.take()?;
let pattern = data
.patterns
.get_pattern_for_options(options)?
.unwrap_or_default();
let time_zone_field = pattern
.items()
.iter()
.filter_map(|p| match p {
PatternItem::Field(field) => Some(field),
_ => None,
})
.find(|field| matches!(field.symbol, FieldSymbol::TimeZone(_)));
if let Some(field) = time_zone_field {
return Err(DateTimeFormatError::UnsupportedField(field.symbol));
}
Ok(Self::new(locale, pattern, data))
}
pub(super) fn new<T: Into<Locale>>(
locale: T,
pattern: Pattern,
data: Cow<'d, DatesV1>,
) -> Self {
let locale = locale.into();
let symbols = match data {
Cow::Borrowed(data) => Cow::Borrowed(&data.symbols),
Cow::Owned(data) => Cow::Owned(data.symbols),
};
Self {
locale,
pattern,
symbols,
}
}
pub fn format<'l, T>(&'l self, value: &'l T) -> FormattedDateTime<'l, T>
where
T: DateTimeInput,
{
FormattedDateTime {
pattern: &self.pattern,
symbols: &self.symbols,
datetime: value,
locale: &self.locale,
}
}
pub fn format_to_write(
&self,
w: &mut impl std::fmt::Write,
value: &impl DateTimeInput,
) -> std::fmt::Result {
datetime::write_pattern(&self.pattern, &self.symbols, value, &self.locale, w)
.map_err(|_| std::fmt::Error)
}
pub fn format_to_string(&self, value: &impl DateTimeInput) -> String {
let mut s = String::new();
self.format_to_write(&mut s, value)
.expect("Failed to write to a String.");
s
}
}