classification
Title: datetime.datetime.today makes no sense and should be removed
Type: Stage: resolved
Components: Library (Lib) Versions:
process
Status: closed Resolution: wont fix
Dependencies: Superseder:
Assigned To: belopolsky Nosy List: HassanAbouelela, belopolsky, p-ganssle, rhettinger, steven.daprano, yurzo
Priority: normal Keywords:

Created on 2020-10-01 15:54 by yurzo, last changed 2020-10-14 16:05 by belopolsky. This issue is now closed.

Messages (12)
msg377768 - (view) Author: Damian Yurzola (yurzo) Date: 2020-10-01 15:54
Last night I discovered we have datetime.datetime.today alongside
datetime.datetime.now and datetime.date.today.

- datetime.now
- date.today

Both make semantic sense.

datetime.datetime.today returns a datetime, which make no semantic sense and causes confusion.

On further inspection of the code, this is due to the fact that datetime inherits from date.

so datetime.today is practically an implementation of datetime.now minus the "tz".

I think we should implement a datetime.today only to rise an AttributeError or some other way to stop people from using the wrong semantic mental model.
We'd also need to remove the documentation entry: 
https://docs.python.org/3/library/datetime.html#datetime.datetime.today


From this inspection we also find that:

datetime.hour/minute/second are unnecessarily redefined.
lines Lib/datetime.py#L1606 to datetime.py#L1620

could be removed without any ill effect.






date.today:
https://github.com/python/cpython/blob/256e54acdbdb26745d4bbb5cf366454151e42773/Lib/datetime.py#L833



https://docs.python.org/3/library/datetime.html#datetime.datetime.today
msg377771 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2020-10-01 16:22
Even if I agreed that this method "makes no sense", and I don't, removing it would be gratuitous breakage.

Why should we break potentially thousands of people's code who are happily using this method, merely because you say that people who use it have "the wrong semantic mental model"?

Considered as a datetime, having `today` return the date and time *now* makes good sense to me. Obviously the date components must be today's date, not yesterday or tomorrow; and the time component could be any arbitrary time, with the current time an obvious choice.

And since datetime inherits from date, it would be very odd if it didn't inherit the `today` method. It would also violate the Liskov Substitution Principle.

But even if you disagree with my opinions, you still have to justify breaking backwards compatibility.
msg377776 - (view) Author: Damian Yurzola (yurzo) Date: 2020-10-01 16:37
Thanks for your prompt answer Steven.

I was inspired to file this bug after reading through a multiplicity of bugs introduced by folks confused by the library's behavior. So there's good precedent.

While granted, the documentation is explicit and the inheritance chain substantiates it. There's nothing more explicit than the function/type names and saying datetime.today() brings, as you say, arbitrary time to the conversation. Which I claim, subjectively, that it should not.


Gratuitous breakage, is debatable. It would not be the first or last. It could be a chance to remove a lot of code that works around potentially incorrect mental models.

But since both points are to some extent subjective. I'm OK to have left this on the record and move on.


What do you say about the unnecessarily redefined properties?

Lines Lib/datetime.py#L1606 to datetime.py#L1620
msg377792 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2020-10-02 01:00
On Thu, Oct 01, 2020 at 04:37:28PM +0000, Damian Yurzola wrote:
> I was inspired to file this bug after reading through a multiplicity 
> of bugs introduced by folks confused by the library's behavior.

Are these public bug reports or private anecdotes?

I'm not saying that the method cannot be deprecated or removed, but it 
needs to be justified. We don't break people's code gratuitiously, at 
least not intentionally. If you make a good enough case for deprecating 
the method, we can do so.

> What do you say about the unnecessarily redefined properties?
> 
> Lines Lib/datetime.py#L1606 to datetime.py#L1620

I don't know. Do all the tests still pass if you take them out?
msg378575 - (view) Author: Hassan Abouelela (HassanAbouelela) * Date: 2020-10-13 20:42
If having an arbitrary time returned from the function is an issue, why not use a fixed time, say 0 UTC, representing the start of the day. This would mean that datetime.today is date.today, with an (arguably) meaningless timestamp to make it a datetime object.
msg378589 - (view) Author: Damian Yurzola (yurzo) Date: 2020-10-14 00:45
I searched all of github and there seem to be ~350K entries for datetime.today
I think this supports steven.daprano point against removal.

I could not spot any major library in a quick cursory look.

However I do see many calls that look a lot like they should have been

datetime.date.today rather than datetime.datetime.today.

You see people basically dropping the hours, minutes, secs.

And you also see people doing date math on datetime.date.today which will result in different answers through out the day.

I like HassanAbouelela's idea that datetime.datetime.today should return   an arbitrary fixed time rather than an arbitrary variable time.
msg378593 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2020-10-14 01:39
On Wed, Oct 14, 2020 at 12:45:55AM +0000, Damian Yurzola wrote:

> And you also see people doing date math on datetime.date.today which 
> will result in different answers through out the day.

