Module icu_datetime::neo_marker

source ·
Expand description

Temporary module for neo formatter markers.

§Examples

§Alignment

By default, datetimes are formatted for a variable-width context. You can give a hint that the strings will be displayed in a column-like context, which will coerce numerics to be padded with zeros.

use icu::calendar::Date;
use icu::calendar::Gregorian;
use icu::datetime::neo::NeoOptions;
use icu::datetime::neo::TypedNeoFormatter;
use icu::datetime::neo_marker::NeoYearMonthDayMarker;
use icu::datetime::neo_skeleton::Alignment;
use icu::datetime::neo_skeleton::NeoSkeletonLength;
use icu::locale::locale;
use writeable::assert_try_writeable_eq;

let plain_formatter =
    TypedNeoFormatter::<Gregorian, NeoYearMonthDayMarker>::try_new(
        &locale!("en-US").into(),
        NeoSkeletonLength::Short.into(),
    )
    .unwrap();

let column_formatter =
    TypedNeoFormatter::<Gregorian, NeoYearMonthDayMarker>::try_new(
        &locale!("en-US").into(),
        {
            let mut options = NeoOptions::from(NeoSkeletonLength::Short);
            options.alignment = Some(Alignment::Column);
            options
        }
    )
    .unwrap();

// By default, en-US does not pad the month and day with zeros.
assert_try_writeable_eq!(
    plain_formatter.format(&Date::try_new_gregorian_date(2025, 1, 1).unwrap()),
    "1/1/25"
);

// The column alignment option hints that they should be padded.
assert_try_writeable_eq!(
    column_formatter.format(&Date::try_new_gregorian_date(2025, 1, 1).unwrap()),
    "01/01/25"
);

§Era Display

The era field can be toggled on and off using the EraDisplay option.

use icu::calendar::Date;
use icu::calendar::Gregorian;
use icu::datetime::neo::NeoOptions;
use icu::datetime::neo::TypedNeoFormatter;
use icu::datetime::neo_marker::NeoEraYearMonthDayMarker;
use icu::datetime::neo_skeleton::EraDisplay;
use icu::datetime::neo_skeleton::NeoSkeletonLength;
use icu::locale::locale;
use writeable::assert_try_writeable_eq;

let formatter =
    TypedNeoFormatter::<Gregorian, NeoEraYearMonthDayMarker>::try_new(
        &locale!("en-US").into(),
        {
            let mut options = NeoOptions::from(NeoSkeletonLength::Medium);
            options.era_display = Some(EraDisplay::Auto);
            options
        }
    )
    .unwrap();

// Era displayed when needed for disambiguation,
// such as years before year 0 and small year numbers:
assert_try_writeable_eq!(
    formatter.format(&Date::try_new_gregorian_date(-1000, 1, 1).unwrap()),
    "Jan 1, 1001 BC"
);
assert_try_writeable_eq!(
    formatter.format(&Date::try_new_gregorian_date(77, 1, 1).unwrap()),
    "Jan 1, 77 AD"
);
// Era elided for modern years:
assert_try_writeable_eq!(
    formatter.format(&Date::try_new_gregorian_date(2023, 12, 20).unwrap()),
    "Dec 20, 2023"
);

let formatter =
    TypedNeoFormatter::<Gregorian, NeoEraYearMonthDayMarker>::try_new(
        &locale!("en-US").into(),
        {
            let mut options = NeoOptions::from(NeoSkeletonLength::Medium);
            options.era_display = Some(EraDisplay::Always);
            options
        }
    )
    .unwrap();

// Era still displayed in cases with ambiguity:
assert_try_writeable_eq!(
    formatter.format(&Date::try_new_gregorian_date(-1000, 1, 1).unwrap()),
    "Jan 1, 1001 BC"
);
assert_try_writeable_eq!(
    formatter.format(&Date::try_new_gregorian_date(77, 1, 1).unwrap()),
    "Jan 1, 77 AD"
);
// But now it is shown even on modern years:
assert_try_writeable_eq!(
    formatter.format(&Date::try_new_gregorian_date(2023, 12, 20).unwrap()),
    "Dec 20, 2023 AD"
);

§Hour Cycle

Hours can be switched between 12-hour and 24-hour time via the u-hc locale keyword.

use icu::calendar::Time;
use icu::datetime::neo::TypedNeoFormatter;
use icu::datetime::neo_marker::NeoHourMinuteMarker;
use icu::datetime::neo_skeleton::NeoSkeletonLength;
use icu::datetime::NeverCalendar;
use icu::locale::locale;
use writeable::assert_try_writeable_eq;

// By default, en-US uses 12-hour time and fr-FR uses 24-hour time,
// but we can set overrides.

let formatter =
    TypedNeoFormatter::<NeverCalendar, NeoHourMinuteMarker>::try_new(
        &locale!("en-US-u-hc-h12").into(),
        NeoSkeletonLength::Short.into(),
    )
    .unwrap();
assert_try_writeable_eq!(
    formatter.format(&Time::try_new(16, 12, 20, 0).unwrap()),
    "4:12 PM"
);

let formatter =
    TypedNeoFormatter::<NeverCalendar, NeoHourMinuteMarker>::try_new(
        &locale!("en-US-u-hc-h23").into(),
        NeoSkeletonLength::Short.into(),
    )
    .unwrap();
assert_try_writeable_eq!(
    formatter.format(&Time::try_new(16, 12, 20, 0).unwrap()),
    "16:12"
);

let formatter =
    TypedNeoFormatter::<NeverCalendar, NeoHourMinuteMarker>::try_new(
        &locale!("fr-FR-u-hc-h12").into(),
        NeoSkeletonLength::Short.into(),
    )
    .unwrap();
