This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: datetime.datetime() should accept a datetime.date as init parameter
Type: enhancement Stage: needs patch
Components: Versions: Python 3.5
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: Nosy List: belopolsky, facundobatista, r.david.murray, rhettinger, tim.peters
Priority: normal Keywords:

Created on 2014-07-24 14:41 by facundobatista, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Messages (10)
msg223840 - (view) Author: Facundo Batista (facundobatista) * (Python committer) Date: 2014-07-24 14:41
Currently (tested on py3.4):

>>> from datetime import datetime, date
>>> d = datetime.now()
>>> date(d)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: an integer is required (got type datetime.datetime)

IMO, it's like doing int(float), a truncation of some info. For example, this is what I want to happen:

>>> d
datetime.datetime(2014, 7, 24, 11, 38, 44, 966613)
>>> date(d)
datetime.date(2014, 7, 24)
msg223849 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2014-07-24 15:33
There is already a spelling for that operation, and it is d.date().  I'm not sure that there is a strong enough argument for adding a second way to spell it, but I won't close this yet to see what other people think.  

Personally I don't think it has ever occurred to me to do date(datetime) (although I have wanted to pass a string to the constructor), and I've wanted the operation and found the 'date()' method more than once.
msg223853 - (view) Author: Alexander Belopolsky (belopolsky) * (Python committer) Date: 2014-07-24 15:52
+1

There is currently no obvious way to convert either date or datetime instance to date.

The best solution I can think of is date(*x.timetuple()[:3]):

>>> d = date.today()
>>> t = datetime.now()
>>> date(*d.timetuple()[:3])
datetime.date(2014, 7, 24)
>>> date(*t.timetuple()[:3])
datetime.date(2014, 7, 24)

Certainly date(x) wins hands down over this atrocity.
msg223863 - (view) Author: Tim Peters (tim.peters) * (Python committer) Date: 2014-07-24 18:01
Was the title of this meant to be

"datetime.date() should accept a datetime.datetime as init parameter"

instead?  That's what the example appears to be getting at.

If so, -1.  Datetime objects already have .date(), .time(), and .timetz() methods to extract, respectively, the date, naive time, and aware time portions of the datetime object.  In the other direction, the datetime .combine() constructor builds a datetime object out of date and time components.  As the docs say,

"For any datetime object d, d == datetime.combine(d.date(), d.timetz())"

Another way to spell this isn't needed.

> There is currently no obvious way to convert either date
> or datetime instance to date.

some_datetime_object.date() is the obvious way to extract a date object from a datetime object.

I don't know what it could mean to convert a date object to a date.  That's pretty much exactly like asking how to convert an int object to an int.  Huh? ;-)  date and int objects are immutable, so a need to make a copy (if that's what is meant) rarely arises.
msg223866 - (view) Author: Alexander Belopolsky (belopolsky) * (Python committer) Date: 2014-07-24 18:29
> some_datetime_object.date() is the obvious way to extract a
> date object from a datetime object.

Sorry if I was not clear enough about my use case.  I often have to deal with functions that are designed to take either date or datetime object as an argument, but only use date components.  In most cases this works automatically because datetime is a subclass of date.  However, there are some annoying exceptions.  For example, x > date(2001, 1, 1) will not work if x is a datetime instance.  If in this example I write x.date() > date(2001, 1, 1) - I get the opposite problem - it won't work when x is a date instance.

The "obvious" way would be date(x) > date(2001, 1, 1).

Can you suggest anything better than date(*x.timetuple()[:3]) > date(2001, 1, 1) here?
msg223867 - (view) Author: Alexander Belopolsky (belopolsky) * (Python committer) Date: 2014-07-24 18:32
Another "solution" is date(2001, 1, 1).__lt__(x), but this is even uglier than the one with timetuple.
msg223871 - (view) Author: Tim Peters (tim.peters) * (Python committer) Date: 2014-07-24 19:01
Alexander, I don't see a need to make everything a one-liner.  Dealing with a mix of dates and datetimes is easily sorted out with an `if` statement, like

def func(thedate):
    if isinstance(thedate, datetime.datetime):
        thedate = thedate.date()
    # and now `thedate` is a bona fide datetime.date

Or stick the two lines in a utility function.

If you're determined to do it one line, because datetime is a subclass of date you could also use .combine() to force everything to class datetime.datetime in one line:

_ZEROT = datetime.time()

def func(thedatetime):
    thedatetime = datetime.combine(thedatetime, _ZEROT)
    # and now `thedatetime` is a bona fide datetime.datetime
msg223876 - (view) Author: Alexander Belopolsky (belopolsky) * (Python committer) Date: 2014-07-24 19:26
It is not as mush about avoiding a one-liner as it is about duck-typing.  IMO, dates and datetime objects are numbers in disguise.  Many functions that are nominally numeric, can work with date/datetime/timedelta objects without modification.  The fact that date/datetime do not accept their own instances often results in the need to branch on isinstance() or write a separate set of functions depending on whether dates are represented by numbers or by date instances.

The example that I gave is one of many and the fact that you suggested using isinstance() in the solution is telling. 

My ideal design would be for date/datetime constructors to take one argument that can be a string, a 3+ elements iterable, or any object that has a .timetuple() method.  The varargs variants can of course stay as syntactic sugar.
msg223888 - (view) Author: Facundo Batista (facundobatista) * (Python committer) Date: 2014-07-24 20:12
El 24/07/14 a las 15:01, Tim Peters escibió:

> "datetime.date() should accept a datetime.datetime as init
> parameter"
> 
> instead?  That's what the example appears to be getting at.
> 
> If so, -1.  Datetime objects already have .date(), .time(), and
> .timetz() methods to extract, respectively, the date, naive time, and

Ah, I wasn't aware of the .date() method.

I guess because it's more natural to me to do int(a_float) than
a_float.integer().

So, unless anyody wants to pursue with this, I'll close the issue.

Thanks!
msg223987 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2014-07-25 19:23
[David]
> There is already a spelling for that operation, and it is d.date()

[Tim]
Alexander, I don't see a need to make everything a one-liner

[Facundo]
> So, unless anyody wants to pursue with this, I'll close the issue.

Marking as closed, rejected for the reasons listed and because making a function signature more complicated just isn't worth it.
History
Date User Action Args
2022-04-11 14:58:06adminsetgithub: 66256
2014-07-25 19:23:26rhettingersetstatus: open -> closed

nosy: + rhettinger
messages: + msg223987

resolution: rejected
2014-07-24 20:12:32facundobatistasetmessages: + msg223888
2014-07-24 19:26:13belopolskysetmessages: + msg223876
2014-07-24 19:01:33tim.peterssetmessages: + msg223871
2014-07-24 18:32:54belopolskysetmessages: + msg223867
2014-07-24 18:29:29belopolskysetmessages: + msg223866
2014-07-24 18:01:46tim.peterssetnosy: + tim.peters
messages: + msg223863
2014-07-24 15:52:22belopolskysettype: enhancement
messages: + msg223853
stage: needs patch
2014-07-24 15:33:15r.david.murraysetnosy: + r.david.murray, belopolsky
messages: + msg223849
2014-07-24 15:02:51facundobatistasettitle: datetime.datetime() should accept a datetime.date as constructor -> datetime.datetime() should accept a datetime.date as init parameter
2014-07-24 14:41:32facundobatistacreate