Skip to content

Commit

Permalink
Time and DateTime to timezone component (#5961)
Browse files Browse the repository at this point in the history
Fixes #5859
  • Loading branch information
robertbastian authored Jan 14, 2025
1 parent 8046758 commit cc68692
Show file tree
Hide file tree
Showing 55 changed files with 764 additions and 726 deletions.
6 changes: 3 additions & 3 deletions components/calendar/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 0 additions & 15 deletions components/calendar/src/datetime.rs

This file was deleted.

164 changes: 1 addition & 163 deletions components/calendar/src/ixdtf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use core::str::FromStr;

use crate::{AnyCalendarKind, AsCalendar, Calendar, Date, DateTime, Iso, RangeError, Time};
use crate::{AnyCalendarKind, AsCalendar, Calendar, Date, Iso, RangeError};
use ixdtf::parsers::records::IxdtfParseRecord;
use ixdtf::parsers::IxdtfParser;
use ixdtf::ParseError as IxdtfError;
Expand Down Expand Up @@ -143,165 +143,3 @@ impl<A: AsCalendar> Date<A> {
Ok(date)
}
}

impl Time {
/// Creates a [`Time`] from an IXDTF syntax string of a time.
///
/// Does not support parsing an IXDTF string with a date and time; for that, use [`DateTime`].
///
/// ✨ *Enabled with the `ixdtf` Cargo feature.*
///
/// # Examples
///
/// ```
/// use icu::calendar::Time;
///
/// let time = Time::try_from_str("16:01:17.045").unwrap();
///
/// assert_eq!(time.hour.number(), 16);
/// assert_eq!(time.minute.number(), 1);
/// assert_eq!(time.second.number(), 17);
/// assert_eq!(time.nanosecond.number(), 45000000);
/// ```
pub fn try_from_str(ixdtf_str: &str) -> Result<Self, ParseError> {
Self::try_from_utf8(ixdtf_str.as_bytes())
}

/// Creates a [`Time`] in the ISO-8601 calendar from an IXDTF syntax string.
///
/// ✨ *Enabled with the `ixdtf` Cargo feature.*
///
/// See [`Self::try_from_str()`].
pub fn try_from_utf8(ixdtf_str: &[u8]) -> Result<Self, ParseError> {
let ixdtf_record = IxdtfParser::from_utf8(ixdtf_str).parse_time()?;
Self::try_from_ixdtf_record(&ixdtf_record)
}

fn try_from_ixdtf_record(ixdtf_record: &IxdtfParseRecord) -> Result<Self, ParseError> {
let time_record = ixdtf_record.time.ok_or(ParseError::MissingFields)?;
let time = Self::try_new(
time_record.hour,
time_record.minute,
time_record.second,
time_record.nanosecond,
)?;
Ok(time)
}
}

impl FromStr for Time {
type Err = ParseError;
fn from_str(ixdtf_str: &str) -> Result<Self, Self::Err> {
Self::try_from_str(ixdtf_str)
}
}

impl DateTime<Iso> {
/// Creates a [`DateTime`] in the ISO-8601 calendar from an IXDTF syntax string.
///
/// Ignores any calendar annotations in the string.
///
/// ✨ *Enabled with the `ixdtf` Cargo feature.*
///
/// # Examples
///
/// ```
/// use icu::calendar::DateTime;
///
/// let datetime =
/// DateTime::try_iso_from_str("2024-07-17T16:01:17.045").unwrap();
///
/// assert_eq!(datetime.date.year().era_year_or_extended(), 2024);
/// assert_eq!(
/// datetime.date.month().standard_code,
/// icu::calendar::types::MonthCode(tinystr::tinystr!(4, "M07"))
/// );
/// assert_eq!(datetime.date.day_of_month().0, 17);
///
/// assert_eq!(datetime.time.hour.number(), 16);
/// assert_eq!(datetime.time.minute.number(), 1);
/// assert_eq!(datetime.time.second.number(), 17);
/// assert_eq!(datetime.time.nanosecond.number(), 45000000);
/// ```
pub fn try_iso_from_str(ixdtf_str: &str) -> Result<Self, ParseError> {
Self::try_iso_from_utf8(ixdtf_str.as_bytes())
}

/// Creates a [`DateTime`] in the ISO-8601 calendar from an IXDTF syntax string.
///
/// ✨ *Enabled with the `ixdtf` Cargo feature.*
///
/// See [`Self::try_iso_from_str()`].
pub fn try_iso_from_utf8(ixdtf_str: &[u8]) -> Result<Self, ParseError> {
let ixdtf_record = IxdtfParser::from_utf8(ixdtf_str).parse()?;
Self::try_from_ixdtf_record(&ixdtf_record)
}

fn try_from_ixdtf_record(ixdtf_record: &IxdtfParseRecord) -> Result<Self, ParseError> {
let date = Date::<Iso>::try_from_ixdtf_record(ixdtf_record)?;
let time = Time::try_from_ixdtf_record(ixdtf_record)?;
Ok(Self { date, time })
}
}

