use crate::{
options::{length, preferences, DateTimeFormatterOptions},
provider::calendar::{TimeLengthsV1Marker, TimeSymbolsV1Marker},
provider::date_time::PatternSelector,
raw,
};
use alloc::string::String;
use core::marker::PhantomData;
use icu_calendar::provider::WeekDataV1Marker;
use icu_decimal::provider::DecimalSymbolsV1Marker;
use icu_plurals::provider::OrdinalV1Marker;
use icu_provider::prelude::*;
use writeable::Writeable;
use crate::{
calendar, input::DateInput, input::DateTimeInput, input::IsoTimeInput, CldrCalendar,
DateTimeError, FormattedDateTime,
};
#[cfg(feature = "experimental")]
use crate::options::components;
#[derive(Debug)]
pub struct TimeFormatter(pub(super) raw::TimeFormatter);
impl TimeFormatter {
#[inline]
pub fn try_new_with_length_unstable<D>(
data_provider: &D,
locale: &DataLocale,
length: length::Time,
) -> Result<Self, DateTimeError>
where
D: DataProvider<TimeLengthsV1Marker>
+ DataProvider<TimeSymbolsV1Marker>
+ DataProvider<DecimalSymbolsV1Marker>
+ ?Sized,
{
let preferences = Some(preferences::Bag::from_data_locale(locale));
Ok(Self(raw::TimeFormatter::try_new(
data_provider,
locale,
length,
preferences,
)?))
}
icu_provider::gen_any_buffer_constructors!(
locale: include,
length: length::Time,
error: DateTimeError,
functions: [
Self::try_new_with_length_unstable,
try_new_with_length_with_any_provider,
try_new_with_length_with_buffer_provider
]
);
#[inline]
pub fn format<'l, T>(&'l self, value: &T) -> FormattedDateTime<'l>
where
T: IsoTimeInput,
{
self.0.format(value)
}
#[inline]
pub fn format_to_string(&self, value: &impl IsoTimeInput) -> String {
self.format(value).write_to_string().into_owned()
}
}
#[derive(Debug)]
pub struct TypedDateFormatter<C>(pub(super) raw::DateFormatter, PhantomData<C>);
impl<C: CldrCalendar> TypedDateFormatter<C> {
#[inline]
pub fn try_new_with_length_unstable<D>(
data_provider: &D,
locale: &DataLocale,
length: length::Date,
) -> Result<Self, DateTimeError>
where
D: DataProvider<<C as CldrCalendar>::DateSymbolsV1Marker>
+ DataProvider<<C as CldrCalendar>::DateLengthsV1Marker>
+ DataProvider<DecimalSymbolsV1Marker>
+ DataProvider<OrdinalV1Marker>
+ DataProvider<WeekDataV1Marker>
+ ?Sized,
{
Ok(Self(
raw::DateFormatter::try_new(
data_provider,
calendar::load_lengths_for_cldr_calendar::<C, _>(data_provider, locale)?,
|| calendar::load_symbols_for_cldr_calendar::<C, _>(data_provider, locale),
locale,
length,
)?,
PhantomData,
))
}
icu_provider::gen_any_buffer_constructors!(
locale: include,
length: length::Date,
error: DateTimeError,
functions: [
Self::try_new_with_length_unstable,
try_new_with_length_with_any_provider,
try_new_with_length_with_buffer_provider
]
);
#[inline]
pub fn format<'l, T>(&'l self, value: &T) -> FormattedDateTime<'l>
where
T: DateInput<Calendar = C>,
{
self.0.format(value)
}
#[inline]
pub fn format_to_string(&self, value: &impl DateInput<Calendar = C>) -> String {
self.format(value).write_to_string().into_owned()
}
}
#[derive(Debug)]
pub struct TypedDateTimeFormatter<C>(pub(super) raw::DateTimeFormatter, PhantomData<C>);
impl<C: CldrCalendar> TypedDateTimeFormatter<C> {
#[inline]
pub fn try_from_date_and_time(
date: TypedDateFormatter<C>,
time: TimeFormatter,
) -> Result<Self, DateTimeError>
where {
Ok(Self(
raw::DateTimeFormatter::try_from_date_and_time(date.0, time.0)?,
PhantomData,
))
}
#[cfg(feature = "experimental")]
#[inline]
pub fn try_new_experimental_unstable<D>(
data_provider: &D,
locale: &DataLocale,
options: DateTimeFormatterOptions,
) -> Result<Self, DateTimeError>
where
D: DataProvider<<C as CldrCalendar>::DateSymbolsV1Marker>
+ DataProvider<<C as CldrCalendar>::DateLengthsV1Marker>
+ DataProvider<TimeSymbolsV1Marker>
+ DataProvider<TimeLengthsV1Marker>
+ DataProvider<crate::provider::calendar::DateSkeletonPatternsV1Marker>
+ DataProvider<DecimalSymbolsV1Marker>
+ DataProvider<OrdinalV1Marker>
+ DataProvider<WeekDataV1Marker>
+ ?Sized,
{
let patterns = PatternSelector::for_options_experimental(
data_provider,
calendar::load_lengths_for_cldr_calendar::<C, _>(data_provider, locale)?,
locale,
&C::DEFAULT_BCP_47_IDENTIFIER,
&options,
)?;
Ok(Self(
raw::DateTimeFormatter::try_new(
data_provider,
patterns,
|| calendar::load_symbols_for_cldr_calendar::<C, _>(data_provider, locale),
locale,
)?,
PhantomData,
))
}
#[inline]
pub fn try_new_unstable<D>(
data_provider: &D,
locale: &DataLocale,
options: DateTimeFormatterOptions,
) -> Result<Self, DateTimeError>
where
D: DataProvider<<C as CldrCalendar>::DateSymbolsV1Marker>
+ DataProvider<<C as CldrCalendar>::DateLengthsV1Marker>
+ DataProvider<TimeSymbolsV1Marker>
+ DataProvider<TimeLengthsV1Marker>
+ DataProvider<DecimalSymbolsV1Marker>
+ DataProvider<OrdinalV1Marker>
+ DataProvider<WeekDataV1Marker>
+ ?Sized,
{
let patterns = PatternSelector::for_options(
data_provider,
calendar::load_lengths_for_cldr_calendar::<C, _>(data_provider, locale)?,
locale,
&options,
)?;
Ok(Self(
raw::DateTimeFormatter::try_new(
data_provider,
patterns,
|| calendar::load_symbols_for_cldr_calendar::<C, _>(data_provider, locale),
locale,
)?,
PhantomData,
))
}
icu_provider::gen_any_buffer_constructors!(
locale: include,
options: DateTimeFormatterOptions,
error: DateTimeError
);
#[inline]
pub fn format<'l, T>(&'l self, value: &T) -> FormattedDateTime<'l>
where
T: DateTimeInput<Calendar = C>,
{
self.0.format(value)
}
#[inline]
pub fn format_to_string(&self, value: &impl DateTimeInput<Calendar = C>) -> String {
self.format(value).write_to_string().into_owned()
}
#[cfg(feature = "experimental")]
pub fn resolve_components(&self) -> components::Bag {
self.0.resolve_components()
}
}
#[cfg(test)]
mod tests {
use super::*;
use icu_calendar::DateTime;
use icu_calendar::Gregorian;
#[test]
#[cfg(feature = "serde")]
fn works_with_default_options() {
assert_eq!(
TypedDateTimeFormatter::<Gregorian>::try_new_with_buffer_provider(
&icu_testdata::buffer(),
Default::default(),
Default::default(),
)
.unwrap()
.format_to_string(&DateTime::try_new_gregorian_datetime(2022, 9, 20, 0, 0, 0).unwrap()),
"2022 M09 20 00:00:00"
);
}
}