Элегантный способ конвертировать 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 дней.