impl FromStr for DateTime<Iso> {
type Err = ParseError;
fn from_str(ixdtf_str: &str) -> Result<Self, Self::Err> {
Self::try_iso_from_str(ixdtf_str)
}
}

impl<A: AsCalendar> DateTime<A> {
/// Creates a [`DateTime`] in any calendar from an IXDTF syntax string with compiled data.
///
/// # Examples
///
/// ```
/// use icu::calendar::cal::Hebrew;
/// use icu::calendar::DateTime;
///
/// let datetime =
/// DateTime::try_from_str("2024-07-17T16:01:17.045[u-ca=hebrew]", Hebrew).unwrap();
///
/// assert_eq!(datetime.date.year().era_year_or_extended(), 5784);
/// assert_eq!(
/// datetime.date.month().standard_code,
/// icu::calendar::types::MonthCode(tinystr::tinystr!(4, "M10"))
/// );
/// assert_eq!(datetime.date.day_of_month().0, 11);
///
/// assert_eq!(datetime.time.hour.number(), 16);
/// assert_eq!(datetime.time.minute.number(), 1);
/// assert_eq!(datetime.time.second.number(), 17);
/// assert_eq!(datetime.time.nanosecond.number(), 45000000);
/// ```
pub fn try_from_str(ixdtf_str: &str, calendar: A) -> Result<Self, ParseError> {
Self::try_from_utf8(ixdtf_str.as_bytes(), calendar)
}

/// Creates a [`DateTime`] in any calendar from an IXDTF syntax string with compiled data.
///
/// See [`Self::try_from_str()`].
pub fn try_from_utf8(ixdtf_str: &[u8], calendar: A) -> Result<Self, ParseError> {
let ixdtf_record = IxdtfParser::from_utf8(ixdtf_str).parse()?;
if let Some(ixdtf_calendar) = ixdtf_record.calendar {
let parsed_calendar = crate::AnyCalendarKind::get_for_bcp47_bytes(ixdtf_calendar)
.ok_or(ParseError::UnknownCalendar)?;
let expected_calendar = calendar
.as_calendar()
.any_calendar_kind()
.ok_or(ParseError::UnknownCalendar)?;
if parsed_calendar != expected_calendar {
return Err(ParseError::MismatchedCalendar(
expected_calendar,
parsed_calendar,
));
}
}
let DateTime { date, time } = DateTime::<Iso>::try_from_ixdtf_record(&ixdtf_record)?;
Ok(DateTime {
date: date.to_any().to_calendar(calendar),
time,
})
}
}
9 changes: 3 additions & 6 deletions components/calendar/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@
// called LICENSE at the top level of the ICU4X source tree
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).

//! Types for dealing with dates, times, and custom calendars.
//! Types for dealing with dates and custom calendars.
//!
//! This module is published as its own crate ([`icu_calendar`](https://docs.rs/icu_calendar/latest/icu_calendar/))
//! and as part of the [`icu`](https://docs.rs/icu/latest/icu/) crate. See the latter for more details on the ICU4X project.
//! The [`types`] module has a lot of common types for dealing with dates and times.
//! The [`types`] module has a lot of common types for dealing with dates.
//!
//! [`Calendar`] is a trait that allows one to define custom calendars, and [`Date`]
//! can represent dates for arbitrary calendars.
//!
//! The [`Iso`] and [`Gregorian`] types are implementations for the ISO and
//! Gregorian calendars respectively. Further calendars can be found in the [`cal`] module.
//!
//! Most interaction with this crate will be done via the [`Date`] and [`DateTime`] types.
//! Most interaction with this crate will be done via the [`Date`] type.
//!
//! Some of the algorithms implemented here are based on
//! Dershowitz, Nachum, and Edward M. Reingold. _Calendrical calculations_. Cambridge University Press, 2008.
Expand Down Expand Up @@ -93,7 +93,6 @@ extern crate alloc;

// Make sure inherent docs go first
mod date;
mod datetime;

/// Types for individual calendars
pub mod cal {
Expand Down Expand Up @@ -183,12 +182,10 @@ pub use crate::ixdtf::ParseError;
pub use any_calendar::{AnyCalendar, AnyCalendarKind, AnyCalendarPreferences};
pub use calendar::Calendar;
pub use date::{AsCalendar, Date, Ref};
pub use datetime::DateTime;
#[doc(hidden)] // unstable
pub use duration::{DateDuration, DateDurationUnit};
pub use error::{DateError, RangeError};
#[doc(no_inline)]
pub use gregorian::Gregorian;
#[doc(no_inline)]
pub use iso::Iso;
pub use types::Time;
Loading

0 comments on commit cc68692

Please sign in to comment.