2013-06-07 15 views
7

Esiste un'elegante conversione tra relativedelta e timedelta?Un modo elegante per convertire python datetime.timedelta a datautil.relativedelta

Il caso d'uso sta ricevendo la data ISO di input dell'utente. Python isodate restituirà isodate.duration.Duration o datetime.timedelta.

Abbiamo bisogno delle funzionalità di relativedelta (per What is the difference between "datetime.timedelta" and "dateutil.relativedelta.relativedelta" when working only with days? - lo fa di più), quindi è necessario convertire entrambi questi tipi in uno relativedata.

risposta

6

Basta prendere il numero totale di seconds e microseconds, questo è tutto un negozi timedelta oggetto:

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

I microsecondi sono inclusi nel totale_secondi. –

+0

@LennartRegebro: Sì, ma relativedelta non accetta i secondi frazionari ('relativedelta (seconds = 0.3)' fornisce 'relativedelta (seconds = + 0)'). Inoltre, come afferma la documentazione, i microsecondi potrebbero non essere accurati per intervalli molto grandi. –

+0

relativedelta (secondi = 0,3) fornisce a relativedelta (secondi = 0,3). Sto usando 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

Uso secondi direttamente con relativedelta non popola i mesi ei campi anni e non v'è un motivo di Certo che non sapremmo se è un anno bisestile o un mese con 31 giorni.

Quindi qualcosa di simile:

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

dà delta relativa con un sacco di giorni e non mesi. Mentre in alcuni casi può andar bene, in alcuni potremmo aver bisogno di anni e mesi. Pertanto:

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) 

Questa potrebbe non essere una soluzione molto pitonica ma funziona.

Nota: ciò presuppone che un anno abbia 365 giorni (ignora il salto di anni bisestili) e mesi di 30 giorni.