181

I have two datetime.time values, exit and enter and I want to do something like:

duration = exit - enter

However, I get this error:

TypeError: unsupported operand type(s) for -: 'datetime.time' and 'datetime.time

How do I do this correctly? One possible solution is converting the time variables to datetime variables and then subtruct, but I'm sure you guys must have a better and cleaner way.

0

12 Answers 12

130

Try this:

from datetime import datetime, date

datetime.combine(date.today(), exit) - datetime.combine(date.today(), enter)

combine builds a datetime, that can be subtracted.

Sign up to request clarification or add additional context in comments.

7 Comments

To @IgnacioVazquez-Abrams point, one could use, say,datetime(1,1,1,0,0,0) instead of date.today().
Don't name a datetime exit, since exit is a built-in function.
using python 2.7, I don't have combine method in my datetime module: AttributeError: 'module' object has no attribute 'combine'
mtoloo: There is datetime module and it has a datetime object inside. The object inside has combine method. If you are simply importing datetime (like this: import datetime), then what you need to do later is this datetime.datetime.combine.
There is a very rare case when you call this function at some time like 23:59:59:9999. In that case, the date.today() before and the date.today() later will return a different value. It would be better to give the value date.today() to a variable.
|
72

Use:

from datetime import datetime, date

duration = datetime.combine(date.min, end) - datetime.combine(date.min, beginning)

Using date.min is a bit more concise and works even at midnight.

This might not be the case with date.today() that might return unexpected results if the first call happens at 23:59:59 and the next one at 00:00:00.

Comments

63

instead of using time try timedelta:

from datetime import timedelta

t1 = timedelta(hours=7, minutes=36)
t2 = timedelta(hours=11, minutes=32)
t3 = timedelta(hours=13, minutes=7)
t4 = timedelta(hours=21, minutes=0)

arrival = t2 - t1
lunch = (t3 - t2 - timedelta(hours=1))
departure = t4 - t3

print(arrival, lunch, departure)

3 Comments

Thanks. This is very clean and better than all the answers here - stackoverflow.com/questions/3096953/…
Note that timedelta conceptually represents a span of time, not a time of day.
Note thattimedelta conceptually represents a span of time and not a point in time, which makes it the correct thing to use here, as we are implicitly talking about the time that has passed (a delta of time) since the start of the day (a point in time).
11

The python timedelta library should do what you need. A timedelta is returned when you subtract two datetime instances.

import datetime
dt_started = datetime.datetime.utcnow()

# do some stuff

dt_ended = datetime.datetime.utcnow()
print((dt_ended - dt_started).total_seconds())

Comments

10

You have two datetime.time objects so for that you just create two timedelta using datetime.timedetla and then substract as you do right now using "-" operand. Following is the example way to substract two times without using datetime.

enter = datetime.time(hour=1)  # Example enter time
exit = datetime.time(hour=2)  # Example start time
enter_delta = datetime.timedelta(hours=enter.hour, minutes=enter.minute, seconds=enter.second)
exit_delta = datetime.timedelta(hours=exit.hour, minutes=exit.minute, seconds=exit.second)
difference_delta = exit_delta - enter_delta

difference_delta is your difference which you can use for your reasons.

2 Comments

It is possible to convert the timedelta object back to datetime ? I mean we have difference_delta .seconds(), is there any way to get back a datetime or time object ? Thx
Yes. datetime.min + delta
7

datetime.time can not do it - But you could use datetime.datetime.now()

start = datetime.datetime.now()
sleep(10)
end = datetime.datetime.now()
duration = end - start

Comments

5

timedelta accepts negative(-) time values. so it could be simple as below.

Answer (single line, without date combine)

datetime.timedelta(hours=exit.hour-enter.hour, minutes=exit.minute-enter.minute)

Run test

import datetime

enter = datetime.time(hour=1, minute=30)
exit = datetime.time(hour=2, minute=0)
duration = datetime.timedelta(hours=exit.hour-enter.hour, minutes=exit.minute-enter.minute)

>>> duration
datetime.timedelta(seconds=1800)

Comments

4

datetime.time does not support this, because it's nigh meaningless to subtract times in this manner. Use a full datetime.datetime if you want to do this.

5 Comments

If you know from your domain that two datetime.time objects a and b are from the same day, and that b > a, then the operation b - a has perfect meaning.
Even if they aren't the same day, it still makes fine sense. At least as much sense as arctan(0) = (0, pi, 2pi, ...), but we just don't care about any of those values after the first. So, 4:00 - 20:00 is 8:00 - it's also (32:00, 56:00, ... ), but who cares?
Furthermore, Python doesn't even stay consistent. If a - b is meaningless for two time objects, then how it that a > b or a < b behaves as it does? The comparison is already assuming same day, otherwise it is completely broken. Since the assumption is made for comparison, it is entirely consistent to make the same assumption for difference operations.
Saying it's meaningless is subjective, but I see where you're coming from. Adding two times together seems to be a meaningless representation to me. I think subtracting two time values should return a timedelta. If that timedelta happens to be negative, so be it. What I want to know is why python can't add or subtract a timedelta from a time to return a new time value.
4
import datetime

def diff_times_in_seconds(t1, t2):
    # caveat emptor - assumes t1 & t2 are python times, on the same day and t2 is after t1
    h1, m1, s1 = t1.hour, t1.minute, t1.second
    h2, m2, s2 = t2.hour, t2.minute, t2.second
    t1_secs = s1 + 60 * (m1 + 60*h1)
    t2_secs = s2 + 60 * (m2 + 60*h2)
    return( t2_secs - t1_secs)

# using it
diff_times_in_seconds( datetime.datetime.strptime( "13:23:34", '%H:%M:%S').time(),datetime.datetime.strptime( "14:02:39", '%H:%M:%S').time())

Comments

2

I had similar situation as you and I ended up with using external library called arrow.

Here is what it looks like:

>>> import arrow
>>> enter = arrow.get('12:30:45', 'HH:mm:ss')
>>> exit = arrow.now()
>>> duration = exit - enter
>>> duration
datetime.timedelta(736225, 14377, 757451)

1 Comment

Here you are just demonstrating subtracting complete datetime objects, not times-of-day as in the original question
2
import time
from datetime import datetime

def calcTime(enter,exit):
    format="%H:%M:%S"
    #Parsing the time to str and taking only the hour,minute,second 
    #(without miliseconds)
    enterStr = str(enter).split(".")[0]
    exitStr = str(exit).split(".")[0]
    #Creating enter and exit time objects from str in the format (H:M:S)
    enterTime = datetime.strptime(enterStr, format)
    exitTime = datetime.strptime(exitStr, format)
    return exitTime - enterTime

enter = datetime.today().time()
#Sleeping for 5 seconds before initializing the exit variable
time.sleep(5)
exit = datetime.today().time()
duration = calcTime(enter,exit)
print(f"Duration is {duration} (Hours:Minutes:Seconds)")
#Output: Duration is 0:00:05 (Hours:Minutes:Seconds)

If it is helpful, you can use the calcTime function as shown.

Comments

0

I think the reason for Time objects being defined this way is that the result of timeA - timeB depends on the date, as we could hit a daylight saving boundary.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.