Skip to content

Commit ce8bdf8

Browse files
authored
Better dynamic datetime field sets (#5761)
#1317
1 parent 09fde64 commit ce8bdf8

22 files changed

+1885
-1376
lines changed

components/datetime/benches/datetime.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ fn datetime_benches(c: &mut Criterion) {
5050
let skeleton = setup.options.semantic.unwrap();
5151

5252
let dtf = {
53-
FixedCalendarDateTimeFormatter::<Gregorian, _>::try_new_with_skeleton(
53+
FixedCalendarDateTimeFormatter::<Gregorian, _>::try_new(
5454
&locale.into(),
5555
skeleton,
5656
)

components/datetime/benches/fixtures/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub struct TestInput {
2424
pub struct TestOptions {
2525
pub length: Option<icu_datetime::options::length::Bag>,
2626
pub components: Option<icu_datetime::options::components::Bag>,
27-
pub semantic: Option<icu_datetime::neo_skeleton::NeoSkeleton>,
27+
pub semantic: Option<icu_datetime::fieldset::dynamic::CompositeFieldSet>,
2828
pub preferences: Option<icu_datetime::options::preferences::Bag>,
2929
}
3030

components/datetime/src/combo.rs

+68-240
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,30 @@
55
use core::marker::PhantomData;
66

77
use crate::{format::neo::*, neo_skeleton::*, provider::neo::*, scaffold::*};
8-
use icu_provider::marker::NeverMarker;
98

10-
/// Struct for combining date, time, and zone fields.
9+
/// Struct for combining date/time fields with zone fields.
1110
///
1211
/// This struct produces "composite field sets" as defined in UTS 35.
1312
///
13+
/// This struct does not have its own constructor, but it can be produced via
14+
/// factory functions on the other field sets.
15+
///
1416
/// # Examples
1517
///
1618
/// Format the weekday, hour, and location-based zone:
1719
///
1820
/// ```
19-
/// use icu::datetime::fieldset::{Combo, E, T, L};
21+
/// use icu::datetime::fieldset::{Combo, ET, L};
2022
/// use icu::datetime::DateTimeFormatter;
2123
/// use icu::locale::locale;
2224
/// use icu::timezone::IxdtfParser;
2325
/// use writeable::assert_try_writeable_eq;
2426
///
27+
/// let field_set: Combo<ET, L> = ET::short().hm().l();
28+
///
2529
/// let formatter = DateTimeFormatter::try_new(
2630
/// &locale!("en-US").into(),
27-
/// Combo::<E, T, L>::short().hm(),
31+
/// field_set,
2832
/// )
2933
/// .unwrap();
3034
///
@@ -43,15 +47,17 @@ use icu_provider::marker::NeverMarker;
4347
///
4448
/// ```
4549
/// use icu::calendar::Gregorian;
46-
/// use icu::datetime::fieldset::{Combo, E, T, L};
50+
/// use icu::datetime::fieldset::{Combo, ET, L};
4751
/// use icu::datetime::FixedCalendarDateTimeFormatter;
4852
/// use icu::locale::locale;
4953
/// use icu::timezone::IxdtfParser;
5054
/// use writeable::assert_try_writeable_eq;
5155
///
56+
/// let field_set: Combo<ET, L> = ET::short().hm().l();
57+
///
5258
/// let formatter = FixedCalendarDateTimeFormatter::try_new(
5359
/// &locale!("en-US").into(),
54-
/// Combo::<E, T, L>::short().hm(),
60+
/// field_set,
5561
/// )
5662
/// .unwrap();
5763
///
@@ -66,232 +72,67 @@ use icu_provider::marker::NeverMarker;
6672
/// "Fri, 3:44 PM Los Angeles Time"
6773
/// );
6874
/// ```
69-
#[derive(Debug)]
70-
pub struct Combo<D, T, Z> {
71-
_d: PhantomData<D>,
72-
_t: PhantomData<T>,
75+
///
76+
/// Mix a dynamic [`DateFieldSet`](crate::fieldset::dynamic::DateFieldSet)
77+
/// with a static time zone:
78+
///
79+
/// ```
80+
/// use icu::datetime::fieldset::{YMD, dynamic::DateFieldSet};
81+
/// use icu::datetime::DateTimeFormatter;
82+
/// use icu::locale::locale;
83+
/// use icu::timezone::IxdtfParser;
84+
/// use writeable::assert_try_writeable_eq;
85+
///
86+
/// let formatter = DateTimeFormatter::try_new(
87+
/// &locale!("en-US").into(),
88+
/// DateFieldSet::YMD(YMD::long()).v(),
89+
/// )
90+
/// .unwrap();
91+
///
92+
/// let zdt = IxdtfParser::new().try_location_only_from_str(
93+
/// "2024-10-18T15:44[America/Los_Angeles]",
94+
/// )
95+
/// .unwrap();
96+
///
97+
/// assert_try_writeable_eq!(
98+
/// formatter.convert_and_format(&zdt),
99+
/// "October 18, 2024 PT"
100+
/// );
101+
/// ```
102+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
103+
pub struct Combo<DT, Z> {
104+
date_time_field_set: DT,
73105
_z: PhantomData<Z>,
74-
/// Desired formatting length.
75-
pub length: NeoSkeletonLength,
76-
/// Alignment option.
77-
pub alignment: Option<Alignment>,
78-
/// Era display option.
79-
pub year_style: Option<YearStyle>,
80-
/// Time precision option.
81-
pub time_precision: Option<TimePrecision>,
82106
}
83107

84-
impl<D, T, Z> UnstableSealed for Combo<D, T, Z> {}
85-
86-
impl<D, T, Z> Combo<D, T, Z> {
87-
/// Creates a date/time/zone skeleton with the given formatting length.
88-
pub const fn with_length(length: NeoSkeletonLength) -> Self {
108+
impl<DT, Z> Combo<DT, Z> {
109+
#[inline]
110+
pub(crate) const fn new(date_time_field_set: DT) -> Self {
89111
Self {
90-
_d: PhantomData,
91-
_t: PhantomData,
112+
date_time_field_set,
92113
_z: PhantomData,
93-
length,
94-
alignment: None,
95-
year_style: None,
96-
time_precision: None,
97114
}
98115
}
99-
/// Creates a date/time/zone skeleton with a long length.
100-
pub const fn long() -> Self {
101-
Self::with_length(NeoSkeletonLength::Long)
102-
}
103-
/// Creates a date/time/zone skeleton with a medium length.
104-
pub const fn medium() -> Self {
105-
Self::with_length(NeoSkeletonLength::Medium)
106-
}
107-
/// Creates a date/time/zone skeleton with a short length.
108-
pub const fn short() -> Self {
109-
Self::with_length(NeoSkeletonLength::Short)
110-
}
111-
112-
/// Sets the time precision to [`TimePrecision::MinuteExact`]
113-
pub fn hm(mut self) -> Self {
114-
self.time_precision = Some(TimePrecision::MinuteExact);
115-
self
116-
}
117-
/// Sets the time precision to [`TimePrecision::SecondPlus`]
118-
pub fn hms(mut self) -> Self {
119-
self.time_precision = Some(TimePrecision::SecondPlus);
120-
self
121-
}
122-
}
123-
124-
impl_get_field!(<D, T, Z> Combo<D, T, Z>, never);
125-
impl_get_field!(<D, T, Z> Combo<D, T, Z>, length, yes);
126-
impl_get_field!(<D, T, Z> Combo<D, T, Z>, alignment, yes);
127-
impl_get_field!(<D, T, Z> Combo<D, T, Z>, year_style, yes);
128-
impl_get_field!(<D, T, Z> Combo<D, T, Z>, time_precision, yes);
129-
130-
impl<D> DateTimeNamesMarker for Combo<D, NeoNeverMarker, NeoNeverMarker>
131-
where
132-
D: DateTimeNamesMarker,
133-
{
134-
type YearNames = D::YearNames;
135-
type MonthNames = D::MonthNames;
136-
type WeekdayNames = D::WeekdayNames;
137-
type DayPeriodNames = NeverMarker<()>;
138-
type ZoneEssentials = NeverMarker<()>;
139-
type ZoneLocations = NeverMarker<()>;
140-
type ZoneGenericLong = NeverMarker<()>;
141-
type ZoneGenericShort = NeverMarker<()>;
142-
type ZoneSpecificLong = NeverMarker<()>;
143-
type ZoneSpecificShort = NeverMarker<()>;
144-
type MetazoneLookup = NeverMarker<()>;
145-
}
146-
147-
impl<D> HasConstComponents for Combo<D, NeoNeverMarker, NeoNeverMarker>
148-
where
149-
D: HasConstDateComponents,
150-
{
151-
const COMPONENTS: NeoComponents = NeoComponents::Date(D::COMPONENTS);
152116
}
153117

154-
impl<D> DateTimeMarkers for Combo<D, NeoNeverMarker, NeoNeverMarker>
155-
where
156-
D: DateTimeMarkers,
157-
{
158-
type D = D;
159-
type T = NeoNeverMarker;
160-
type Z = NeoNeverMarker;
161-
type LengthOption = NeoSkeletonLength; // always needed for date
162-
type AlignmentOption = D::AlignmentOption;
163-
type YearStyleOption = D::YearStyleOption;
164-
type TimePrecisionOption = ();
165-
type GluePatternV1Marker = NeverMarker<GluePatternV1<'static>>;
166-
}
118+
impl<DT, Z> UnstableSealed for Combo<DT, Z> {}
167119

168-
impl<T> DateTimeNamesMarker for Combo<NeoNeverMarker, T, NeoNeverMarker>
169-
where
170-
T: DateTimeNamesMarker,
171-
{
172-
type YearNames = NeverMarker<()>;
173-
type MonthNames = NeverMarker<()>;
174-
type WeekdayNames = NeverMarker<()>;
175-
type DayPeriodNames = T::DayPeriodNames;
176-
type ZoneEssentials = NeverMarker<()>;
177-
type ZoneLocations = NeverMarker<()>;
178-
type ZoneGenericLong = NeverMarker<()>;
179-
type ZoneGenericShort = NeverMarker<()>;
180-
type ZoneSpecificLong = NeverMarker<()>;
181-
type ZoneSpecificShort = NeverMarker<()>;
182-
type MetazoneLookup = NeverMarker<()>;
183-
}
184-
185-
impl<T> HasConstComponents for Combo<NeoNeverMarker, T, NeoNeverMarker>
186-
where
187-
T: HasConstTimeComponents,
188-
{
189-
const COMPONENTS: NeoComponents = NeoComponents::Time(T::COMPONENTS);
190-
}
191-
192-
impl<T> DateTimeMarkers for Combo<NeoNeverMarker, T, NeoNeverMarker>
193-
where
194-
T: DateTimeMarkers,
195-
{
196-
type D = NeoNeverMarker;
197-
type T = T;
198-
type Z = NeoNeverMarker;
199-
type LengthOption = NeoSkeletonLength; // always needed for time
200-
type AlignmentOption = Option<Alignment>; // always needed for time
201-
type YearStyleOption = (); // no year in a time-only format
202-
type TimePrecisionOption = T::TimePrecisionOption;
203-
type GluePatternV1Marker = NeverMarker<GluePatternV1<'static>>;
204-
}
205-
206-
impl<Z> DateTimeNamesMarker for Combo<NeoNeverMarker, NeoNeverMarker, Z>
207-
where
208-
Z: DateTimeNamesMarker,
209-
{
210-
type YearNames = NeverMarker<()>;
211-
type MonthNames = NeverMarker<()>;
212-
type WeekdayNames = NeverMarker<()>;
213-
type DayPeriodNames = NeverMarker<()>;
214-
type ZoneEssentials = Z::ZoneEssentials;
215-
type ZoneLocations = Z::ZoneLocations;
216-
type ZoneGenericLong = Z::ZoneGenericLong;
217-
type ZoneGenericShort = Z::ZoneGenericShort;
218-
type ZoneSpecificLong = Z::ZoneSpecificLong;
219-
type ZoneSpecificShort = Z::ZoneSpecificShort;
220-
type MetazoneLookup = Z::MetazoneLookup;
221-
}
222-
223-
impl<Z> HasConstComponents for Combo<NeoNeverMarker, NeoNeverMarker, Z>
224-
where
225-
Z: HasConstZoneComponent,
226-
{
227-
const COMPONENTS: NeoComponents = NeoComponents::Zone(Z::COMPONENT);
228-
}
229-
230-
impl<Z> DateTimeMarkers for Combo<NeoNeverMarker, NeoNeverMarker, Z>
231-
where
232-
Z: DateTimeMarkers,
233-
{
234-
type D = NeoNeverMarker;
235-
type T = NeoNeverMarker;
236-
type Z = Z;
237-
type LengthOption = Z::LengthOption; // no date or time: inherit from zone
238-
type AlignmentOption = Z::AlignmentOption; // no date or time: inherit from zone
239-
type YearStyleOption = (); // no year in a zone-only format
240-
type TimePrecisionOption = ();
241-
type GluePatternV1Marker = GluePatternV1Marker;
242-
}
243-
244-
impl<D, T> DateTimeNamesMarker for Combo<D, T, NeoNeverMarker>
245-
where
246-
D: DateTimeNamesMarker,
247-
T: DateTimeNamesMarker,
248-
{
249-
type YearNames = D::YearNames;
250-
type MonthNames = D::MonthNames;
251-
type WeekdayNames = D::WeekdayNames;
252-
type DayPeriodNames = T::DayPeriodNames;
253-
type ZoneEssentials = NeverMarker<()>;
254-
type ZoneLocations = NeverMarker<()>;
255-
type ZoneGenericLong = NeverMarker<()>;
256-
type ZoneGenericShort = NeverMarker<()>;
257-
type ZoneSpecificLong = NeverMarker<()>;
258-
type ZoneSpecificShort = NeverMarker<()>;
259-
type MetazoneLookup = NeverMarker<()>;
260-
}
261-
262-
impl<D, T> HasConstComponents for Combo<D, T, NeoNeverMarker>
263-
where
264-
D: HasConstDateComponents,
265-
T: HasConstTimeComponents,
266-
{
267-
const COMPONENTS: NeoComponents = NeoComponents::DateTime(D::COMPONENTS, T::COMPONENTS);
268-
}
269-
270-
impl<D, T> DateTimeMarkers for Combo<D, T, NeoNeverMarker>
271-
where
272-
D: DateTimeMarkers,
273-
T: DateTimeMarkers,
274-
{
275-
type D = D;
276-
type T = T;
277-
type Z = NeoNeverMarker;
278-
type LengthOption = NeoSkeletonLength; // always needed for date/time
279-
type AlignmentOption = Option<Alignment>; // always needed for date/time
280-
type YearStyleOption = D::YearStyleOption;
281-
type TimePrecisionOption = T::TimePrecisionOption;
282-
type GluePatternV1Marker = GluePatternV1Marker;
120+
impl<DT, Z> Combo<DT, Z> {
121+
#[inline]
122+
pub(crate) fn dt(self) -> DT {
123+
self.date_time_field_set
124+
}
283125
}
284126

285-
impl<D, T, Z> DateTimeNamesMarker for Combo<D, T, Z>
127+
impl<DT, Z> DateTimeNamesMarker for Combo<DT, Z>
286128
where
287-
D: DateTimeNamesMarker,
288-
T: DateTimeNamesMarker,
129+
DT: DateTimeNamesMarker,
289130
Z: DateTimeNamesMarker,
290131
{
291-
type YearNames = D::YearNames;
292-
type MonthNames = D::MonthNames;
293-
type WeekdayNames = D::WeekdayNames;
294-
type DayPeriodNames = T::DayPeriodNames;
132+
type YearNames = DT::YearNames;
133+
type MonthNames = DT::MonthNames;
134+
type WeekdayNames = DT::WeekdayNames;
135+
type DayPeriodNames = DT::DayPeriodNames;
295136
type ZoneEssentials = Z::ZoneEssentials;
296137
type ZoneLocations = Z::ZoneLocations;
297138
type ZoneGenericLong = Z::ZoneGenericLong;
@@ -301,30 +142,17 @@ where
301142
type MetazoneLookup = Z::MetazoneLookup;
302143
}
303144

304-
impl<D, T, Z> HasConstComponents for Combo<D, T, Z>
145+
impl<DT, Z> DateTimeMarkers for Combo<DT, Z>
305146
where
306-
D: HasConstDateComponents,
307-
T: HasConstTimeComponents,
308-
Z: HasConstZoneComponent,
309-
{
310-
const COMPONENTS: NeoComponents =
311-
NeoComponents::DateTimeZone(D::COMPONENTS, T::COMPONENTS, Z::COMPONENT);
312-
}
313-
314-
impl<D, T, Z> DateTimeMarkers for Combo<D, T, Z>
315-
where
316-
D: DateTimeMarkers,
317-
T: DateTimeMarkers,
147+
DT: DateTimeMarkers,
318148
Z: DateTimeMarkers,
319149
{
320-
type D = D;
321-
type T = T;
322-
type Z = Z;
323-
type LengthOption = NeoSkeletonLength; // always needed for date/time
324-
type AlignmentOption = Option<Alignment>; // always needed for date/time
325-
type YearStyleOption = D::YearStyleOption;
326-
type TimePrecisionOption = T::TimePrecisionOption;
327-
type GluePatternV1Marker = GluePatternV1Marker;
150+
type D = DT::D;
151+
type T = DT::T;
152+
type Z = Z::Z;
153+
type LengthOption = NeoSkeletonLength; // always needed for date
154+
type AlignmentOption = DT::AlignmentOption;
155+
type YearStyleOption = DT::YearStyleOption;
156+
type TimePrecisionOption = DT::TimePrecisionOption;
157+
type GluePatternV1Marker = datetime_marker_helper!(@glue, yes);
328158
}
329-
330-
// TODO: Fill in the missing Combos, like DZ and TZ

0 commit comments

Comments
 (0)