assert_try_writeable_eq!(
    formatter.format(&Time::try_new(16, 12, 20, 0).unwrap()),
    "4:12 PM"
);

let formatter =
    TypedNeoFormatter::<NeverCalendar, NeoHourMinuteMarker>::try_new(
        &locale!("fr-FR-u-hc-h23").into(),
        NeoSkeletonLength::Short.into(),
    )
    .unwrap();
assert_try_writeable_eq!(
    formatter.format(&Time::try_new(16, 12, 20, 0).unwrap()),
    "16:12"
);

Hour cycles h11 and h24 are supported, too:

use icu::calendar::Time;
use icu::datetime::neo::TypedNeoFormatter;
use icu::datetime::neo_marker::NeoHourMinuteMarker;
use icu::datetime::neo_skeleton::NeoSkeletonLength;
use icu::datetime::NeverCalendar;
use icu::locale::locale;
use writeable::assert_try_writeable_eq;

let formatter =
    TypedNeoFormatter::<NeverCalendar, NeoHourMinuteMarker>::try_new(
        &locale!("und-u-hc-h11").into(),
        NeoSkeletonLength::Short.into(),
    )
    .unwrap();
assert_try_writeable_eq!(
    formatter.format(&Time::try_new(0, 0, 0, 0).unwrap()),
    "0:00 AM"
);

let formatter =
    TypedNeoFormatter::<NeverCalendar, NeoHourMinuteMarker>::try_new(
        &locale!("und-u-hc-h24").into(),
        NeoSkeletonLength::Short.into(),
    )
    .unwrap();
assert_try_writeable_eq!(
    formatter.format(&Time::try_new(0, 0, 0, 0).unwrap()),
    "24:00"
);

§Fractional Second Digits

Times can be displayed with a custom number of fractional digits from 0-9:

use icu::calendar::Gregorian;
use icu::calendar::Time;
use icu::datetime::neo::NeoOptions;
use icu::datetime::neo::TypedNeoFormatter;
use icu::datetime::neo_marker::NeoHourMinuteSecondMarker;
use icu::datetime::neo_skeleton::NeoSkeletonLength;
use icu::datetime::neo_skeleton::FractionalSecondDigits;
use icu::datetime::NeverCalendar;
use icu::locale::locale;
use writeable::assert_try_writeable_eq;

let formatter =
    TypedNeoFormatter::<NeverCalendar, NeoHourMinuteSecondMarker>::try_new(
        &locale!("en-US").into(),
        {
            let mut options = NeoOptions::from(NeoSkeletonLength::Short);
            options.fractional_second_digits = Some(FractionalSecondDigits::F2);
            options
        }
    )
    .unwrap();

assert_try_writeable_eq!(
    formatter.format(&Time::try_new(16, 12, 20, 543200000).unwrap()),
    "4:12:20.54 PM"
);

§Time Zone Formatting

Here, we configure a NeoFormatter to format with generic non-location short, which falls back to the offset when unavailable (see NeoTimeZoneGenericShortMarker).

use icu::calendar::DateTime;
use icu::timezone::{CustomTimeZone, MetazoneCalculator, TimeZoneIdMapper, TimeZoneBcp47Id};
use icu::datetime::neo::TypedNeoFormatter;
use icu::datetime::neo_marker::NeoTimeZoneGenericShortMarker;
use icu::datetime::NeverCalendar;
use icu::locale::locale;
use tinystr::tinystr;
use writeable::assert_try_writeable_eq;

// Set up the time zone. Note: the inputs here are
//   1. The offset
//   2. The IANA time zone ID
//   3. A datetime (for metazone resolution)
//   4. Note: we do not need the zone variant because of `load_generic_*()`

// Set up the Metazone calculator, time zone ID mapper,
// and the DateTime to use in calculation
let mzc = MetazoneCalculator::new();
let mapper = TimeZoneIdMapper::new();
let datetime = DateTime::try_new_iso_datetime(2022, 8, 29, 0, 0, 0)
    .unwrap();

// Set up the formatter
let mut tzf = TypedNeoFormatter::<NeverCalendar, NeoTimeZoneGenericShortMarker>::try_new(
    &locale!("en").into(),
    // Length does not matter here: it is specified in the type parameter
    Default::default(),
)
.unwrap();

// "uschi" - has metazone symbol data for generic_non_location_short
let mut time_zone = "-0600".parse::<CustomTimeZone>().unwrap();
time_zone.time_zone_id = mapper.as_borrowed().iana_to_bcp47("America/Chicago");
time_zone.maybe_calculate_metazone(&mzc, &datetime);
assert_try_writeable_eq!(
    tzf.format(&time_zone),
    "CT"
);

// "ushnl" - has time zone override symbol data for generic_non_location_short
let mut time_zone = "-1000".parse::<CustomTimeZone>().unwrap();
time_zone.time_zone_id = Some(TimeZoneBcp47Id(tinystr!(8, "ushnl")));
time_zone.maybe_calculate_metazone(&mzc, &datetime);
assert_try_writeable_eq!(
    tzf.format(&time_zone),
    "HST"
);

// Raw offset - used when metazone is not available
let mut time_zone = "+0530".parse::<CustomTimeZone>().unwrap();
assert_try_writeable_eq!(
    tzf.format(&time_zone),
    "GMT+05:30"
);

Structs§

  • A struct that supports formatting both a date and a time.
  • Struct representing the absence of a datetime formatting field.

Enums§

Traits§

Type Aliases§