Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Temporal duration compare #186

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

sffc
Copy link

@sffc sffc commented Jan 27, 2025

Fixes #154

Wrote this along with @lockels, @Neelzee, @sebastianjacmatt, @Magnus-Fjeldstad, @HenrikTennebekk.

Please see question regarding the return type of DateDurationDays.

Copy link
Member

@nekevss nekevss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for contributing! This is looking really great overall!


/// DateDurationDays
/// TODO(review): Question: what the correct return type?
pub fn days(&self, relative_to: &PlainDate) -> TemporalResult<i64> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: What the return type should be here is a good question. Based off the specification, DateDurationDays is an abstract op that is only called in Temporal.Duration.compare. Given that context, my immediate reaction would be that this method should be pub(crate) (unless there is an argument for an abstract operation being public immediatley) and return TemporalResult<i64>.

This is slightly related to a long running question, I've had about whether temporal_rs would be able to move to a Duration using integers vs. floating points. But I haven't had the time to sit down and audit the spec to confirm.

@@ -572,6 +631,7 @@ impl Duration {
self.weeks(),
self.days().checked_add(&FiniteF64::from(balanced_days))?,
)?;
// TODO: Should this be using AdjustDateDurationRecord?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! This implementation is from before some of the more recent specification changes. There's a good argument to be made that round should be updated to take advantage of the methods implemented in this PR.

That may be best scoped to another PR as that may include a a couple more changes in the code then specifically in round. I'll leave that up to you.

Some(ArithmeticOverflow::Constrain),
)?;
// 4. Let epochDays1 be ISODateToEpochDays(plainRelativeTo.[[ISODate]].[[Year]], plainRelativeTo.[[ISODate]].[[Month]] - 1, plainRelativeTo.[[ISODate]].[[Day]]).
let epoch_days_1 = iso_date_to_epoch_days(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: iso_date_to_epoch_days deviates from the specification here and takes an exact month vs. month - 1

This is sort of a mea culpa, I should have documented this change better (and thought that I had!). We don't have to subtract 1 from month here because the neri-schneider calculations take the month exactly vs month - 1. For reference, here are the tests.

@@ -66,6 +66,7 @@ impl NormalizedTimeDuration {

// NOTE: `days: f64` should be an integer -> `i64`.
/// Equivalent: 7.5.23 Add24HourDaysToNormalizedTimeDuration ( d, days )
/// Add24HourDaysToTimeDuration??
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: looks like the abstract op name changed in the docs. This can be updated.

///
/// `7.2.3 Temporal.Duration.compare ( one, two [ , options ] )`
#[must_use]
pub fn compare(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: Should compare take &self for the first Duration parameter or mimic the specification and have it be a standalone function on Duration?

This is more a question of what is the best way to translate compare in Rust vs. JavaScript. In the literal sense to the specification, this is implemented exactly as it should be. But in Rust where PartialOrd exists as a trait, it's common to have one.cmp(&two) conceptually. So is it best for this to be a method similar to PartialOrd, e.g. one.compare(&two, None)??

I've tended to prefer this approach, mostly, because I think it's nice to adhere to similarly structured syntax. But I could be convinced to this current implementation if others think it's bad to overload the concept of one.cmp(&two). The most important thing to be consistent across similar methods and functions in temporal_rs for the builtins.

@@ -77,7 +77,7 @@ impl PartialDuration {
/// `Duration` is made up of a `DateDuration` and `TimeDuration` as primarily
/// defined by Abtract Operation 7.5.1-5.
#[non_exhaustive]
#[derive(Debug, Clone, Copy, Default)]
#[derive(Debug, Clone, Copy, Default, PartialEq, PartialOrd)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: Duration should not implement PartialOrd and potentially not PartialEq.

The compare method supersedes the cmp impl from PartialOrd, implementing them both could lead to confusion. PartialEq is not necessarily needed by the specification. It doesn't define an equals method on Duration, but PartialEq is incredibly useful for testing purposes.

// e. If after1 > after2, return 1𝔽.
// f. If after1 < after2, return -1𝔽.
// g. Return +0𝔽.
return Ok(after1.cmp(&after2));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: this will probably need to be updated on a rebase / merge to main due to #175.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

/// AdjustDateDurationRecord
pub fn adjust(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: pub(crate)

Since this is an abstract op, it would be best to keep these pub(crate) until otherwise needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement compare method for Duration
4 participants