240

I have two times, a start and a stop time, in the format of 10:33:26 (HH:MM:SS). I need the difference between the two times. I've been looking through documentation for Python and searching online and I would imagine it would have something to do with the datetime and/or time modules. I can't get it to work properly and keep finding only how to do this when a date is involved.

Ultimately, I need to calculate the averages of multiple time durations. I got the time differences to work and I'm storing them in a list. I now need to calculate the average. I'm using regular expressions to parse out the original times and then doing the differences.

For the averaging, should I convert to seconds and then average?

DocZerø
  • 8,037
  • 11
  • 38
  • 66
Hannah
  • 2,805
  • 4
  • 19
  • 10

15 Answers15

286

Yes, definitely datetime is what you need here. Specifically, the datetime.strptime() method, which parses a string into a datetime object.

from datetime import datetime
s1 = '10:33:26'
s2 = '11:15:49' # for example
FMT = '%H:%M:%S'
tdelta = datetime.strptime(s2, FMT) - datetime.strptime(s1, FMT)

That gets you a timedelta object that contains the difference between the two times. You can do whatever you want with that, e.g. converting it to seconds or adding it to another datetime.

This will return a negative result if the end time is earlier than the start time, for example s1 = 12:00:00 and s2 = 05:00:00. If you want the code to assume the interval crosses midnight in this case (i.e. it should assume the end time is never earlier than the start time), you can add the following lines to the above code:

if tdelta.days < 0:
    tdelta = timedelta(
        days=0,
        seconds=tdelta.seconds,
        microseconds=tdelta.microseconds
    )

(of course you need to include from datetime import timedelta somewhere). Thanks to J.F. Sebastian for pointing out this use case.

David Z
  • 128,184
  • 27
  • 255
  • 279
  • 1
    Negative time hack will not work when `days= -2` and above in the tdelta object. – CKM Feb 09 '17 at 06:30
  • 2
    @chandresh Yes, but `days` can never be -2 or less without there being additional information (specifically, dates) beyond what is described in the question. So that situation is not relevant here. – David Z Feb 09 '17 at 06:31
  • 7
    Hint: To get the time delta in seconds you have to call `tdelta.total_seconds()`. – scai Dec 10 '18 at 15:39
  • 1
    `datetime.strptime` returns a `datetime` object (not a `time` object), in Python 3.9 https://docs.python.org/3/library/datetime.html#datetime.datetime.strptime – Ran Feldesh Mar 15 '21 at 22:33
  • I don't remember for sure, but I have a feeling I meant "time object" in the sense of "an object that represents the time", not "an object of type `time`". That's why it's not code-formatted. Still, couldn't hurt to clarify; I'll edit shortly. – David Z Mar 15 '21 at 22:39
212

Try this -- it's efficient for timing short-term events. If something takes more than an hour, then the final display probably will want some friendly formatting.

import time
start = time.time()

time.sleep(10)  # or do something more productive

done = time.time()
elapsed = done - start
print(elapsed)

The time difference is returned as the number of elapsed seconds.

BuvinJ
  • 10,221
  • 5
  • 83
  • 96
Bill Grava
  • 2,245
  • 1
  • 12
  • 2
  • 11
    Why wasn't this the accepted answer? It's simple, it gives a value which can be compared with something (did my command take more than 2.5 seconds to execute?) and it works in v2.7 – Mawg says reinstate Monica Jul 05 '16 at 10:09
  • 16
    @Mawg Because it doesn't answer the OPs question. He was asking how to compare two different times he already has in a certain format, not how to generate them by timing an event in his code. They're pretty different problems. – Natsukane Jan 14 '17 at 15:48
  • 3
    You shouldn't use this; use monotonic time instead (`time.monotonic()` in Python). `time.time()` can go backwards (e.g., when the time on the machine changes, including NTP corrections). – nemequ Nov 14 '17 at 19:54
  • 3
    Irrelevant to question – patricktokeeffe Dec 13 '17 at 21:13
22

Here's a solution that supports finding the difference even if the end time is less than the start time (over midnight interval) such as 23:55:00-00:25:00 (a half an hour duration):

