How to truncate the time on a datetime object? - python

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.

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)

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)

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()

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?

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)

See more at https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.dt.floor.html
It's now 2019, I think the most efficient way to do it is:
df['truncate_date'] = df['timestamp'].dt.floor('d')

You could use pandas for that (although it could be overhead for that task). You could use round, floor and ceil like for usual numbers and any pandas frequency from offset-aliases:
import pandas as pd
import datetime as dt
now = dt.datetime.now()
pd_now = pd.Timestamp(now)
freq = '1d'
pd_round = pd_now.round(freq)
dt_round = pd_round.to_pydatetime()
print(now)
print(dt_round)
"""
2018-06-15 09:33:44.102292
2018-06-15 00:00:00
"""

There is a great library used to manipulate dates: Delorean
import datetime
from delorean import Delorean
now = datetime.datetime.now()
d = Delorean(now, timezone='US/Pacific')
>>> now
datetime.datetime(2015, 3, 26, 19, 46, 40, 525703)
>>> d.truncate('second')
Delorean(datetime=2015-03-26 19:46:40-07:00, timezone='US/Pacific')
>>> d.truncate('minute')
Delorean(datetime=2015-03-26 19:46:00-07:00, timezone='US/Pacific')
>>> d.truncate('hour')
Delorean(datetime=2015-03-26 19:00:00-07:00, timezone='US/Pacific')
>>> d.truncate('day')
Delorean(datetime=2015-03-26 00:00:00-07:00, timezone='US/Pacific')
>>> d.truncate('month')
Delorean(datetime=2015-03-01 00:00:00-07:00, timezone='US/Pacific')
>>> d.truncate('year')
Delorean(datetime=2015-01-01 00:00:00-07:00, timezone='US/Pacific')
and if you want to get datetime value back:
>>> d.truncate('year').datetime
datetime.datetime(2015, 1, 1, 0, 0, tzinfo=<DstTzInfo 'US/Pacific' PDT-1 day, 17:00:00 DST>)

You can use datetime.strftime to extract the day, the month, the year...
Example :
from datetime import datetime
d = datetime.today()
# Retrieves the day and the year
print d.strftime("%d-%Y")
Output (for today):
29-2011
If you just want to retrieve the day, you can use day attribute like :
from datetime import datetime
d = datetime.today()
# Retrieves the day
print d.day
Ouput (for today):
29

If you are dealing with a Series of type DateTime there is a more efficient way to truncate them, specially when the Series object has a lot of rows.
You can use the floor function
For example, if you want to truncate it to hours:
Generate a range of dates
times = pd.Series(pd.date_range(start='1/1/2018 04:00:00', end='1/1/2018 22:00:00', freq='s'))
We can check it comparing the running time between the replace and the floor functions.
%timeit times.apply(lambda x : x.replace(minute=0, second=0, microsecond=0))
>>> 341 ms ± 18.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit times.dt.floor('h')
>>>>2.26 ms ± 451 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

>>> import datetime
>>> dt = datetime.datetime.now()
>>> datetime.datetime.date(dt)
datetime.date(2019, 4, 2)

Here is yet another way which fits in one line but is not particularly elegant:
dt = datetime.datetime.fromordinal(datetime.date.today().toordinal())

There is a module datetime_truncate which handlers this for you. It just calls datetime.replace.

6 years later... I found this post and I liked more the numpy aproach:
import numpy as np
dates_array = np.array(['2013-01-01', '2013-01-15', '2013-01-30']).astype('datetime64[ns]')
truncated_dates = dates_array.astype('datetime64[D]')
cheers

If you want to truncate to an arbitrary timedelta:
from datetime import datetime, timedelta
truncate = lambda t, d: t + (datetime.min - t) % - d
# 2022-05-04 15:54:19.979349
now = datetime.now()
# truncates to the last 15 secondes
print(truncate(now, timedelta(seconds=15)))
# truncates to the last minute
print(truncate(now, timedelta(minutes=1)))
# truncates to the last 2 hours
print(truncate(now, timedelta(hours=2)))
# ...
"""
2022-05-04 15:54:15
2022-05-04 15:54:00
2022-05-04 14:00:00
"""
PS: This is for python3

You can just use
datetime.date.today()
It's light and returns exactly what you want.

You could do it by specifying isoformat
>>> import datetime
>>> datetime.datetime.now().isoformat(timespec='seconds', sep=' ')
2022-11-24 12:42:05
The documentation offers more details about the isoformat() usage.
https://docs.python.org/3/library/datetime.html#datetime.datetime.isoformat

What does truncate mean?
You have full control over the formatting by using the strftime() method and using an appropriate format string.
http://docs.python.org/library/datetime.html#strftime-strptime-behavior

Related

How to use milliseconds instead of microsenconds in datetime python

A client has specified that they use DateTime to store their dates using the format 2021-06-22T11:17:09.465Z, and so far I've been able only to obtain it in string dates, because If I want to maintain the milliseconds it saves them like 2021-06-22T11:17:09.465000.
Is there any possible way to force DateTime to use milliseconds instead of microseconds? I'm aware of the %f for microseconds in the format, but I've tried everything I can think of to reduce those 3 decimals while keeping it DateTime with no results however.
I suggest to use the timespec parameter, as described in python docs https://docs.python.org/3/library/datetime.html#datetime.datetime.isoformat:
>>> from datetime import datetime
>>> datetime.now().isoformat(timespec='minutes')
'2002-12-25T00:00'
>>> dt = datetime(2015, 1, 1, 12, 30, 59, 0)
>>> datetime.now().isoformat(timespec='milliseconds')
'2021-12-02T14:03:57.937'
Something like this works:
from datetime import datetime
dt = datetime.now()
print(f"{dt:%Y/%m/%dT%H:%M:%S}.{f'{dt:%f}'[:3]}")
Hope I help.
I assume you're looking for this? See also my general comment at question.
The variable 3 in [:3] can be adjusted to your liking for amount of zeros in ms to ns range. Use the type() to show you its a DateTime object.
import time
from datetime import datetime
tm = time.time()
print(tm)
dt = str(tm).split('.')
print(dt)
timestamp = float(dt[0] + '.' + dt[1][:3])
dt_object = datetime.fromtimestamp(timestamp)
print(dt_object)
This prints for example:
tm : 1638463260.919723
dt : ['1638463260', '919723']
and
dd_object : 2021-12-02 17:41:00.919000
You can divide nanoseconds by 1000000000 to get seconds and by 1000000 to get milliseconds.
Here is some code that will get nanoseconds:
tim = time.time_ns()
You can then combine the output of this with the rest of the format. Probably not the cleanest solution but it should work.

How to get current time in python and break up into year, month, day, hour, minute?

