diff = reference_time - topic_time
hour = round((reference_time-topic_time) / datetime.timedelta(hours=1))
if reference_time = '2020-08-23 07:00:10' and topic_time = '2020-08-22 00:00:00', the 'diff' variable is:
days = 1
seconds = 25210
The 'hour' conversion code make the hour = 31, which seems incorrect. The max diff should be less than 24 hours in one day. How to calculate time diffs and convert to hours in this case?
import datetime
firstTime = datetime.datetime.utcnow()
secondTime = datetime.datetime.utcnow() + datetime.timedelta(hours=5)
diff = secondTime - firstTime
hours = diff.total_seconds() // 3600
print(hours) # Answer is 5
reference_time = datetime.datetime(2020,8,23,7)
topic_time = datetime.datetime(2020,8,22,0)
hours = (reference_time - topic_time).total_seconds() // 3600
days = hours // 24
hours = hours - (days*24)
print('days: %d, hours: %d' % (days, hours) ) # days:1, hours:7
I get a start_date like this:
from django.utils.timezone import utc
import datetime
start_date = datetime.datetime.utcnow().replace(tzinfo=utc)
end_date = datetime.datetime.utcnow().replace(tzinfo=utc)
duration = end_date - start_date
I get output like this:
datetime.timedelta(0, 5, 41038)
How do I convert this into normal time like the following?
10 minutes, 1 hour like this
There's no built-in formatter for timedelta objects, but it's pretty easy to do it yourself:
days, seconds = duration.days, duration.seconds
hours = days * 24 + seconds // 3600
minutes = (seconds % 3600) // 60
seconds = seconds % 60
Or, equivalently, if you're in Python 2.7+ or 3.2+:
seconds = duration.total_seconds()
hours = seconds // 3600
minutes = (seconds % 3600) // 60
seconds = seconds % 60
Now you can print it however you want:
'{} minutes, {} hours'.format(minutes, hours)
For example:
def convert_timedelta(duration):
days, seconds = duration.days, duration.seconds
hours = days * 24 + seconds // 3600
minutes = (seconds % 3600) // 60
seconds = (seconds % 60)
return hours, minutes, seconds
td = datetime.timedelta(2, 7743, 12345)
hours, minutes, seconds = convert_timedelta(td)
print '{} minutes, {} hours'.format(minutes, hours)
This will print:
9 minutes, 50 hours
If you want to get "10 minutes, 1 hour" instead of "10 minutes, 1 hours", you need to do that manually too:
print '{} minute{}, {} hour{}'.format(minutes, 's' if minutes != 1 else '',
hours, 's' if minutes != 1 else '')
Or you may want to write an english_plural function to do the 's' bits for you, instead of repeating yourself.
From your comments, it sounds like you actually want to keep the days separate. That's even easier:
def convert_timedelta(duration):
days, seconds = duration.days, duration.seconds
hours = seconds // 3600
minutes = (seconds % 3600) // 60
seconds = (seconds % 60)
return days, hours, minutes, seconds
If you want to convert this to a single value to store in a database, then convert that single value back to format it, do this:
def dhms_to_seconds(days, hours, minutes, seconds):
return (((days * 24) + hours) * 60 + minutes) * 60 + seconds
def seconds_to_dhms(seconds):
days = seconds // (3600 * 24)
hours = (seconds // 3600) % 24
minutes = (seconds // 60) % 60
seconds = seconds % 60
return days, hours, minutes, seconds
So, putting it together:
def store_timedelta_in_database(thingy, duration):
seconds = dhms_to_seconds(*convert_timedelta(duration))
db.execute('INSERT INTO foo (thingy, duration) VALUES (?, ?)',
thingy, seconds)
db.commit()
def print_timedelta_from_database(thingy):
cur = db.execute('SELECT duration FROM foo WHERE thingy = ?', thingy)
seconds = int(cur.fetchone()[0])
days, hours, minutes, seconds = seconds_to_dhms(seconds)
print '{} took {} minutes, {} hours, {} days'.format(thingy, minutes, hours, days)
A datetime.timedelta corresponds to the difference between two dates, not a date itself. It's only expressed in terms of days, seconds, and microseconds, since larger time units like months and years don't decompose cleanly (is 30 days 1 month or 0.9677 months?).
If you want to convert a timedelta into hours and minutes, you can use the total_seconds() method to get the total number of seconds and then do some math:
x = datetime.timedelta(1, 5, 41038) # Interval of 1 day and 5.41038 seconds
secs = x.total_seconds()
hours = int(secs / 3600)
minutes = int(secs / 60) % 60
There is no need for custom helper functions if all we need is to print the string of the form [D day[s], ][H]H:MM:SS[.UUUUUU]. timedelta object supports str() operation that will do this. It works even in Python 2.6.
>>> from datetime import timedelta
>>> timedelta(seconds=90136)
datetime.timedelta(1, 3736)
>>> str(timedelta(seconds=90136))
'1 day, 1:02:16'
I don't think it's a good idea to caculate yourself.
If you just want a pretty output, just covert it into str with str() function or directly print() it.
And if there's further usage of the hours and minutes, you can parse it to datetime object use datetime.strptime()(and extract the time part with datetime.time() mehtod), for example:
import datetime
delta = datetime.timedelta(seconds=10000)
time_obj = datetime.datetime.strptime(str(delta),'%H:%M:%S').time()
Just use strftime :)
Something like that:
my_date = datetime.datetime(2013, 1, 7, 10, 31, 34, 243366, tzinfo=<UTC>)
print(my_date.strftime("%Y, %d %B"))
After edited your question to format timedelta, you could use:
def timedelta_tuple(timedelta_object):
return timedelta_object.days, timedelta_object.seconds//3600, (timedelta_object.seconds//60)%60
# Try this code
from datetime import timedelta
class TimeDelta(timedelta):
def __str__(self):
_times = super(TimeDelta, self).__str__().split(':')
if "," in _times[0]:
_hour = int(_times[0].split(',')[-1].strip())
if _hour:
_times[0] += " hours" if _hour > 1 else " hour"
else:
_times[0] = _times[0].split(',')[0]
else:
_hour = int(_times[0].strip())
if _hour:
_times[0] += " hours" if _hour > 1 else " hour"
else:
_times[0] = ""
_min = int(_times[1])
if _min:
_times[1] += " minutes" if _min > 1 else " minute"
else:
_times[1] = ""
_sec = int(_times[2])
if _sec:
_times[2] += " seconds" if _sec > 1 else " second"
else:
_times[2] = ""
return ", ".join([i for i in _times if i]).strip(" ,").title()
# Test
>>> str(TimeDelta(seconds=10))
'10 Seconds'
>>> str(TimeDelta(seconds=60))
'01 Minute'
>>> str(TimeDelta(seconds=90))
'01 Minute, 30 Seconds'
>>> str(TimeDelta(seconds=3000))
'50 Minutes'
>>> str(TimeDelta(seconds=3600))
'1 Hour'
>>> str(TimeDelta(seconds=3690))
'1 Hour, 01 Minute, 30 Seconds'
>>> str(TimeDelta(seconds=3660))
'1 Hour, 01 Minute'
>>> str(TimeDelta(seconds=3630))
'1 Hour, 30 Seconds'
>>> str(TimeDelta(seconds=3600*20))
'20 Hours'
>>> str(TimeDelta(seconds=3600*20 + 3000))
'20 Hours, 50 Minutes'
>>> str(TimeDelta(seconds=3600*20 + 3630))
'21 Hours, 30 Seconds'
>>> str(TimeDelta(seconds=3600*20 + 3660))
'21 Hours, 01 Minute'
>>> str(TimeDelta(seconds=3600*20 + 3690))
'21 Hours, 01 Minute, 30 Seconds'
>>> str(TimeDelta(seconds=3600*24))
'1 Day'
>>> str(TimeDelta(seconds=3600*24 + 10))
'1 Day, 10 Seconds'
>>> str(TimeDelta(seconds=3600*24 + 60))
'1 Day, 01 Minute'
>>> str(TimeDelta(seconds=3600*24 + 90))
'1 Day, 01 Minute, 30 Seconds'
>>> str(TimeDelta(seconds=3600*24 + 3000))
'1 Day, 50 Minutes'
>>> str(TimeDelta(seconds=3600*24 + 3600))
'1 Day, 1 Hour'
>>> str(TimeDelta(seconds=3600*24 + 3630))
'1 Day, 1 Hour, 30 Seconds'
>>> str(TimeDelta(seconds=3600*24 + 3660))
'1 Day, 1 Hour, 01 Minute'
>>> str(TimeDelta(seconds=3600*24 + 3690))
'1 Day, 1 Hour, 01 Minute, 30 Seconds'
>>> str(TimeDelta(seconds=3600*24*2))
'2 Days'
>>> str(TimeDelta(seconds=3600*24*2 + 9999))
'2 Days, 2 Hours, 46 Minutes, 39 Seconds'
I defined own helper function to convert timedelta object to 'HH:MM:SS' format - only hours, minutes and seconds, without changing hours to days.
def format_timedelta(td):
hours, remainder = divmod(td.total_seconds(), 3600)
minutes, seconds = divmod(remainder, 60)
hours, minutes, seconds = int(hours), int(minutes), int(seconds)
if hours < 10:
hours = '0%s' % int(hours)
if minutes < 10:
minutes = '0%s' % minutes
if seconds < 10:
seconds = '0%s' % seconds
return '%s:%s:%s' % (hours, minutes, seconds)
An alternative for this (older) question is to create a relative time from a timedelta converted to seconds. This can be accomplished using the time.gmtime(...) method that accepts seconds since the epoch:
>>> time.strftime("%H:%M:%S",time.gmtime(36901)) # secs = 36901
'10:15:01'
And, that's it! (NOTE: Here's a link to format specifiers for time.strftime() so the difference can be truncated to any units, as needed. ...)
Notably, this technique is also a great way to tell if your current time zone is actually in daylight savings time or not. (It provides an offset of 0 or 1 hours meaning it can be interpreted basically as a boolean.)
import datetime
import pytz
import time
pacific=pytz.timezone('US/Pacific')
now=datetime.datetime.now()
# pacific.dst(now).total_seconds() yields 3600 secs. [aka 1 hour]
time.strftime("%-H", time.gmtime(pacific.dst(now).total_seconds()))
'1'
This can be rendered to a method is_standard_time(...) where 1 means true and 0 means false.
Do you want to print the date in that format? This is the Python documentation: http://docs.python.org/2/library/datetime.html#strftime-strptime-behavior
>>> a = datetime.datetime(2013, 1, 7, 10, 31, 34, 243366)
>>> print a.strftime('%Y %d %B, %M:%S%p')
>>> 2013 07 January, 31:34AM
For the timedelta:
>>> a = datetime.timedelta(0,5,41038)
>>> print '%s seconds, %s microseconds' % (a.seconds, a.microseconds)
But please notice, you should make sure it has the related value. For the above cases, it doesn't have the hours and minute values, and you should calculate from the seconds.
datetime.timedelta(hours=1, minutes=10)
#python 2.7
Consider the following snippet:
import datetime
print(datetime.datetime.now() - datetime.datetime.now())
On my Python 2.7.8 under x86_64 Linux, I am getting -1 day, 23:59:59.999940. Why could be that?
See the datetime.timedelta documenation:
Note that normalization of negative values may be surprising at first. For example,
>>> from datetime import timedelta
>>> d = timedelta(microseconds=-1)
>>> (d.days, d.seconds, d.microseconds) (-1, 86399, 999999)
You have a negative timedelta, and normalisation always uses positive numbers for seconds and microseconds.
To store a negative delta then where only the .days attribute can store negative values, you end up with a -1 day plus a positive amount of seconds and microseconds:
>>> import datetime
>>> td = datetime.datetime.now() - datetime.datetime.now()
>>> print(td)
-1 day, 23:59:59.999988
>>> td
datetime.timedelta(-1, 86399, 999988)
>>> td.days
-1
>>> td.seconds
86399
>>> td.microseconds
999988
>>> (24 * 60 * 60) # 1 day in seconds
86400
>>> (24 * 60 * 60) - td.seconds
1
>>> 1000000 - td.microseconds
12
So the timedelta really represents -12 microseconds, but expressed relative to -1 day that becomes +86399 seconds and +999988 microseconds.
This question already has answers here:
How do I check the difference, in seconds, between two dates?
(7 answers)
Closed 8 years ago.
I need to check if some date and now arent' different more than in 18 hours:
dt = parser.parse("some date 123") #working well
diff = datetime.datetime.now() - dt
print "datetime.datetime.now() - dt = %s" % diff # 31 days, 0:08:04.882498 -- correct
print "datetime.datetime.now() - dt seconds = %s" % diff.seconds # 484 -- too
(datetime.datetime.now() - dt).seconds / 3600) < 18 # returns True always
As you can see, even though the dates are different in 31 days, the amount of seconds if very little which doesn't allow me to calculate the amount of hours. Why is it so small? Should it be x * 60 * 60 * amount_of_days? And how can I do what I want?
seconds is returning just the number of seconds, not the total number of seconds, for that you can use timedelta.total_seconds.
You may try this:
from datetime import date
date0 = date(2014, 9, 07)
date1 = date(2014, 9, 05)
diff = date0 - date1
print diff.days * 24
Also check How do I check the difference, in seconds, between two dates?
or
>>> from datetime import datetime
>>> date0 = datetime(2014,09,07,0,0,0)
>>> date1 = datetime(2014,09,01,23,59,59)
>>> date0-date1
datetime.timedelta(6, 1)
>>> (date0-date1).days * 24
144
What's the best way to find the time until a date. I would like to know the years, months, days and hours.
I was hoping somebody had a nice function. I want to do something like: This comment was posted 2month and three days ago or this comment was posted 1year 5months ago.
datetime module, datetime and timedelta objects, it will give you days and seconds.
In [5]: datetime.datetime(2009, 10, 19) - datetime.datetime.now()
Out[5]: datetime.timedelta(2, 5274, 16000)
In [6]: td = datetime.datetime(2009, 10, 19) - datetime.datetime.now()
In [7]: td.days
Out[7]: 2
In [8]: td.seconds
Out[8]: 5262
You should use dateutil.relativedelta.
from dateutil.relativedelta import relativedelta
import datetime
today = datetime.date.today()
rd = relativedelta(today, datetime.date(2001,1,1))
print "comment created %(years)d years, %(months)d months, %(days)d days ago" % rd.__dict__
Let's asume you have the future datetime in a variable named eta:
(eta - datetime.datetime.now()).total_seconds()
Datetime difference results in a timedelta object, which happens to implement a method named total_seconds. That's it :)
I was looking for something more like this ... which took some hard work to find.
import datetime
SECOND = 1
MINUTE = 60 * SECOND
HOUR = 60 * MINUTE
DAY = 24 * HOUR
MONTH = 30 * DAY
def get_relative_time(dt):
now = datetime.datetime.now()
delta_time = dt - now
delta = delta_time.days * DAY + delta_time.seconds
minutes = delta / MINUTE
hours = delta / HOUR
days = delta / DAY
if delta < 0:
return "already happened"
if delta < 1 * MINUTE:
if delta == 1:
return "one second to go"
else:
return str(delta) + " seconds to go"
if delta < 2 * MINUTE:
return "a minute ago"
if delta < 45 * MINUTE:
return str(minutes) + " minutes to go"
if delta < 90 * MINUTE:
return "an hour ago"
if delta < 24 * HOUR:
return str(hours) + " hours to go"
if delta < 48 * HOUR:
return "yesterday"
if delta < 30 * DAY:
return str(days) + " days to go"
if delta < 12 * MONTH:
months = delta / MONTH
if months <= 1:
return "one month to go"
else:
return str(months) + " months to go"
else:
years = days / 365.0
if years <= 1:
return "one year to go"
else:
return str(years) + " years to go"
may be you want something like this:
import datetime
today = datetime.date.today()
futdate = datetime.date(2016, 8, 10)
now = datetime.datetime.now()
mnight = now.replace(hour=0, minute=0, second=0, microsecond=0)
seconds = (mnight - now).seconds
days = (futdate - today).days
hms = str(datetime.timedelta(seconds=seconds))
print ("%d days %s" % (days, hms))