Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion crates/temporal/src/builtins/compiled/zoned_date_time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,11 +214,27 @@ impl ZonedDateTime {
) -> TemporalResult<Self> {
ZonedDateTime::from_utf8_with_provider(source, disambiguation, offset_option, &*TZ_PROVIDER)
}

/// Attempts to parse and create a `ZonedDateTime` from a UTF-16 encoded IXDTF string.
///
/// Enable with the `compiled_data` feature flag.
pub fn from_utf16(
source: &[u16],
disambiguation: Disambiguation,
offset_option: OffsetDisambiguation,
) -> TemporalResult<Self> {
ZonedDateTime::from_utf16_with_provider(
source,
disambiguation,
offset_option,
&*TZ_PROVIDER,
)
}
/// Attempts to parse and create a `ZonedDateTime` from an IXDTF formatted [`&str`].
///
/// Enable with the `compiled_data` feature flag.
pub fn from_parsed(
parsed: crate::parsed_intermediates::ParsedZonedDateTime,
parsed: crate::parsers::intermediates::ParsedZonedDateTime,
disambiguation: Disambiguation,
offset_option: OffsetDisambiguation,
) -> TemporalResult<Self> {
Expand Down
27 changes: 21 additions & 6 deletions crates/temporal/src/builtins/core/calendar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
error::ErrorMessage,
iso::IsoDate,
options::{Overflow, Unit},
parsers::parse_allowed_calendar_formats,
parsers::TemporalEncoding,
TemporalError, TemporalResult,
};
use core::str::FromStr;
Expand Down Expand Up @@ -179,6 +179,12 @@ impl Calendar {
Ok(Self::new(kind))
}

/// Returns a `Calendar` from a slice of UTF-16 encoded code units.
pub fn try_from_utf16(code_units: &[u16]) -> TemporalResult<Self> {
let ascii = crate::parsers::Utf16::ascii_identifier(code_units)?;
Self::try_from_utf8(&ascii)
}

