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

fix: equivalent negative durations add to the same time #43795

Merged
merged 3 commits into from Dec 10, 2021

Conversation

cpb
Copy link
Contributor

@cpb cpb commented Dec 7, 2021

Summary

Modulo does not work as needed for negative numbers. (thanks @bradenchime for digging into that).

This PR avoids sending negative values into the modulo based parts calculating algorithm of ActiveSupport::Duration.build

Context

I want to help the next person who attempts to use ActiveSupport::Duration.build and has negative numbers slip into there in their use case.

This PR makes ActiveSupport::Duration.build(-1) not only == -ActiveSupport::Duration.build(1) but also results in the same Time when added.

I've noticed, in the closed Issues related to ActiveSupport::Duration that there is counter intuitive behaviour associated with duration math. However, because -1.second or even ActiveSupport::Duration::Scalar.new(-1) modifies Time as I expected ActiveSupport::Duration.build(-1) to, I thought: perhaps this is unexpected behaviour.

Alternatives

If it is decided to not change the behaviour of ActiveSupport::Duration.build(-1) then I humbly propose changing my last assert_equal to refute_equal and adding (at least) documentation to ActiveSupport::Duration.build that it is not expected to work with negative values, and to use Numeric#second or ActiveSupport::Duration::Scalar (for example) instead.

Observed Error Rate

This is a single sample of the slippage or error rate in the modification of Time with a ActiveSupport::Duration.build with a negative value. When I complete collecting the data for the range of whole numbers in a year, I'll be able to share a chart that illustrates the range of errors.

This will ultimately be a graph of the errors introduced in the algorithm by taking a modulo of a negative number.

time = Time.now

a = time + ActiveSupport::Duration.build(-1)
b = time + -ActiveSupport::Duration.build(1)

ActiveSupport::Duration.build((a-b).abs) # => `10 hours, 29 minutes, and 6.0 seconds`

@cpb cpb force-pushed the fix-negative-durations branch 3 times, most recently from 38e7c1d to 4326b10 Compare December 8, 2021 04:50
@cpb
Copy link
Contributor Author

cpb commented Dec 8, 2021

If buildkite is able to reproduce the test failure on:

assert_equal expected_time, time + ActiveSupport::Duration.build(-1)

I'll add cpb@f12a0fa which provides a fix.

@cpb
Copy link
Contributor Author

cpb commented Dec 8, 2021

If buildkite is able to reproduce the test failure on:

assert_equal expected_time, time + ActiveSupport::Duration.build(-1)

I'll add cpb@f12a0fa which provides a fix.

activesupport (2.5)
activesupport (2.6)
activesupport (2.7)
activesupport (3.0)

@cpb
Copy link
Contributor Author

cpb commented Dec 8, 2021

@rafaelfranca
Copy link
Member

Instead of calling build again, can we doing the same as #43809?

@bradenchime
Copy link

For reference @rafaelfranca #43809 was put up to place-hold an alternative option for fix. Given the preference for that approach @cpb has kindly brought that work over into this PR.

I will close #43809 now.

@cpb
Copy link
Contributor Author

cpb commented Dec 9, 2021

@cpb
Copy link
Contributor Author

cpb commented Dec 9, 2021

Let me know if you want one for main -- I'm improvising here, dunno if I'm getting ahead of myself.

@ghiculescu
Copy link
Member

All PRs should target main, then can be backported to old versions as appropriate. Could you update this one to target main?

@cpb
Copy link
Contributor Author

cpb commented Dec 9, 2021

Yes! Thanks for that clarification 😊

cpb and others added 2 commits December 8, 2021 19:02
Co-authored-by: Caleb <me@cpb.ca>
Co-authored-by: Braden Staudacher <braden.staudacher@chime.com>
@cpb
Copy link
Contributor Author

cpb commented Dec 9, 2021

@ghiculescu updated to main, renamed other PR's for backporting. Or, should I close them?

#43815

#43814

@ghiculescu
Copy link
Member

I think just close them. Core team will decide on backports when they review this one.

@ghiculescu
Copy link
Member

I think this needs a CHANGELOG entry too.

@cpb
Copy link
Contributor Author

cpb commented Dec 9, 2021

@ghiculescu Done! 🙌

@rafaelfranca rafaelfranca merged commit ffc1e5f into rails:main Dec 10, 2021
rafaelfranca added a commit that referenced this pull request Dec 10, 2021
* bug: illustrate negative durations don't add to the same time

* fix: equivalent negative durations add to the same time

Co-authored-by: Caleb <me@cpb.ca>
Co-authored-by: Braden Staudacher <braden.staudacher@chime.com>

* Updates CHANGELOG with fix to `ActiveSupport::Duration.build`

Co-authored-by: Rafael Mendonça França <rafael@rubyonrails.org>
rafaelfranca added a commit that referenced this pull request Dec 10, 2021
* bug: illustrate negative durations don't add to the same time

* fix: equivalent negative durations add to the same time

Co-authored-by: Caleb <me@cpb.ca>
Co-authored-by: Braden Staudacher <braden.staudacher@chime.com>

* Updates CHANGELOG with fix to `ActiveSupport::Duration.build`

Co-authored-by: Rafael Mendonça França <rafael@rubyonrails.org>
@cpb cpb deleted the fix-negative-durations branch December 11, 2021 21:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants