вычесть два раза в Python


117

У меня два datetime.timeзначения, exitи enterя хочу сделать что-то вроде:

duration = exit - enter

Однако я получаю эту ошибку:

TypeError: неподдерживаемые типы операндов для -: 'datetime.time' и 'datetime.time

Как мне это сделать правильно? Одно из возможных решений - преобразовать timeпеременные в datetimeпеременные, а затем вычесть их, но я уверен, что у вас, ребята, должен быть лучший и более чистый способ.

Ответы:


91

Попробуй это:

from datetime import datetime, date

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

combine строит дату и время, которые можно вычесть.


2
Для точки @IgnacioVazquez-Abrams можно было бы использовать, скажем, datetime(1,1,1,0,0,0)вместо date.today().
Akavall 07

25
Не называйте a datetime exit, поскольку exitэто встроенная функция.
orokusaki

1
используя python 2.7, у меня нет combineметода в моем datetimeмодуле: AttributeError: 'module' object has no attribute 'combine'
mtoloo

6
mtoloo: Есть datetimeмодуль и datetimeвнутри него есть объект. У объекта внутри есть combineметод. Если вы просто импортируете datetime(например:) import datetime, то вам нужно сделать это позже datetime.datetime.combine.
gruszczy

1
Есть очень редкий случай, когда вы вызываете эту функцию в какое-то время, например, 23: 59: 59: 9999. В этом случае date.today() предыдущее и date.today()позднее вернут разные значения. Лучше присвоить значение date.today()переменной.
ramwin

44

Использование:

from datetime import datetime, date

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

Использование date.minнемного более лаконично и работает даже в полночь.

Это может быть не так, date.today()это может привести к неожиданным результатам, если первый вызов произойдет в 23:59:59, а следующий - в 00:00:00.


1
Согласен с тобой.
ramwin

27

вместо использования времени попробуйте 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)

2
Спасибо. Это очень чисто и лучше, чем все ответы здесь - stackoverflow.com/questions/3096953/…
Pushpak Dagade

8

datetime.timeне поддерживает это, потому что вычитать время таким образом почти бессмысленно. Используйте полный, datetime.datetimeесли хотите.


53
Если вы знаете из своего домена, что два datetime.timeобъекта aи bотносятся к одному и тому же дню, и что b > a, тогда операция b - aимеет идеальный смысл.
swalog 05

4
Даже если они не в один и тот же день, это все равно имеет смысл. По крайней мере, столько же здравого смысла, сколько arctan(0) = (0, pi, 2pi, ...), но нас просто не волнует ни одно из этих значений после первого. Таким образом, 4:00 - 20:00это 8:00- это также ( 32:00, 56:00, ...), но кого это волнует?
naught101


7
Более того, Python даже не остается последовательным. Если a - b не имеет смысла для двух временных объектов, тогда как это, что a> b или a <b ведет себя так же? Сравнение уже предполагается в тот же день, иначе оно полностью не выполняется. Поскольку предположение сделано для сравнения, вполне логично сделать то же предположение для разностных операций.
Шон

1
Сказать, что это бессмысленно - субъективно, но я понимаю, откуда вы. Сложение двух раз кажется мне бессмысленным представлением. Я думаю, что вычитание двух значений времени должно вернуть timedelta. Если эта timedelta окажется отрицательной, пусть будет так. Я хочу знать, почему python не может добавлять или вычитать timedelta из времени, чтобы вернуть новое значение времени.
aj.toulan 04

7

У вас есть два объекта datetime.time, поэтому вы просто создаете два timedelta, используя datetime.timedetla, а затем вычитаете, как сейчас, используя операнд "-". Ниже приведен пример способа двухкратного вычитания без использования 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

разница_delta - это ваша разница, которую вы можете использовать по своим причинам.


Можно ли преобразовать объект timedelta обратно в datetime? Я имею в виду, что у нас есть difference_delta .seconds (), есть ли способ вернуть объект datetime или time? Thx
dejdej

Да. datetime.min + delta
sourcedelica

6

Библиотека python timedelta должна делать то, что вам нужно. A timedeltaвозвращается, когда вы вычитаете два datetimeэкземпляра.

import datetime
dt_started = datetime.datetime.utcnow()

# do some stuff

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

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

3

datetime.time не может этого сделать - но вы могли бы использовать datetime.datetime.now()

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

2

У меня была аналогичная ситуация, когда мы с вами использовали внешнюю библиотеку под названием arrow .

Вот как это выглядит:

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

1
Здесь вы просто демонстрируете вычитание полных объектов datetime, а не времени суток, как в исходном вопросе
kleptog
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.