diff --git a/components/datetime/tests/resolved_components.rs b/components/datetime/tests/resolved_components.rs index 140b16350f3..5f6640983d2 100644 --- a/components/datetime/tests/resolved_components.rs +++ b/components/datetime/tests/resolved_components.rs @@ -106,3 +106,42 @@ fn test_date_and_time() { "en-u-hc-h23".parse::().unwrap(), ); } + +/// More thorough test of `components::Bag::hour_cycle` across multiple locales, +/// including region-based defaults and explicit overrides. +/// Fixes . +#[test] +fn test_hour_cycle_resolved_components() { + let skeleton = CompositeDateTimeFieldSet::Time(TimeFieldSet::T(fieldsets::T::short())); + + let check = |locale_str: &str, expected: HourCycle| { + let locale: Locale = locale_str.parse().unwrap(); + let dtf = FixedCalendarDateTimeFormatter::::try_new(locale.into(), skeleton) + .unwrap(); + let datetime = DateTime { + date: Date::try_new_gregorian(2024, 1, 15).unwrap(), + time: Time::try_new(21, 22, 0, 0).unwrap(), + }; + let bag = components::Bag::from(&dtf.format(&datetime).pattern()); + assert_eq!( + bag.hour_cycle, + Some(expected), + "{locale_str}: expected {expected:?}, got {:?}", + bag.hour_cycle, + ); + }; + + // h12 locales + check("en", HourCycle::H12); + check("ko", HourCycle::H12); + + // h23 locales + check("fr", HourCycle::H23); + check("ja", HourCycle::H23); + check("de", HourCycle::H23); + check("en-GB", HourCycle::H23); // same language, different region + + // explicit -u-hc- overrides + check("fr-u-hc-h12", HourCycle::H12); + check("en-u-hc-h23", HourCycle::H23); +} diff --git a/provider/source/src/datetime/semantic_skeletons/tests.rs b/provider/source/src/datetime/semantic_skeletons/tests.rs index 81803bc5b66..04de9da1c4f 100644 --- a/provider/source/src/datetime/semantic_skeletons/tests.rs +++ b/provider/source/src/datetime/semantic_skeletons/tests.rs @@ -511,3 +511,35 @@ mod date_skeleton_consistency_tests { } } } + +/// Verify that `preferred_hour_cycle()` infers the correct `CoarseHourCycle` +/// from CLDR time skeleton patterns. +#[test] +fn test_preferred_hour_cycle_by_locale() { + use icu::datetime::provider::pattern::CoarseHourCycle; + + let provider = SourceDataProvider::new_testing(); + + // (locale, expected coarse hour cycle) + let cases = [ + ("en", CoarseHourCycle::H11H12), // US English + ("fr", CoarseHourCycle::H23), // French + // en-GB not in test data; en-ZA follows UK conventions (h23) + ("en-ZA", CoarseHourCycle::H23), + ("ja", CoarseHourCycle::H23), // Japanese + ]; + + for (locale_str, expected) in cases { + let locale = locale_str.parse::().unwrap(); + let data = provider + .get_dates_resource(&locale, Some(DatagenCalendar::Gregorian)) + .expect("Failed to load dates resource"); + + let actual = preferred_hour_cycle(data, &locale); + + assert_eq!( + actual, expected, + "Locale {locale_str}: expected {expected:?}, got {actual:?}" + ); + } +}