#!/usr/bin/env python
from datetime import datetime, time as datetime_time, timedelta

def time_diff(start, end):
    if isinstance(start, datetime_time): # convert to datetime
        assert isinstance(end, datetime_time)
        start, end = [datetime.combine(datetime.min, t) for t in [start, end]]
    if start <= end: # e.g., 10:33:26-11:15:49
        return end - start
    else: # end < start e.g., 23:55:00-00:25:00
        end += timedelta(1) # +day
        assert end > start
        return end - start

for time_range in ['10:33:26-11:15:49', '23:55:00-00:25:00']:
    s, e = [datetime.strptime(t, '%H:%M:%S') for t in time_range.split('-')]
    print(time_diff(s, e))
    assert time_diff(s, e) == time_diff(s.time(), e.time())

Output

0:42:23
0:30:00

time_diff() returns a timedelta object that you can pass (as a part of the sequence) to a mean() function directly e.g.:

#!/usr/bin/env python
from datetime import timedelta

def mean(data, start=timedelta(0)):
    """Find arithmetic average."""
    return sum(data, start) / len(data)

data = [timedelta(minutes=42, seconds=23), # 0:42:23
        timedelta(minutes=30)] # 0:30:00
print(repr(mean(data)))
# -> datetime.timedelta(0, 2171, 500000) # days, seconds, microseconds

The mean() result is also timedelta() object that you can convert to seconds (td.total_seconds() method (since Python 2.7)), hours (td / timedelta(hours=1) (Python 3)), etc.

jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • 1
    @J.F. I wonder if statistics mean and variance functions work directly with timedelta object now? Any thought on that? Also, any help to compute the variance of timedelta objects will be useful. – CKM Feb 09 '17 at 10:04
  • 1
    @chandresh: it is not supported. You could convert to seconds/microseconds for calculating mathematical statistics of timedeltas. – jfs Feb 09 '17 at 15:02
  • This is great, but if you would like to get the time difference between 13 and 12 it will be 23 hours, which isn't in my case. In my case it should be 1 hour. An easy way to solve this is to get the min while flipping the start and end. ``` min( time_diff(time1, time2), time_diff(time2, time1) ) ``` – Ysrninja Mar 17 '22 at 14:13
  • @Ysrninja: if `start=13` and `end=12` then `23` hours is expected (`start` is earlier than `end`). To get `1` hour: `abs(dt1 - dt2)` – jfs Mar 17 '22 at 14:41
16

This site says to try:

import datetime as dt
start="09:35:23"
end="10:23:00"
start_dt = dt.datetime.strptime(start, '%H:%M:%S')
end_dt = dt.datetime.strptime(end, '%H:%M:%S')
diff = (end_dt - start_dt) 
diff.seconds/60 

This forum uses time.mktime()

Tim McNamara
  • 18,019
  • 4
  • 52
  • 83
Kyra
  • 5,129
  • 5
  • 35
  • 55
  • 1
    Make sure that if you use %p (AM/PM) that you use %I (12 hours) instead of %H (24 hours): https://docs.python.org/2/library/datetime.html#strftime-strptime-behavior – Andrew Jun 28 '19 at 14:57
14

Structure that represent time difference in Python is called timedelta. If you have start_time and end_time as datetime types you can calculate the difference using - operator like:

diff = end_time - start_time

you should do this before converting to particualr string format (eg. before start_time.strftime(...)). In case you have already string representation you need to convert it back to time/datetime by using strptime method.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
dzida
  • 8,854
  • 2
  • 36
  • 57
14

I like how this guy does it — https://amalgjose.com/2015/02/19/python-code-for-calculating-the-difference-between-two-time-stamps. Not sure if it has some cons.

But looks neat for me :)

from datetime import datetime
from dateutil.relativedelta import relativedelta

t_a = datetime.now()
t_b = datetime.now()

def diff(t_a, t_b):
    t_diff = relativedelta(t_b, t_a)  # later/end time comes first!
    return '{h}h {m}m {s}s'.format(h=t_diff.hours, m=t_diff.minutes, s=t_diff.seconds)

