Элегантный способ конвертировать python datetime.timedelta в dateutil.relativedelta

Есть ли элегантный был конвертировать между relativedelta а также timedelta?

Вариант использования - получение пользователем даты ISO. Питона isodate вернется либо isodate.duration.Duration или же datetime.timedelta,

Нам нужны особенности relativedeltaчем разница между "datetime.timedelta" и "dateutil.relativedelta.relativedelta" при работе только с днями? - это больше), поэтому необходимо преобразовать оба этих типа в relativedata,

4 ответа

Решение

Просто возьмите общее количество seconds а также microsecondsвот и все timedelta хранилища объектов:

def to_relativedelta(tdelta):
    return relativedelta(seconds=int(tdelta.total_seconds()),
                         microseconds=tdelta.microseconds)

>>> to_relativedelta(timedelta(seconds=0.3))
relativedelta(microseconds=+300000)
>>> to_relativedelta(timedelta(seconds=3))
relativedelta(seconds=+3)
>>> to_relativedelta(timedelta(seconds=300))
relativedelta(minutes=+5)
>>> to_relativedelta(timedelta(seconds=3000000))
relativedelta(days=+34, hours=+17, minutes=+20)
d = datetime.timedelta(...)
dateutil.relativedelta.relativedelta(seconds=d.total_seconds())

Я предполагаю, что вы имеете дело с разницей во времени, потому что были вычтены две даты и времени.Relativedelta имеет аргументы dt1 и dt2 в init .

Просто передайте две даты и времени, которые вы использовали, чтобы получить свою временную дельту, и вы получите относительную дельту.

Использование секунд напрямую с относительной дельтой не заполняет поля месяцев и лет, и, конечно, есть причина, по которой мы не будем знать, високосный год или месяц с 31 днем.

Так что-то вроде этого:

[In]:  tdelta = datetime.now() - datetime(1971, 1, 1)
[In]:  relativedelta(seconds=tdelta.total_seconds())
[Out]: relativedelta(days=+16958, hours=+13, minutes=+19, seconds=+49)

дает относительную дельту с большим количеством дней и без месяцев. Хотя в некоторых случаях это может быть хорошо, в некоторых нам могут понадобиться годы и месяцы. Следовательно:

def timedelta_to_relativedelta(tdelta):
    assert isinstance(tdelta, timedelta)

    seconds_in = {
        'year'  : 365 * 24 * 60 * 60,
        'month' : 30 * 24 * 60 * 60,
        'day'   : 24 * 60 * 60,
        'hour'  : 60 * 60,
        'minute': 60
    }

    years, rem = divmod(tdelta.total_seconds(), seconds_in['year'])
    months, rem = divmod(rem, seconds_in['month'])
    days, rem = divmod(rem, seconds_in['day'])
    hours, rem = divmod(rem, seconds_in['hour'])
    minutes, rem = divmod(rem, seconds_in['minute'])
    seconds = rem

    return relativedelta(years=years, months=months, days=days, hours=hours, minutes=minutes, seconds=seconds)

Это может быть не очень Pythonic решение, но оно работает.

Примечание. Предполагается, что в году 365 дней (игнорируется високосные годы), а в месяцах 30 дней.

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