Каков стандартный способ добавить 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)

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

Связанный

связанная проблема Python: datetime.time поддержка "+" и "-"

jfs 29.12.2014 04:21
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
418
1
387 775
10
Перейти к ответу Данный вопрос помечен как решенный

Ответы 10

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

Ответ принят как подходящий

Вы можете использовать полные переменные 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

Чтобы избежать OverflowErrors, я бы рекомендовал использовать другую фиктивную дату, например, пару лет спустя: datetime (101,1,1,11,34,59). Если вы попытаетесь вычесть большое значение timedelta из указанной выше даты, вы получите ошибку «OverflowError: значение даты вне диапазона», поскольку год для объекта datetime не может быть меньше 1.

pheelicks 29.11.2011 09:23

@pheelicks, готово, хотя и немного поздно, не совсем гибкое время отклика :-) Поскольку мне пришлось исправить еще одну ошибку в моем коде, я подумал, что учту ваше предложение в то же время.

paxdiablo 15.01.2013 05:20

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

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

Мне нравится этот. Красиво и ясно с указанным аргументом.

Vigrond 03.07.2014 17:19

Спасибо @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()

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

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

from datetime import datetime, date, time, timedelta
sometime = time(8,00) # 8am
later = (datetime.combine(date.today(), sometime) + timedelta(seconds=3)).time()

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

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

Очевидно, исключение. Невозможно добавить ВРЕМЯdelta к ВРЕМЯ - глупо.

Jürgen A. Erhard 15.09.2020 12:25

@ JürgenA.Erhard Интересно, что я «явно» думал, что правильное поведение будет заключаться в том, чтобы обернуть вокруг…

JamesTheAwesomeDude 16.02.2021 18:17

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

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

>>> 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.

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

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

Вы не можете просто добавить число к 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.

пожалуйста, ВСЕГДА добавляйте пояснения, новички могут не понимать, что вы здесь делаете.

Gerhard 18.01.2018 12:10

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

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

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

Поэтому я бы рекомендовал такой подход:

import datetime as dt

_now = dt.datetime.now()  # or dt.datetime.now(dt.timezone.utc)
_in_5_sec = _now + dt.timedelta(seconds=5)

# get '14:39:57':
_in_5_sec.strftime('%H:%M:%S')

Другие вопросы по теме