Skip to content

gh-99772: Do not ignore utc offset microseconds - #99774

Closed
blenq wants to merge 3 commits into
python:mainfrom
blenq:fix-issue-99772
Closed

gh-99772: Do not ignore utc offset microseconds#99774
blenq wants to merge 3 commits into
python:mainfrom
blenq:fix-issue-99772

Conversation

@blenq

@blenq blenq commented Nov 25, 2022

Copy link
Copy Markdown

Fixes the compare operations for datetime.time values with microseconds in the utc offset.

@bedevere-bot

Copy link
Copy Markdown

Most changes to Python require a NEWS entry.

Please add it using the blurb_it web app or the blurb command-line tool.

@ghost

ghost commented Nov 25, 2022

Copy link
Copy Markdown

All commit authors signed the Contributor License Agreement.
CLA signed

@Jason-Y-Z Jason-Y-Z left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for your contributions. Please see comments inline.

for op in lt, le, gt, ge, eq, ne:
got = op(x, y)
expected = op(
-x.utcoffset().microseconds,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why do we need the minus sign here?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Because the utc offset contributes to the time in a negative way, in other words, the greater the utc offset, the earlier the actual time.

Comment thread Modules/_datetimemodule.c
/* The hard case: both aware with different UTC offsets */
else if (offset1 != Py_None && offset2 != Py_None) {
int offsecs1, offsecs2;
int64_t offusecs1, offusecs2, diff64;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This might be a minor discussion point, but we could avoid using int64_t and the following big-integer calculations by doing a multi-step comparison, i.e. comparing the hours, then minutes, then seconds etc.
The motivation for this is a bit of gut feeling, but I think that way will be slightly more efficient in terms of time and space.

@blenq blenq Nov 27, 2022

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I actually implemented it like you suggest earlier, because I share your gut feeling. Using the existing code for checks up to seconds and adjusting only the microseconds check. Indeed with the advantage that it all fits in 32 bits.

What I encountered using this approach was the following: 13:59:59.9+02 is actually later than 14:00:00+02:00:00.9. The combined microseconds values, in the time values and the offsets, can contribute up to a maximum of 1.999998 seconds to the diff in either way. That means that the simple intermediary check that is used in other multi step comparisons if (diff == 0) can not be used. It should become if (diff > -2 && diff < 2). I chose to go for the int64_t approach because I thought it to be less confusing, than the 2 seconds intermediary check, but I am perfectly willing to go with your suggestion, if that is the consensus.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@blenq Does one of the tests already handle the use case of 13:59:59.9+02 vs. 14:00:00+02:00:00.9? If not we should add that as a test case.

@brandonschabell

Copy link
Copy Markdown
Contributor

I'm going to move my conversation here for visibility.

You are right if you only take current timezones into consideration. On the other hand, historic timezones exist with seconds and even fractional seconds in the UTC offset

  • That's fascinating; I never knew that.

Given that the most exotic time zones seem to have at most millisecond precision and the shared concerns about using int64s, would it make sense to limit the scope from microsecond support to millisecond support? If my back-of-the-napkin math is correct, 32 bit integers should be sufficient for that. FWIW- I benchmarked datetime comparisons with your code and cpython-main, and there was no difference in timing on my 64 bit machine.

@blenq

blenq commented Nov 27, 2022

Copy link
Copy Markdown
Author

I actually created an alternative implementation that does not use 64 integers. If this is preferable I'll add the commit to the pull request.

@Jason-Y-Z Jason-Y-Z left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@github-actions

Copy link
Copy Markdown

This PR is stale because it has been open for 30 days with no activity.

@github-actions github-actions Bot added the stale Stale PR or inactive for long period of time. label Apr 11, 2026
@StanFromIreland

Copy link
Copy Markdown
Member

I'm sorry but I'm closing in favour of #155024 as it includes additional fixes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting core review stale Stale PR or inactive for long period of time.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants