Skip to content

Commit a5d9815

Browse files
authored
Add ZonedDateTime calendar accessor methods (#117)
This PR is dependent on #115 and will need a rebase once that PR is merged. This continues to build out methods that `ZonedDateTime` needs for accessor methods. Overall the features implemented are: - All calendar accessor methods - An implementation of `HoursInDay` method
1 parent e153634 commit a5d9815

File tree

3 files changed

+236
-2
lines changed

3 files changed

+236
-2
lines changed

Diff for: src/components/duration/normalized.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl NormalizedTimeDuration {
7474

7575
// TODO: Potentially, update divisor to u64?
7676
/// `Divide the NormalizedTimeDuraiton` by a divisor.
77-
pub(super) fn divide(&self, divisor: i64) -> i128 {
77+
pub(crate) fn divide(&self, divisor: i64) -> i128 {
7878
// TODO: Validate.
7979
self.0 / i128::from(divisor)
8080
}

Diff for: src/components/now.rs

+1
Original file line numberDiff line numberDiff line change
@@ -86,5 +86,6 @@ mod tests {
8686
// errors, we only assert a range.
8787
assert!(tolerable_range.contains(&diff.seconds().as_inner()));
8888
assert!(diff.hours().is_zero());
89+
assert!(diff.minutes().is_zero());
8990
}
9091
}

Diff for: src/components/zoneddatetime.rs

+234-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use tinystr::TinyAsciiStr;
88
use crate::{
99
components::{
1010
calendar::CalendarDateLike,
11+
duration::normalized::NormalizedTimeDuration,
1112
tz::{parse_offset, TzProvider},
1213
EpochNanoseconds,
1314
},
@@ -240,7 +241,7 @@ impl ZonedDateTime {
240241
}
241242
}
242243

243-
// ===== TzProvider APIs for ZonedDateTime =====
244+
// ===== Experimental TZ_PROVIDER accessor implementations =====
244245

245246
#[cfg(feature = "experimental")]
246247
impl ZonedDateTime {
@@ -314,7 +315,103 @@ impl ZonedDateTime {
314315

315316
self.millisecond_with_provider(provider.deref())
316317
}
318+
}
319+
320+
// ==== Experimental TZ_PROVIDER calendar method implementations ====
321+
322+
#[cfg(feature = "experimental")]
323+
impl ZonedDateTime {
324+
pub fn era(&self) -> TemporalResult<Option<TinyAsciiStr<16>>> {
325+
let provider = TZ_PROVIDER
326+
.lock()
327+
.map_err(|_| TemporalError::general("Unable to acquire lock"))?;
328+
self.era_with_provider(provider.deref())
329+
}
330+
331+
pub fn era_year(&self) -> TemporalResult<Option<i32>> {
332+
let provider = TZ_PROVIDER
333+
.lock()
334+
.map_err(|_| TemporalError::general("Unable to acquire lock"))?;
335+
self.era_year_with_provider(provider.deref())
336+
}
337+
338+
/// Returns the calendar day of week value.
339+
pub fn day_of_week(&self) -> TemporalResult<u16> {
340+
let provider = TZ_PROVIDER
341+
.lock()
342+
.map_err(|_| TemporalError::general("Unable to acquire lock"))?;
343+
self.day_of_week_with_provider(provider.deref())
344+
}
345+
346+
/// Returns the calendar day of year value.
347+
pub fn day_of_year(&self) -> TemporalResult<u16> {
348+
let provider = TZ_PROVIDER
349+
.lock()
350+
.map_err(|_| TemporalError::general("Unable to acquire lock"))?;
351+
self.day_of_year_with_provider(provider.deref())
352+
}
353+
354+
/// Returns the calendar week of year value.
355+
pub fn week_of_year(&self) -> TemporalResult<Option<u16>> {
356+
let provider = TZ_PROVIDER
357+
.lock()
358+
.map_err(|_| TemporalError::general("Unable to acquire lock"))?;
359+
self.week_of_year_with_provider(provider.deref())
360+
}
361+
362+
/// Returns the calendar year of week value.
363+
pub fn year_of_week(&self) -> TemporalResult<Option<i32>> {
364+
let provider = TZ_PROVIDER
365+
.lock()
366+
.map_err(|_| TemporalError::general("Unable to acquire lock"))?;
367+
self.year_of_week_with_provider(provider.deref())
368+
}
369+
370+
/// Returns the calendar days in week value.
371+
pub fn days_in_week(&self) -> TemporalResult<u16> {
372+
let provider = TZ_PROVIDER
373+
.lock()
374+
.map_err(|_| TemporalError::general("Unable to acquire lock"))?;
375+
self.days_in_week_with_provider(provider.deref())
376+
}
377+
378+
/// Returns the calendar days in month value.
379+
pub fn days_in_month(&self) -> TemporalResult<u16> {
380+
let provider = TZ_PROVIDER
381+
.lock()
382+
.map_err(|_| TemporalError::general("Unable to acquire lock"))?;
383+
self.days_in_month_with_provider(provider.deref())
384+
}
385+
386+
/// Returns the calendar days in year value.
387+
pub fn days_in_year(&self) -> TemporalResult<u16> {
388+
let provider = TZ_PROVIDER
389+
.lock()
390+
.map_err(|_| TemporalError::general("Unable to acquire lock"))?;
391+
self.days_in_year_with_provider(provider.deref())
392+
}
393+
394+
/// Returns the calendar months in year value.
395+
pub fn months_in_year(&self) -> TemporalResult<u16> {
396+
let provider = TZ_PROVIDER
397+
.lock()
398+
.map_err(|_| TemporalError::general("Unable to acquire lock"))?;
399+
self.months_in_year_with_provider(provider.deref())
400+
}
401+
402+
/// Returns returns whether the date in a leap year for the given calendar.
403+
pub fn in_leap_year(&self) -> TemporalResult<bool> {
404+
let provider = TZ_PROVIDER
405+
.lock()
406+
.map_err(|_| TemporalError::general("Unable to acquire lock"))?;
407+
self.in_leap_year_with_provider(provider.deref())
408+
}
409+
}
410+
411+
// ==== Experimental TZ_PROVIDER method implementations ====
317412

413+
#[cfg(feature = "experimental")]
414+
impl ZonedDateTime {
318415
pub fn add(
319416
&self,
320417
duration: &Duration,
@@ -358,6 +455,40 @@ impl ZonedDateTime {
358455
}
359456
}
360457

458+
// ==== HoursInDay accessor method implementation ====
459+
460+
impl ZonedDateTime {
461+
#[cfg(feature = "experimental")]
462+
pub fn hours_in_day(&self) -> TemporalResult<u8> {
463+
let provider = TZ_PROVIDER
464+
.lock()
465+
.map_err(|_| TemporalError::general("Unable to acquire lock"))?;
466+
self.hours_in_day_with_provider(provider.deref())
467+
}
468+
469+
pub fn hours_in_day_with_provider(&self, provider: &impl TzProvider) -> TemporalResult<u8> {
470+
// 1-3. Is engine specific steps
471+
// 4. Let isoDateTime be GetISODateTimeFor(timeZone, zonedDateTime.[[EpochNanoseconds]]).
472+
let iso = self.tz.get_iso_datetime_for(&self.instant, provider)?;
473+
// 5. Let today be isoDateTime.[[ISODate]].
474+
let today = iso.date;
475+
// 6. Let tomorrow be BalanceISODate(today.[[Year]], today.[[Month]], today.[[Day]] + 1).
476+
let tomorrow = IsoDate::balance(today.year, today.month.into(), i32::from(today.day + 1));
477+
// 7. Let todayNs be ? GetStartOfDay(timeZone, today).
478+
let today_ns = self.tz.get_start_of_day(&today, provider)?;
479+
// 8. Let tomorrowNs be ? GetStartOfDay(timeZone, tomorrow).
480+
let tomorrow_ns = self.tz.get_start_of_day(&tomorrow, provider)?;
481+
// 9. Let diff be TimeDurationFromEpochNanosecondsDifference(tomorrowNs, todayNs).
482+
let diff = NormalizedTimeDuration::from_nanosecond_difference(tomorrow_ns.0, today_ns.0)?;
483+
// NOTE: The below should be safe as today_ns and tomorrow_ns should be at most 25 hours.
484+
// TODO: Tests for the below cast.
485+
// 10. Return 𝔽(TotalTimeDuration(diff, hour)).
486+
Ok(diff.divide(60_000_000_000) as u8)
487+
}
488+
}
489+
490+
// ==== Core accessor methods ====
491+
361492
impl ZonedDateTime {
362493
/// Returns the `year` value for this `ZonedDateTime`.
363494
#[inline]
@@ -426,7 +557,109 @@ impl ZonedDateTime {
426557
let iso = self.tz.get_iso_datetime_for(&self.instant, provider)?;
427558
Ok(iso.time.nanosecond)
428559
}
560+
}
561+
562+
// ==== Core calendar method implementations ====
429563

564+
impl ZonedDateTime {
565+
pub fn era_with_provider(
566+
&self,
567+
provider: &impl TzProvider,
568+
) -> TemporalResult<Option<TinyAsciiStr<16>>> {
569+
let iso = self.tz.get_iso_datetime_for(&self.instant, provider)?;
570+
let pdt = PlainDateTime::new_unchecked(iso, self.calendar.clone());
571+
self.calendar.era(&CalendarDateLike::DateTime(&pdt))
572+
}
573+
574+
pub fn era_year_with_provider(
575+
&self,
576+
provider: &impl TzProvider,
577+
) -> TemporalResult<Option<i32>> {
578+
let iso = self.tz.get_iso_datetime_for(&self.instant, provider)?;
579+
let pdt = PlainDateTime::new_unchecked(iso, self.calendar.clone());
580+
self.calendar.era_year(&CalendarDateLike::DateTime(&pdt))
581+
}
582+
583+
/// Returns the calendar day of week value.
584+
pub fn day_of_week_with_provider(&self, provider: &impl TzProvider) -> TemporalResult<u16> {
585+
let iso = self.tz.get_iso_datetime_for(&self.instant, provider)?;
586+
let pdt = PlainDateTime::new_unchecked(iso, self.calendar.clone());
587+
self.calendar.day_of_week(&CalendarDateLike::DateTime(&pdt))
588+
}
589+
590+
/// Returns the calendar day of year value.
591+
pub fn day_of_year_with_provider(&self, provider: &impl TzProvider) -> TemporalResult<u16> {
592+
let iso = self.tz.get_iso_datetime_for(&self.instant, provider)?;
593+
let pdt = PlainDateTime::new_unchecked(iso, self.calendar.clone());
594+
self.calendar.day_of_year(&CalendarDateLike::DateTime(&pdt))
595+
}
596+
597+
/// Returns the calendar week of year value.
598+
pub fn week_of_year_with_provider(
599+
&self,
600+
provider: &impl TzProvider,
601+
) -> TemporalResult<Option<u16>> {
602+
let iso = self.tz.get_iso_datetime_for(&self.instant, provider)?;
603+
let pdt = PlainDateTime::new_unchecked(iso, self.calendar.clone());
604+
self.calendar
605+
.week_of_year(&CalendarDateLike::DateTime(&pdt))
606+
}
607+
608+
/// Returns the calendar year of week value.
609+
pub fn year_of_week_with_provider(
610+
&self,
611+
provider: &impl TzProvider,
612+
) -> TemporalResult<Option<i32>> {
613+
let iso = self.tz.get_iso_datetime_for(&self.instant, provider)?;
614+
let pdt = PlainDateTime::new_unchecked(iso, self.calendar.clone());
615+
self.calendar
616+
.year_of_week(&CalendarDateLike::DateTime(&pdt))
617+
}
618+
619+
/// Returns the calendar days in week value.
620+
pub fn days_in_week_with_provider(&self, provider: &impl TzProvider) -> TemporalResult<u16> {
621+
let iso = self.tz.get_iso_datetime_for(&self.instant, provider)?;
622+
let pdt = PlainDateTime::new_unchecked(iso, self.calendar.clone());
623+
self.calendar
624+
.days_in_week(&CalendarDateLike::DateTime(&pdt))
625+
}
626+
627+
/// Returns the calendar days in month value.
628+
pub fn days_in_month_with_provider(&self, provider: &impl TzProvider) -> TemporalResult<u16> {
629+
let iso = self.tz.get_iso_datetime_for(&self.instant, provider)?;
630+
let pdt = PlainDateTime::new_unchecked(iso, self.calendar.clone());
631+
self.calendar
632+
.days_in_month(&CalendarDateLike::DateTime(&pdt))
633+
}
634+
635+
/// Returns the calendar days in year value.
636+
pub fn days_in_year_with_provider(&self, provider: &impl TzProvider) -> TemporalResult<u16> {
637+
let iso = self.tz.get_iso_datetime_for(&self.instant, provider)?;
638+
let pdt = PlainDateTime::new_unchecked(iso, self.calendar.clone());
639+
self.calendar
640+
.days_in_year(&CalendarDateLike::DateTime(&pdt))
641+
}
642+
643+
/// Returns the calendar months in year value.
644+
pub fn months_in_year_with_provider(&self, provider: &impl TzProvider) -> TemporalResult<u16> {
645+
let iso = self.tz.get_iso_datetime_for(&self.instant, provider)?;
646+
let pdt = PlainDateTime::new_unchecked(iso, self.calendar.clone());
647+
self.calendar
648+
.months_in_year(&CalendarDateLike::DateTime(&pdt))
649+
}
650+
651+
/// Returns returns whether the date in a leap year for the given calendar.
652+
pub fn in_leap_year_with_provider(&self, provider: &impl TzProvider) -> TemporalResult<bool> {
653+
let iso = self.tz.get_iso_datetime_for(&self.instant, provider)?;
654+
let pdt = PlainDateTime::new_unchecked(iso, self.calendar.clone());
655+
self.calendar
656+
.in_leap_year(&CalendarDateLike::DateTime(&pdt))
657+
}
658+
}
659+
660+
// ==== Core method implementations ====
661+
662+
impl ZonedDateTime {
430663
pub fn add_with_provider(
431664
&self,
432665
duration: &Duration,

0 commit comments

Comments
 (0)