2013-06-07 3 views
7

Есть ли элегантный, чтобы конвертировать между relativedelta и timedelta?Элегантный способ конвертировать python datetime.timedelta to dateutil.relativedelta

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

Нам нужны функции relativedelta (за What is the difference between "datetime.timedelta" and "dateutil.relativedelta.relativedelta" when working only with days? - это больше), поэтому необходимо преобразовать оба эти типа в relativedata.

ответ

6

Просто общее количество 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) 
+0

Микросекунды включены в итоговые_секунды. –

+0

@ LennartRegebro: Да, но relativedelta не принимает дробные секунды ('relativedelta (seconds = 0.3)' дает 'relativedelta (seconds = + 0)'). Кроме того, как указывается в документации, микросекунды могут быть неточными в течение очень больших интервалов. –

+0

relativedelta (секунды = 0,3) дает мне relativedelta (секунды = 0,3). Я использую python-dateutil 1.5 – falsetru

0
d = datetime.timedelta(...) 
dateutil.relativedelta.relativedelta(seconds=d.total_seconds()) 
+0

http://docs.python.org/2/library/datetime.html#datetime.timedelta.total_seconds – falsetru

0

Использование секунд непосредственно relativedelta не заполняет месяцы и годы поля и есть причина Конечно, мы не знали бы, если это високосный год или месяц с 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 дней.

Смежные вопросы