Yes? Is this a problem? If I ask the question "How long is it until 
Christmas?" the answer should be different if I ask on one minute past 
midnight on December 24 or one minute to midnight.

I daresay that you are correct that many (maybe a majority) of uses of 
datetime.today are conceptually better as date.today, but not all of 
them.

> I like HassanAbouelela's idea that datetime.datetime.today should 
> return an arbitrary fixed time rather than an arbitrary variable time.

But it's not an arbitrary variable time. It is just a high-resolution 
(down to the microsecond) version of "today", instead of the 
low-resolution (down to a single day) date.today.
msg378598 - (view) Author: Hassan Abouelela (HassanAbouelela) * Date: 2020-10-14 02:34
> "How long is it until Christmas?" the answer should be different if I ask on one minute past midnight on December 24 or one minute to midnight.

No disagreement there, but that doesn't change based on having the current precise time (the current implementation) vs the start of the current day (my recommendation), especially if you are just calculating the difference in days. In both cases, running it one minute before midnight would return the 23rd, running it one minute after would return the 24th.

The only difference between both is that a direct subtraction from the beginning of the day, with the current implementation, would result in one-point-something days, instead of one day. If that is the case, what is the point of having datetime.today? It should be, like the original issue suggested, phased out.

The benefit doesn't lie there, rather it lies in having direct access to date.today in a datetime format, so you can perform math on it with datetime objects. This, in my opinion, would be more consistent with other languages, and more importantly would make datetime.today logical, as it would be date.today in datetime form, instead of datetime.now.

> many (maybe a majority) of uses of datetime.today are conceptually better as date.today, but not all of them.

In what cases would having the current time be better? Should those cases instead use datetime.now for legibility?
msg378621 - (view) Author: Damian Yurzola (yurzo) Date: 2020-10-14 15:14
It took me a while to collect my thoughts but here you go.

Advanced users don't have a problem. They'll trade in date or datetime objects explicitly. The "proof" is I could not find any github repo with more than one start that'll call datetime.today().

The less advanced users are sometime doing datetime.today and then all kinds of weird things.

HassanAbouelela has a good point: datetime.today() is a straight forward way to get today in a datetime object.


On the topic of:

> "How long is it until Christmas?"

# Current
In [7]: datetime.datetime.today() - datetime.datetime.now()
Out[7]: datetime.timedelta(days=-1, seconds=86399, microseconds=999991)

# Hassan's
In [16]: datetime.datetime(2020, 12, 25) - datetime.datetime(datetime.datetime.today().year, datetime.datetime.today().month, datetime.datetime.today().day)
Out[16]: datetime.timedelta(days=72)


Optimizing for the less advanced user, I believe Hassan's proposal yields the more intuitive result.
msg378622 - (view) Author: Damian Yurzola (yurzo) Date: 2020-10-14 15:17
Sorry I got my "current" wrong and I can't find the edit button
Here again:


> "How long is it until Christmas?"

# Current implementation
In [23]: datetime.datetime(2020, 12, 25) - datetime.datetime.today()
Out[23]: datetime.timedelta(days=71, seconds=53018, microseconds=941806)

# Hassan's
In [16]: datetime.datetime(2020, 12, 25) - datetime.datetime(datetime.datetime.today().year, datetime.datetime.today().month, datetime.datetime.today().day)
Out[16]: datetime.timedelta(days=72)
msg378629 - (view) Author: Alexander Belopolsky (belopolsky) * (Python committer) Date: 2020-10-14 15:49
I agree that having some of datetime.now([tz]) functionality replicated in datetime.today() makes little sense.  However, the presence of this method in datetime class is a consequence of datetime being a subclass of the date class. The latter was a design mistake IMO, but as other pointed out it is too late to do anything about it.
msg378631 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2020-10-14 15:57
I concur with the other respondents.  This ship has sailed.
History
Date User Action Args
2020-10-14 16:05:18belopolskysetstatus: open -> closed
resolution: wont fix
stage: resolved
2020-10-14 15:57:20rhettingersetnosy: + rhettinger
messages: + msg378631
2020-10-14 15:49:35belopolskysetassignee: belopolsky
messages: + msg378629
2020-10-14 15:17:51yurzosetmessages: + msg378622
2020-10-14 15:14:37yurzosetmessages: + msg378621
2020-10-14 02:34:55HassanAbouelelasetmessages: + msg378598
2020-10-14 01:39:31steven.dapranosetmessages: + msg378593
2020-10-14 00:45:55yurzosetmessages: + msg378589
2020-10-13 20:42:11HassanAbouelelasetnosy: + HassanAbouelela
messages: + msg378575
2020-10-02 01:57:11xtreaksetnosy: + belopolsky, p-ganssle
2020-10-02 01:00:11steven.dapranosetmessages: + msg377792
2020-10-01 16:37:28yurzosetmessages: + msg377776
2020-10-01 16:22:39steven.dapranosetnosy: + steven.daprano
messages: + msg377771
2020-10-01 15:54:18yurzocreate