I would like to get the current time in Python and assign them into variables like year, month, day, hour, minute. How can this be done in Python 2.7?
The datetime module is your friend:
import datetime
now = datetime.datetime.now()
print(now.year, now.month, now.day, now.hour, now.minute, now.second)
# 2015 5 6 8 53 40
You don't need separate variables, the attributes on the returned datetime object have all you need.
Here's a one-liner that comes in just under the 80 char line max.
import time
year, month, day, hour, min = map(int, time.strftime("%Y %m %d %H %M").split())
The datetime answer by tzaman is much cleaner, but you can do it with the original python time module:
import time
strings = time.strftime("%Y,%m,%d,%H,%M,%S")
t = strings.split(',')
numbers = [ int(x) for x in t ]
print numbers
Output:
[2016, 3, 11, 8, 29, 47]
By unpacking timetuple of datetime object, you should get what you want:
from datetime import datetime
n = datetime.now()
t = n.timetuple()
y, m, d, h, min, sec, wd, yd, i = t
Let's see how to get and print day,month,year in python from current time:
import datetime
now = datetime.datetime.now()
year = '{:02d}'.format(now.year)
month = '{:02d}'.format(now.month)
day = '{:02d}'.format(now.day)
hour = '{:02d}'.format(now.hour)
minute = '{:02d}'.format(now.minute)
day_month_year = '{}-{}-{}'.format(year, month, day)
print('day_month_year: ' + day_month_year)
result:
day_month_year: 2019-03-26
For python 3
import datetime
now = datetime.datetime.now()
print(now.year, now.month, now.day, now.hour, now.minute, now.second)
import time
year = time.strftime("%Y") # or "%y"
You can use gmtime
from time import gmtime
detailed_time = gmtime()
#returns a struct_time object for current time
year = detailed_time.tm_year
month = detailed_time.tm_mon
day = detailed_time.tm_mday
hour = detailed_time.tm_hour
minute = detailed_time.tm_min
Note: A time stamp can be passed to gmtime, default is current time as
returned by time()
eg.
gmtime(1521174681)
See struct_time
Three libraries for accessing and manipulating dates and times, namely datetime, arrow and pendulum, all make these items available in namedtuples whose elements are accessible either by name or index. Moreover, the items are accessible in precisely the same way. (I suppose if I were more intelligent I wouldn't be surprised.)
>>> YEARS, MONTHS, DAYS, HOURS, MINUTES = range(5)
>>> import datetime
>>> import arrow
>>> import pendulum
>>> [datetime.datetime.now().timetuple()[i] for i in [YEARS, MONTHS, DAYS, HOURS, MINUTES]]
[2017, 6, 16, 19, 15]
>>> [arrow.now().timetuple()[i] for i in [YEARS, MONTHS, DAYS, HOURS, MINUTES]]
[2017, 6, 16, 19, 15]
>>> [pendulum.now().timetuple()[i] for i in [YEARS, MONTHS, DAYS, HOURS, MINUTES]]
[2017, 6, 16, 19, 16]
This is an older question, but I came up with a solution I thought others might like.
def get_current_datetime_as_dict():
n = datetime.now()
t = n.timetuple()
field_names = ["year",
"month",
"day",
"hour",
"min",
"sec",
"weekday",
"md",
"yd"]
return dict(zip(field_names, t))
timetuple() can be zipped with another array, which creates labeled tuples. Cast that to a dictionary and the resultant product can be consumed with get_current_datetime_as_dict()['year'].
This has a little more overhead than some of the other solutions on here, but I've found it's so nice to be able to access named values for clartiy's sake in the code.

DateTime Conversion to Epoch Time

I need to convert time stored in a variable in the format using Python <=2.7
07/20-10:38:04.360700
to epoch time (since Midnight, Jan 1st, 1970) like this
1405852684.360700
Is it best to import the time module, or just split and use some math calculations?
If the string date is with respect to UTC, then:
In [31]: import datetime as DT
In [32]: text = '07/20-10:38:04.360700'
In [33]: date = DT.datetime.strptime('2014/'+text, '%Y/%m/%d-%H:%M:%S.%f')
In [34]: (date - DT.datetime(1970,1,1)).total_seconds()
Out[34]: 1405852684.3607
If the string date refers to a date with respect to some other timezone, then you could use pytz to make the datetime timezone-aware before doing the calculation. For example,
import pytz
import datetime as DT
text = '07/20-10:38:04.360700'
tz = pytz.timezone('US/Eastern')
date = DT.datetime.strptime('2014/'+text, '%Y/%m/%d-%H:%M:%S.%f')
# interpret the date as coming from US/Eastern
date_tz = tz.localize(date)
epoch = DT.datetime(1970,1,1, tzinfo=pytz.utc)
timestamp = (date_tz - epoch).total_seconds()
print(repr(timestamp))
# 1405867084.3607
You can use python's timetuple() function (and a little math)
>>> import datetime
>>> import time
>>> v = datetime.datetime(2014, 7, 20, 10, 38, 4, 360700)
>>> time.mktime(v.timetuple())
1405870684.0
Now we need your microseconds:
>>> time.mktime(v.timetuple())+(v.microsecond/1000000.)
1405870684.3607
You don't specify the year so here I assume that it is the current year. The following assumes that all times are UTC, i.e. not local time.
from datetime import datetime
time_string = '07/20-10:38:04.360700'
dt = datetime.strptime(time_string, '%m/%d-%H:%M:%S.%f')
dt = dt.replace(year=datetime.today().year)
>>> (dt - datetime.utcfromtimestamp(0)).total_seconds()
1405852684.3607

convert time in Python

I am parsing an xml file in python and I need to convert the following date and time format to something human-friendly:
<due_date>735444</due_date>
<due_time>55800</due_time>
The format of date seems to be number of days since year 0, and time is the number of seconds since midnight.
How could I convert it into some standard format, such as 2014-07-30 15:30:00 ?
Use datetime.datetime.fromordinal() plus a timedelta() for the seconds after midnight:
import datetime
dt = datetime.datetime.fromordinal(due_date) + datetime.timedelta(seconds=due_time)
Your due_date is relative to the year 1 instead, as your values fit to produce your expected date:
>>> import datetime
>>> due_date = 735444
>>> due_time = 55800
>>> datetime.datetime.fromordinal(due_date) + datetime.timedelta(seconds=due_time)
datetime.datetime(2014, 7, 30, 15, 30)

Convert string date to timestamp in Python

How to convert a string in the format "%d/%m/%Y" to timestamp?
"01/12/2011" -> 1322697600
>>> import time
>>> import datetime
>>> s = "01/12/2011"
>>> time.mktime(datetime.datetime.strptime(s, "%d/%m/%Y").timetuple())
1322697600.0
I use ciso8601, which is 62x faster than datetime's strptime.
t = "01/12/2011"
ts = ciso8601.parse_datetime(t)
# to get time in seconds:
time.mktime(ts.timetuple())
You can learn more here.
>>> int(datetime.datetime.strptime('01/12/2011', '%d/%m/%Y').strftime("%s"))
1322683200
To convert the string into a date object:
from datetime import date, datetime
date_string = "01/12/2011"
date_object = date(*map(int, reversed(date_string.split("/"))))
assert date_object == datetime.strptime(date_string, "%d/%m/%Y").date()
The way to convert the date object into POSIX timestamp depends on timezone. From Converting datetime.date to UTC timestamp in Python:
date object represents midnight in UTC
import calendar
timestamp1 = calendar.timegm(utc_date.timetuple())
timestamp2 = (utc_date.toordinal() - date(1970, 1, 1).toordinal()) * 24*60*60
assert timestamp1 == timestamp2
date object represents midnight in local time
import time
timestamp3 = time.mktime(local_date.timetuple())
assert timestamp3 != timestamp1 or (time.gmtime() == time.localtime())
The timestamps are different unless midnight in UTC and in local time is the same time instance.
Simply use datetime.datetime.strptime:
import datetime
stime = "01/12/2011"
print(datetime.datetime.strptime(stime, "%d/%m/%Y").timestamp())
Result:
1322697600
To use UTC instead of the local timezone use .replace:
datetime.datetime.strptime(stime, "%d/%m/%Y").replace(tzinfo=datetime.timezone.utc).timestamp()
The answer depends also on your input date timezone. If your date is a local date, then you can use mktime() like katrielalex said - only I don't see why he used datetime instead of this shorter version:
>>> time.mktime(time.strptime('01/12/2011', "%d/%m/%Y"))
1322694000.0
But observe that my result is different than his, as I am probably in a different TZ (and the result is timezone-free UNIX timestamp)
Now if the input date is already in UTC, than I believe the right solution is:
>>> calendar.timegm(time.strptime('01/12/2011', '%d/%m/%Y'))
1322697600
I would give a answer for beginners (like me):
You have the date string "01/12/2011". Then it can be written by the format "%d/%m/%Y". If you want to format to another format like "July 9, 2015", here a good cheatsheet.
Import the datetime library.
Use the datetime.datetime class to handle date and time combinations.
Use the strptime method to convert a string datetime to a object datetime.
Finally, use the timestamp method to get the Unix epoch time as a float. So,
import datetime
print( int( datetime.datetime.strptime( "01/12/2011","%d/%m/%Y" ).timestamp() ) )
# prints 1322712000
A lot of these answers don't bother to consider that the date is naive to begin with
To be correct, you need to make the naive date a timezone aware datetime first
import datetime
import pytz
# naive datetime
d = datetime.datetime.strptime('01/12/2011', '%d/%m/%Y')
>>> datetime.datetime(2011, 12, 1, 0, 0)
# add proper timezone
pst = pytz.timezone('America/Los_Angeles')
d = pst.localize(d)
>>> datetime.datetime(2011, 12, 1, 0, 0,
tzinfo=<DstTzInfo 'America/Los_Angeles' PST-1 day, 16:00:00 STD>)
# convert to UTC timezone
utc = pytz.UTC
d = d.astimezone(utc)
>>> datetime.datetime(2011, 12, 1, 8, 0, tzinfo=<UTC>)
# epoch is the beginning of time in the UTC timestamp world
epoch = datetime.datetime(1970,1,1,0,0,0,tzinfo=pytz.UTC)
>>> datetime.datetime(1970, 1, 1, 0, 0, tzinfo=<UTC>)
# get the total second difference
ts = (d - epoch).total_seconds()
>>> 1322726400.0
Also:
Be careful, using pytz for tzinfo in a datetime.datetime DOESN'T WORK for many timezones. See datetime with pytz timezone. Different offset depending on how tzinfo is set
# Don't do this:
d = datetime.datetime(2011, 12, 1,0,0,0, tzinfo=pytz.timezone('America/Los_Angeles'))
>>> datetime.datetime(2011, 1, 12, 0, 0,
tzinfo=<DstTzInfo 'America/Los_Angeles' LMT-1 day, 16:07:00 STD>)
# tzinfo in not PST but LMT here, with a 7min offset !!!
# when converting to UTC:
d = d.astimezone(pytz.UTC)
>>> datetime.datetime(2011, 1, 12, 7, 53, tzinfo=<UTC>)
# you end up with an offset
https://en.wikipedia.org/wiki/Local_mean_time
First you must the strptime class to convert the string to a struct_time format.
Then just use mktime from there to get your float.
I would suggest dateutil:
import dateutil.parser
dateutil.parser.parse("01/12/2011", dayfirst=True).timestamp()
Seems to be quite efficient:
import datetime
day, month, year = '01/12/2011'.split('/')
datetime.datetime(int(year), int(month), int(day)).timestamp()
1.61 µs ± 120 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
you can convert to isoformat
my_date = '2020/08/08'
my_date = my_date.replace('/','-') # just to adapte to your question
date_timestamp = datetime.datetime.fromisoformat(my_date).timestamp()
You can refer this following link for using strptime function from datetime.datetime, to convert date from any format along with time zone.
https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior
just use datetime.timestamp(your datetime instanse), datetime instance contains the timezone infomation, so the timestamp will be a standard utc timestamp. if you transform the datetime to timetuple, it will lose it's timezone, so the result will be error.
if you want to provide an interface, you should write like this:
int(datetime.timestamp(time_instance)) * 1000
A simple function to get UNIX Epoch time.
NOTE: This function assumes the input date time is in UTC format (Refer to comments here).
def utctimestamp(ts: str, DATETIME_FORMAT: str = "%d/%m/%Y"):
import datetime, calendar
ts = datetime.datetime.utcnow() if ts is None else datetime.datetime.strptime(ts, DATETIME_FORMAT)
return calendar.timegm(ts.utctimetuple())
Usage:
>>> utctimestamp("01/12/2011")
1322697600
>>> utctimestamp("2011-12-01", "%Y-%m-%d")
1322697600
You can go both directions, unix epoch <==> datetime :
import datetime
import time
the_date = datetime.datetime.fromtimestamp( 1639763585 )
unix_time = time.mktime(the_date.timetuple())
assert ( the_date == datetime.datetime.fromtimestamp(unix_time) ) & \
( time.mktime(the_date.timetuple()) == unix_time )

Categories