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

Improve API for calculating difference between two datetimes #108

Open
ArneBachmannDLR opened this issue Apr 9, 2024 · 5 comments
Open
Assignees
Labels
discussion Discussion is needed before proceeding enhancement New feature or request

Comments

@ArneBachmannDLR
Copy link

ArneBachmannDLR commented Apr 9, 2024

I was expecting it to return a DateTimeDelta, but it is:

    def __sub__(self, other: _AwareDateTime) -> TimeDelta: ...

Hint: I want to compute (dt - UTCDateTime(1970, 1, 1)).days.

Update: this seems to work: (dt._py_dt - datetime.datetime(1970, 1, 1, tzinfo=datetime.UTC)).days

@ariebovenberg
Copy link
Owner

ariebovenberg commented Apr 9, 2024

Hi @ArneBachmannDLR, thanks for posting this issue—this is indeed a part of the API I'd like to see improved myself as well.

Before I go into detail about potential solutions, here are two workarounds, with different semantics:

  1. if you care about calendar days, do your arithmetic on Date objects:

    >>> dt.date() - Date(1970, 1, 1)
    DateDelta(P54Y3M8D)
    # note that this may be different, depending on `dt` UTC offset!
    >>> dt.as_utc().date() - Date(1970, 1, 1)
    DateDelta(P54Y3M9D)
  2. If you care about days as exact 24-hour time units, make this explicit:

    >>> (dt - UTCDateTime(1970, 1, 1)).in_hours() / 24
    19822.5

the reason there is no in_days() is because days are sometimes more or less than 24 hours long, due to daylight saving time.

A note on your workaround

  • Please use the public .py_datetime() instead of the private _py_dt. The private attribute may be removed in later releases.
  • This solution is equivalent to workaround nr. 2 above

A long-term solution

The complicating factor here is that if UTCDateTime - x simply returns a DateTimeDelta, that you can't do .in_hours() or similar since calendar units aren't exact.

The solution is perhaps some kind of Difference object which can be interpreted on the calendar, as well as the timeline. I will create an issue about this in the future, and link it here.

@ariebovenberg ariebovenberg added the discussion Discussion is needed before proceeding label Apr 9, 2024
@ArneBachmannDLR
Copy link
Author

ArneBachmannDLR commented Apr 9, 2024

Just noticed that

  • (UTCDateTime(2022, 2, 11) - UTCDateTime(1970, 1, 1)).days gives 10 instead of 19358
  • (dt - UTCDateTime(1970, 1, 1)).in_hours() // 24 returns a float instead of an int

@ariebovenberg
Copy link
Owner

ariebovenberg commented Apr 9, 2024

Indeed:

  • .days refers to the days component of the DateDelta: Date(2024, 4, 11) - Date(1970, 1, 1) is DateDelta(P54Y3M10D), i.e. .years=54, .months=3, .days=10. The .days attribute is perhaps too ambiguous, and can lead to misunderstandings—especially coming from datetime.timedelta. Perhaps renaming it to days_component is less ambiguous 🤔
  • returning a float is actually correct right? There probably isn't an exact 24h-divisible difference between two moments. You need to explicitly decide whether to round up or down

edit: mistaken first conclusion

@ariebovenberg ariebovenberg added the enhancement New feature or request label Apr 30, 2024
@ariebovenberg ariebovenberg self-assigned this Apr 30, 2024
@ariebovenberg
Copy link
Owner

The new release 0.6.0 has changed the API somewhat to at least prevent confusing situations:

>>> (Date(2022, 2, 11) - Date(1970, 1, 1)).in_years_months_days()
(52, 1, 10)
>>> (Instant.now() - Instant.from_utc(1970, 1, 1)).in_days_of_24h()
19908.618500809072

Of course, this still leaves the situation where you'd like to get a DateTimeDelta from a difference calculation. This will require some more thinking to get a good API. To be continued...

@ariebovenberg ariebovenberg changed the title UTCDateTime.__sub__ returns only TimeDelta without Date-Delta Improve API for calculating difference between to datetimes Jul 5, 2024
@ariebovenberg ariebovenberg changed the title Improve API for calculating difference between to datetimes Improve API for calculating difference between two datetimes Jul 9, 2024
@ariebovenberg ariebovenberg added this to the API freeze (1.0) milestone Nov 17, 2024
@ariebovenberg
Copy link
Owner

ariebovenberg commented Nov 17, 2024

Another gap in the current API: calculating the number of days between two dates.

The API I'm considering:

>>> b - a
DateDiff(...)  # no longer a Delta, since we CANNOT assume whether we want it in months/days, or only days
>>> (b - a).in_months_days()
DateDelta(P3M5D)
>>> (b - a).in_months_days().tuple()  # to allow unpacking
(3, 5)
>>> (b - a).in_days()
96

Still needs some thought...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion Discussion is needed before proceeding enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants