Каков стандартный способ добавления N секунд в datetime.time в Python?

Учитывая значение datetime.time в Python, существует ли стандартный способ добавить к нему целое число секунд, так что 11:34:59 + 3 = 11:35:02, например?

Эти очевидные идеи не работают:

>>> datetime.time(11, 34, 59) + 3
TypeError: unsupported operand type(s) for +: 'datetime.time' and 'int'
>>> datetime.time(11, 34, 59) + datetime.timedelta(0, 3)
TypeError: unsupported operand type(s) for +: 'datetime.time' and 'datetime.timedelta'
>>> datetime.time(11, 34, 59) + datetime.time(0, 0, 3)
TypeError: unsupported operand type(s) for +: 'datetime.time' and 'datetime.time'

В конце я написал такие функции:

def add_secs_to_time(timeval, secs_to_add):
    secs = timeval.hour * 3600 + timeval.minute * 60 + timeval.second
    secs += secs_to_add
    return datetime.time(secs // 3600, (secs % 3600) // 60, secs % 60)

Я не могу не думать, что мне не хватает более легкого способа сделать это, хотя.

Связанные

Ответ 1

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

Например:

import datetime
a = datetime.datetime(100,1,1,11,34,59)
b = a + datetime.timedelta(0,3) # days, seconds, then other fields.
print a.time()
print b.time()

приводит к двум значениям, разделенным на три секунды:

11:34:59
11:35:02

Вы также можете выбрать более читаемый

b = a + datetime.timedelta(seconds=3)

если вы так склонны.


Если вы выполняете функцию, которая может это сделать, вы можете использовать addSecs ниже:

import datetime

def addSecs(tm, secs):
    fulldate = datetime.datetime(100, 1, 1, tm.hour, tm.minute, tm.second)
    fulldate = fulldate + datetime.timedelta(seconds=secs)
    return fulldate.time()

a = datetime.datetime.now().time()
b = addSecs(a, 300)
print a
print b

Выводится:

 09:11:55.775695
 09:16:55

Ответ 2

Как заявили другие, вы можете просто использовать полные объекты datetime:

sometime = get_some_time() # the time to which you want to add 3 seconds
later = (datetime.combine(date.today(), sometime) + timedelta(seconds=3)).time()

Однако, я думаю, это стоит объяснить, почему требуются полные объекты datetime. Подумайте, что произойдет, если я добавлю 2 часа до 11 вечера. Какое правильное поведение? Исключение, потому что у вас не может быть времени больше 23:59? Должен ли он обернуться вокруг?

Различные программисты будут ожидать разные вещи, поэтому, какой бы результат они ни выбрали, это удивит многих людей. Хуже того, программисты пишут код, который отлично работал, когда они сначала тестировали его, а затем прерывали его, делая что-то неожиданное. Это очень плохо, поэтому вам не разрешено добавлять объекты timedelta к объектам времени.

Ответ 3

Одна мелочь, может добавить ясность, чтобы переопределить значение по умолчанию в секундах

>>> b = a + datetime.timedelta(seconds=3000)
>>> b
datetime.datetime(1, 1, 1, 12, 24, 59)

Ответ 4

Благодаря @Pax Diablo, @bvmou и @Arachnid за предложение использовать полные даты по всему миру. Если мне нужно принимать объекты datetime.time из внешнего источника, то это кажется альтернативной функцией add_secs_to_time():

def add_secs_to_time(timeval, secs_to_add):
    dummy_date = datetime.date(1, 1, 1)
    full_datetime = datetime.datetime.combine(dummy_date, timeval)
    added_datetime = full_datetime + datetime.timedelta(seconds=secs_to_add)
    return added_datetime.time()

Этот подробный код может быть сжат в этот однострочный файл:

(datetime.datetime.combine(datetime.date(1, 1, 1), timeval) + datetime.timedelta(seconds=secs_to_add)).time()

но я думаю, что мне все равно понадобилось бы обернуть это в функции для ясности кода.

Ответ 5

Если стоит добавить еще один файл/зависимость в ваш проект, я только что написал крошечный маленький класс, который расширяет datetime.time возможностью выполнять арифметику. Когда вы выходите после полуночи, оно оборачивается вокруг нуля. Теперь "Сколько времени будет через 24 часа" имеет множество angular случаев, включая переход на летнее время, дополнительные секунды, исторические изменения часового пояса и т.д. Но иногда вам действительно нужен простой случай, и вот что это будет делать.

Ваш пример будет написан:

>>> import datetime
>>> import nptime
>>> nptime.nptime(11, 34, 59) + datetime.timedelta(0, 3)
nptime(11, 35, 2)

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

Он доступен из PyPi как nptime ("непедантичное время") или на GitHub: https://github.com/tgs/nptime

Ответ 6

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

Существует timedelta класс для манипуляций с датой и временем. datetime минус datetime дает timedelta, datetime плюс timedelta дает datetime, два объекта datetime не могут быть добавлены, хотя два timedelta могут.

Создайте объект timedelta сколько секунд вы хотите добавить, и добавьте его в объект datetime:

>>> from datetime import datetime, timedelta
>>> t = datetime.now() + timedelta(seconds=3000)
>>> print(t)
datetime.datetime(2018, 1, 17, 21, 47, 13, 90244)

В C++ есть такая же концепция: std::chrono::duration.

Ответ 7

Для полноты картины, вот способ сделать это с помощью arrow (лучшие даты и время для Python):

sometime = arrow.now()
abitlater = sometime.shift(seconds=3)

Ответ 8

Попробуйте добавить datetime.datetime к datetime.timedelta. Если вам нужна только часть времени, вы можете вызвать метод time() для результирующего объекта datetime.datetime, чтобы получить его.

Ответ 9

Старый вопрос, но я решил добавить функцию, которая обрабатывает часовые пояса. Ключевые части передают атрибут tzinfo объекта datetime.time в комбинат, а затем используют timetz() вместо time() в итоговой фиктивной дате и времени. Этот ответ частично вдохновлен другими ответами здесь.

def add_timedelta_to_time(t, td):
    """Add a timedelta object to a time object using a dummy datetime.

    :param t: datetime.time object.
    :param td: datetime.timedelta object.

    :returns: datetime.time object, representing the result of t + td.

    NOTE: Using a gigantic td may result in an overflow. You've been
    warned.
    """
    # Create a dummy date object.
    dummy_date = date(year=100, month=1, day=1)

    # Combine the dummy date with the given time.
    dummy_datetime = datetime.combine(date=dummy_date, time=t, tzinfo=t.tzinfo)

    # Add the timedelta to the dummy datetime.
    new_datetime = dummy_datetime + td

    # Return the resulting time, including timezone information.
    return new_datetime.timetz()

А вот класс действительно простых тестовых примеров (с использованием встроенного unittest):

import unittest
from datetime import datetime, timezone, timedelta, time

class AddTimedeltaToTimeTestCase(unittest.TestCase):
    """Test add_timedelta_to_time."""

    def test_wraps(self):
        t = time(hour=23, minute=59)
        td = timedelta(minutes=2)
        t_expected = time(hour=0, minute=1)
        t_actual = add_timedelta_to_time(t=t, td=td)
        self.assertEqual(t_expected, t_actual)

    def test_tz(self):
        t = time(hour=4, minute=16, tzinfo=timezone.utc)
        td = timedelta(hours=10, minutes=4)
        t_expected = time(hour=14, minute=20, tzinfo=timezone.utc)
        t_actual = add_timedelta_to_time(t=t, td=td)
        self.assertEqual(t_expected, t_actual)


if __name__ == '__main__':
    unittest.main()