/// Returns a `Calendar` from the a slice of UTF-8 encoded bytes.
pub(crate) fn try_kind_from_utf8(bytes: &[u8]) -> TemporalResult<AnyCalendarKind> {
// TODO: Determine the best way to handle "julian" here.
Expand Down Expand Up @@ -207,11 +213,7 @@ impl FromStr for Calendar {

// 13.34 ParseTemporalCalendarString ( string )
fn from_str(s: &str) -> Result<Self, Self::Err> {
match parse_allowed_calendar_formats(s.as_bytes()) {
Some([]) => Ok(Calendar::ISO),
Some(result) => Calendar::try_from_utf8(result),
None => Calendar::try_from_utf8(s.as_bytes()),
}
crate::parsers::TemporalParser::from_utf8(s.as_bytes()).parse_calendar()
}
}

Expand Down Expand Up @@ -795,6 +797,19 @@ mod tests {
let _err = Calendar::from_str(cal_str).unwrap_err();
}

#[test]
fn try_from_utf16_multi_segment_id() {
// Regression test: `islamic-umalqura` is two dash-joined BCP-47 subtags
// and exceeds the 8-ASCII-char bound of a single subtag.
let cal_str = "islamic-umalqura";
let utf16: alloc::vec::Vec<u16> = cal_str.encode_utf16().collect();
assert_eq!(
Calendar::try_from_utf8(cal_str.as_bytes()),
Calendar::try_from_utf16(&utf16)
);
assert!(Calendar::try_from_utf16(&utf16).is_ok());
}

#[test]
fn date_until_largest_year() {
// tests format: (Date one, PlainDate two, Duration result)
Expand Down
16 changes: 14 additions & 2 deletions crates/temporal/src/builtins/core/duration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{
Overflow, RelativeTo, ResolvedRoundingOptions, RoundingIncrement, RoundingOptions,
ToStringRoundingOptions, Unit, UnitGroup,
},
parsers::TemporalParser,
parsers::{FormattableDateDuration, FormattableDuration, FormattableTimeDuration, Precision},
primitive::FiniteF64,
provider::TimeZoneProvider,
Expand All @@ -16,7 +17,9 @@ use crate::{
use alloc::string::String;
use core::{cmp::Ordering, str::FromStr};
use ixdtf::{
encoding::Utf8, parsers::IsoDurationParser, records::Fraction, records::TimeDurationRecord,
encoding::{Utf16, Utf8},
records::Fraction,
records::TimeDurationRecord,
};
use normalized::InternalDurationRecord;
use num_traits::Euclid;
Expand Down Expand Up @@ -714,8 +717,17 @@ impl Duration {

// Converts a UTF-8 encoded string into a `Duration`.
pub fn from_utf8(s: &[u8]) -> TemporalResult<Self> {
let parse_record = IsoDurationParser::<Utf8>::from_utf8(s).parse()?;
TemporalParser::<Utf8>::from_utf8(s).parse_duration()
}

/// Converts a UTF-16 encoded string into a `Duration`.
pub fn from_utf16(s: &[u16]) -> TemporalResult<Self> {
TemporalParser::<Utf16>::from_utf16(s).parse_duration()
}

pub(crate) fn from_duration_record(
parse_record: ixdtf::records::DurationParseRecord,
) -> TemporalResult<Self> {
fn fraction_to_unadjusted_ns(fraction: Option<Fraction>) -> Result<u32, TemporalError> {
if let Some(fraction) = fraction {
fraction.to_nanoseconds().ok_or(
Expand Down
23 changes: 21 additions & 2 deletions crates/temporal/src/builtins/core/instant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
DifferenceOperation, DifferenceSettings, DisplayOffset, ResolvedRoundingOptions,
RoundingOptions, ToStringRoundingOptions, Unit, UnitGroup,
},
parsers::{parse_instant, IxdtfStringBuilder},
parsers::IxdtfStringBuilder,
provider::TimeZoneProvider,
rounding::IncrementRounder,
unix_time::EpochNanoseconds,
Expand Down Expand Up @@ -296,8 +296,17 @@ impl Instant {

// Converts a UTF-8 encoded string into a `Instant`.
pub fn from_utf8(s: &[u8]) -> TemporalResult<Self> {
let ixdtf_record = parse_instant(s)?;
crate::parsers::TemporalParser::from_utf8(s).parse_instant()
}

/// Converts a UTF-16 encoded string into a `Instant`.
pub fn from_utf16(s: &[u16]) -> TemporalResult<Self> {
crate::parsers::TemporalParser::from_utf16(s).parse_instant()
}

pub(crate) fn from_parsed_record(
ixdtf_record: crate::parsers::ParsedInstantRecord,
) -> TemporalResult<Self> {
// Find the offset
let ns_offset = match ixdtf_record.offset {
UtcOffsetRecordOrZ::Offset(offset) => {
Expand Down Expand Up @@ -505,6 +514,16 @@ mod tests {
assert!(Instant::try_new(min_minus_one).is_err());
}

#[test]
fn from_utf16_matches_from_utf8() {
let s = "2024-07-19T15:43:12.5Z";
let utf16: alloc::vec::Vec<u16> = s.encode_utf16().collect();
assert_eq!(
Instant::from_utf8(s.as_bytes()),
Instant::from_utf16(&utf16)
);
}

#[test]
fn max_min_epoch_millseconds() {
// Assert the casting is valid.
Expand Down
19 changes: 18 additions & 1 deletion crates/temporal/src/builtins/core/plain_date.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! This module implements `PlainDate` and any directly related algorithms.

use crate::error::ErrorMessage;
use crate::parsed_intermediates::ParsedDate;
use crate::parsers::intermediates::ParsedDate;
use crate::{
builtins::{
calendar::{CalendarFields, YearMonthCalendarFields},
Expand Down Expand Up @@ -426,6 +426,13 @@ impl PlainDate {
Self::from_parsed(parsed)
}

/// Converts a UTF-16 encoded string into a `PlainDate`.
pub fn from_utf16(s: &[u16]) -> TemporalResult<Self> {
let parsed = ParsedDate::from_utf16(s)?;

Self::from_parsed(parsed)
}

/// Creates a `PlainDate` from a [`ParsedDate`].
pub fn from_parsed(parsed: ParsedDate) -> TemporalResult<Self> {
Self::try_new(
Expand Down Expand Up @@ -757,6 +764,16 @@ mod tests {
);
}

#[test]
fn from_utf16_matches_from_utf8() {
let s = "2024-07-19[u-ca=hebrew]";
let utf16: alloc::vec::Vec<u16> = s.encode_utf16().collect();
assert_eq!(
PlainDate::from_utf8(s.as_bytes()),
PlainDate::from_utf16(&utf16)
);
}

#[test]
fn simple_date_add() {
let base = PlainDate::from_str("1976-11-18").unwrap();
Expand Down
8 changes: 7 additions & 1 deletion crates/temporal/src/builtins/core/plain_date_time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use super::{
ZonedDateTime,
};
use crate::error::ErrorMessage;
use crate::parsed_intermediates::ParsedDateTime;
use crate::parsers::intermediates::ParsedDateTime;
use crate::{
builtins::{
calendar::CalendarFields,
Expand Down Expand Up @@ -597,6 +597,12 @@ impl PlainDateTime {
Self::from_parsed(parsed)
}

/// Converts a UTF-16 encoded string into a `PlainDateTime`.
pub fn from_utf16(s: &[u16]) -> TemporalResult<Self> {
let parsed = ParsedDateTime::from_utf16(s)?;
Self::from_parsed(parsed)
}

pub fn from_parsed(parsed: ParsedDateTime) -> TemporalResult<Self> {
let date = IsoDate::new_with_overflow(
parsed.date.record.year,
Expand Down
11 changes: 9 additions & 2 deletions crates/temporal/src/builtins/core/plain_month_day.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ use crate::{
error::ErrorMessage,
iso::{IsoDate, IsoDateTime, IsoTime},
options::{Disambiguation, DisplayCalendar, Overflow},
parsed_intermediates::ParsedDate,
parsers::{FormattableCalendar, FormattableDate, FormattableMonthDay},
parsers::{
intermediates::ParsedDate, FormattableCalendar, FormattableDate, FormattableMonthDay,
},
provider::TimeZoneProvider,
unix_time::EpochNanoseconds,
Calendar, MonthCode, TemporalError, TemporalResult, TimeZone,
Expand Down Expand Up @@ -215,6 +216,12 @@ impl PlainMonthDay {
Self::from_parsed(parsed)
}

/// Converts a UTF-16 encoded string into a `PlainMonthDay`.
pub fn from_utf16(s: &[u16]) -> TemporalResult<Self> {
let parsed = ParsedDate::month_day_from_utf16(s)?;
Self::from_parsed(parsed)
}

// Converts a ParsedDate into a `PlainMonthDay`.
//
// Be sure to parse this using [`ParsedDate::month_day_from_utf8()`]~
Expand Down
11 changes: 7 additions & 4 deletions crates/temporal/src/builtins/core/plain_time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::{
DifferenceOperation, DifferenceSettings, Overflow, ResolvedRoundingOptions,
RoundingOptions, ToStringRoundingOptions, Unit, UnitGroup,
},
parsers::{parse_time, IxdtfStringBuilder},
parsers::IxdtfStringBuilder,
unix_time::EpochNanoseconds,
TemporalError, TemporalResult,
};
Expand Down Expand Up @@ -410,9 +410,12 @@ impl PlainTime {

// Converts a UTF-8 encoded string into a `PlainTime`.
pub fn from_utf8(s: &[u8]) -> TemporalResult<Self> {
let result = parse_time(s)?;
let iso = IsoTime::from_time_record(result)?;
Ok(Self::new_unchecked(iso))
crate::parsers::TemporalParser::from_utf8(s).parse_time()
}

/// Converts a UTF-16 encoded string into a `PlainTime`.
pub fn from_utf16(s: &[u16]) -> TemporalResult<Self> {
crate::parsers::TemporalParser::from_utf16(s).parse_time()
}

/// Creates a new `PlainTime` using the current `PlainTime` fields as a fallback.
Expand Down
11 changes: 9 additions & 2 deletions crates/temporal/src/builtins/core/plain_year_month.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ use crate::{
DifferenceOperation, DifferenceSettings, Disambiguation, DisplayCalendar, Overflow,
ResolvedRoundingOptions, RoundingIncrement, Unit, UnitGroup,
},
parsed_intermediates::ParsedDate,
parsers::{FormattableCalendar, FormattableDate, FormattableYearMonth},
parsers::{
intermediates::ParsedDate, FormattableCalendar, FormattableDate, FormattableYearMonth,
},
provider::{NeverProvider, TimeZoneProvider},
unix_time::EpochNanoseconds,
Calendar, MonthCode, TemporalError, TemporalResult, TimeZone,
Expand Down Expand Up @@ -419,6 +420,12 @@ impl PlainYearMonth {
Self::from_parsed(parsed)
}

/// Converts a UTF-16 encoded string into a `PlainYearMonth`.
pub fn from_utf16(s: &[u16]) -> TemporalResult<Self> {
let parsed = ParsedDate::year_month_from_utf16(s)?;
Self::from_parsed(parsed)
}

/// Converts a ParsedDate into a `PlainYearMonth`.
///
/// Be sure to parse this using [`ParsedDate::year_month_from_utf8()`]~
Expand Down
Loading
Loading