Regarding to the question you still need to use datetime.strptime() as others said earlier.

Community
  • 1
  • 1
antonavy
  • 480
  • 6
  • 11
9

Try this

import datetime
import time
start_time = datetime.datetime.now().time().strftime('%H:%M:%S')
time.sleep(5)
end_time = datetime.datetime.now().time().strftime('%H:%M:%S')
total_time=(datetime.datetime.strptime(end_time,'%H:%M:%S') - datetime.datetime.strptime(start_time,'%H:%M:%S'))
print total_time

OUTPUT :

0:00:05
Dipnesh Parakhiya
  • 516
  • 1
  • 5
  • 17
7
import datetime as dt
from dateutil.relativedelta import relativedelta

start = "09:35:23"
end = "10:23:00"
start_dt = dt.datetime.strptime(start, "%H:%M:%S")
end_dt = dt.datetime.strptime(end, "%H:%M:%S")
timedelta_obj = relativedelta(start_dt, end_dt)
print(
    timedelta_obj.years,
    timedelta_obj.months,
    timedelta_obj.days,
    timedelta_obj.hours,
    timedelta_obj.minutes,
    timedelta_obj.seconds,
)

result: 0 0 0 0 -47 -37

hu wentao
  • 131
  • 1
  • 5
3

Both time and datetime have a date component.

Normally if you are just dealing with the time part you'd supply a default date. If you are just interested in the difference and know that both times are on the same day then construct a datetime for each with the day set to today and subtract the start from the stop time to get the interval (timedelta).

ChrisF
  • 134,786
  • 31
  • 255
  • 325
3

Take a look at the datetime module and the timedelta objects. You should end up constructing a datetime object for the start and stop times, and when you subtract them, you get a timedelta.

Pierce
  • 346
  • 1
  • 4
3

you can use pendulum:

import pendulum

t1 = pendulum.parse("10:33:26")
t2 = pendulum.parse("10:43:36")

period = t2 - t1

print(period.seconds)

would output:

610
Alon Gouldman
  • 3,025
  • 26
  • 29
2
    import datetime
    
    day = int(input("day[1,2,3,..31]: "))
    month = int(input("Month[1,2,3,...12]: "))
    year = int(input("year[0~2020]: "))
    start_date = datetime.date(year, month, day)
    
    day = int(input("day[1,2,3,..31]: "))
    month = int(input("Month[1,2,3,...12]: "))
    year = int(input("year[0~2020]: "))
    end_date = datetime.date(year, month, day)
    
    time_difference = end_date - start_date
    age = time_difference.days
    print("Total days: " + str(age))
KittoMi
  • 411
  • 5
  • 19
1

Concise if you are just interested in the time elapsed that is under 24 hours. You can format the output as needed in the return statement :

import datetime
def elapsed_interval(start,end):
    elapsed = end - start
    min,secs=divmod(elapsed.days * 86400 + elapsed.seconds, 60)
    hour, minutes = divmod(min, 60)
    return '%.2d:%.2d:%.2d' % (hour,minutes,secs)

if __name__ == '__main__':
    time_start=datetime.datetime.now()
    """ do your process """
    time_end=datetime.datetime.now()
    total_time=elapsed_interval(time_start,time_end)
user2654744
  • 438
  • 5
  • 8
1

Usually, you have more than one case to deal with and perhaps have it in a pd.DataFrame(data) format. Then:

import pandas as pd

df['duration'] = pd.to_datetime(df['stop time']) - pd.to_datetime(df['start time'])

gives you the time difference without any manual conversion.

Taken from Convert DataFrame column type from string to datetime.

If you are lazy and do not mind the overhead of pandas, then you could do this even for just one entry.

questionto42
  • 7,175
  • 4
  • 57
  • 90
0

Here is the code if the string contains days also [-1 day 32:43:02]:

print(
    (int(time.replace('-', '').split(' ')[0]) * 24) * 60 
    + (int(time.split(' ')[-1].split(':')[0]) * 60)
    + int(time.split(' ')[-1].split(':')[1])
)
vvvvv
  • 25,404
  • 19
  • 49
  • 81
Shrey
  • 9
  • 1