How to truncate the time on a datetime object?
Solution 1
I think this is what you're looking for...
>>> import datetime
>>> dt = datetime.datetime.now()
>>> dt = dt.replace(hour=0, minute=0, second=0, microsecond=0) # Returns a copy
>>> dt
datetime.datetime(2011, 3, 29, 0, 0)
But if you really don't care about the time aspect of things, then you should really only be passing around date
objects...
>>> d_truncated = datetime.date(dt.year, dt.month, dt.day)
>>> d_truncated
datetime.date(2011, 3, 29)
Solution 2
Use a date
not a datetime
if you dont care about the time.
>>> now = datetime.now()
>>> now.date()
datetime.date(2011, 3, 29)
You can update a datetime like this:
>>> now.replace(minute=0, hour=0, second=0, microsecond=0)
datetime.datetime(2011, 3, 29, 0, 0)
Solution 3
Four years later: another way, avoiding replace
I know the accepted answer from four years ago works, but this seems a tad lighter than using replace
:
dt = datetime.date.today()
dt = datetime.datetime(dt.year, dt.month, dt.day)
Notes
- When you create a
datetime
object without passing time properties to the constructor, you get midnight. - As others have noted, this assumes you want a datetime object for later use with timedeltas.
- You can, of course, substitute this for the first line:
dt = datetime.datetime.now()
Solution 4
You cannot truncate a datetime object because it is immutable.
However, here is one way to construct a new datetime with 0 hour, minute, second, and microsecond fields, without throwing away the original date or tzinfo:
newdatetime = now.replace(hour=0, minute=0, second=0, microsecond=0)
Solution 5
To get a midnight corresponding to a given datetime object, you could use datetime.combine()
method:
>>> from datetime import datetime, time
>>> dt = datetime.utcnow()
>>> dt.date()
datetime.date(2015, 2, 3)
>>> datetime.combine(dt, time.min)
datetime.datetime(2015, 2, 3, 0, 0)
The advantage compared to the .replace()
method is that datetime.combine()
-based solution will continue to work even if datetime
module introduces the nanoseconds support.
tzinfo
can be preserved if necessary but the utc offset may be different at midnight e.g., due to a DST transition and therefore a naive solution (setting tzinfo
time attribute) may fail. See How do I get the UTC time of “midnight” for a given timezone?
Related videos on Youtube
Kyle Brandt
Developer at Grafana Labs - formerly SRE at Stack Overflow.
Updated on May 05, 2022Comments
-
Kyle Brandt almost 2 years
What is a classy way to way truncate a python
datetime
object?In this particular case, to the day. So basically setting hour, minute, seconds, and microseconds to 0.
I would like the output to also be a
datetime
object, not a string. -
Kyle Brandt about 13 yearsWell the thing is I already do this once, so that might have more overhead then just setting the hour min etc fields in the datetime object.
-
Jochen Ritzel about 13 yearsHeh, thats a weird way to do it, you can actually just do
d.day
etc. -
ʇsәɹoɈ about 13 yearsWith timezone-aware datetimes, now.date() throws away the tzinfo information.
-
ʇsәɹoɈ about 13 yearsWith a timezone-aware dt, datetime.datetime(dt.year, dt.month, dt.day) throws away the tzinfo information.
-
user1066101 about 13 years+1: if you put the
replace
option first, since that's probably what they want. -
galarant almost 11 yearsif you're looking for just today, you can also do datetime.date.today()
-
Brad M over 9 yearsNote that python 2 and python 3 docs both state that the
replace()
method returns a datetime object, so the correct incantation would be:dt = datetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
-
jfs about 9 yearsOP wants
datetime
, notdate
object (that you could get usingdt.date()
call (no need to use the explicit constructor)). The.replace()
method may fail ifdatetime
adds nanosecond support. You could usedatetime.combine()
instead. -
jfs about 9 years@ʇsәɹoɈ: here's how you could get the timezone-aware midnight
-
jfs about 9 yearsit returns the wrong time (wrong utc offset) if the result time has a different utc offset e.g., due to a DST transition. See How do I get the UTC time of “midnight” for a given timezone?
-
jfs about 9 yearsIt is incorrect to use
tzinfo=now.tzinfo
. Thetzinfo
at midnight may be different e.g., utc offset at2012-04-01 00:09:00
(9am) in Australia/Melbourne timezone isAEST+10:00
but it isAEDT+11:00
at2012-04-01 00:00:00
(midnight) -- there is end-of-DST transition on that day. You could usepytz
module to fix it, see my answer. -
3kstc over 5 years@chrisw Why not just write it up in one line
datetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
? -
slfan over 5 yearsThe same answer has been given before, there is nothing new.
-
Bordotti about 5 yearsSorry @slfan but i didn't see any post with your name, even using "search" from browser.
-
slfan about 5 yearsNot by me, by zx81 3 years ago. search for datetime.date.today(). If an answer is correct, you should upvote, not answer again.
-
mathtick over 3 yearscast as datetime
-
ebk about 3 yearsand it saves you a lot of typing (compared to replace()).
-
Eiffelbear about 3 yearsthis answer is the best but got only 1 upvote, so I upvoted your answer:)
-
Eiffelbear about 3 yearsyeah, let's use dt.floor!!
-
Skippy le Grand Gourou almost 3 yearsNote that it’s kind of a pain to convert it back to datetime, though.
-
Seyfi over 2 yearsWith timezone-aware datetimes, tzinfo information does not share between the two.
-
Clej about 2 yearsWaw, exactly what I've been looking for the last three hours. Thanks a lot. That's the only solution that enables to pass the truncating frequency as a parameter...
-
cph_sto almost 2 yearsWell,
df['timestamp'] = df['timestamp'].dt.floor('d')
will not work. Column name must be different and this is a serious drawback.