2009-07-05 8 views
9

Rozumiem, że sekundy i mikrosekund prawdopodobnie reprezentowane oddzielnie datetime.timedelta ze względów efektywności, ale ja po prostu napisał tę prostą funkcję:Brakujące datetime.timedelta.to_seconds() -> unosić w Pythonie?

def to_seconds_float(timedelta): 
    """Calculate floating point representation of combined 
    seconds/microseconds attributes in :param:`timedelta`. 

    :raise ValueError: If :param:`timedelta.days` is truthy. 

     >>> to_seconds_float(datetime.timedelta(seconds=1, milliseconds=500)) 
     1.5 
     >>> too_big = datetime.timedelta(days=1, seconds=12) 
     >>> to_seconds_float(too_big) # doctest: +ELLIPSIS 
     Traceback (most recent call last): 
     ... 
     ValueError: ('Must not have days', datetime.timedelta(1, 12)) 
    """ 
    if timedelta.days: 
     raise ValueError('Must not have days', timedelta) 
    return timedelta.seconds + timedelta.microseconds/1E6 

ta jest przydatna dla rzeczy jak przepuszczenie wartość time.sleep lub select.select. Dlaczego coś takiego nie jest częścią interfejsu datetime.timedelta? Może brakuje mi jakiegoś rogu. Reprezentacja czasu wydaje się mieć wiele nieoczywistych przypadków narożnych ...

Odrzuciłem kilka dni, aby uzyskać rozsądny strzał z pewną precyzją (jestem zbyt leniwy, aby opracować matematyczne bankomaty ATM, więc wydaje się, że rozsądny kompromis ;-).

+0

Na czym polega pytanie? –

+0

Ośmielasz się - zastanawiasz się, czy jest jakiś powód, dla którego nie ma go w interfejsie. – cdleary

+2

To wygląda na duplikat https://stackoverflow.com/questions/21414639/convert-timedelta-to-floating-point, który ma lepszą odpowiedź. – outofculture

Odpowiedz

12

Python float ma około 15 cyfr znaczących, więc z czasem wynoszącym do 86400 (5 cyfr na lewo od przecinka dziesiętnego) i mikrosekund potrzebujących 6 cyfr, można również uwzględnić dni (do kilku lat) bez utraty precyzji.

Dobra mantra to "pi sekund to nanocentury" - około 3,14E9 na 100 lat, czyli 3E7 rocznie, czyli 3E13 mikrosekund na rok. Mantra jest dobra, ponieważ jest niezapomniana, chociaż wymaga później trochę arytmetyki mentalnej (ale, jak szpinak, jest DOBRA dla ciebie - trzyma cię zwinnie i czujnie! -).

Filozofia projektowania datetime jest nieco minimalistyczna, więc nie jest zaskakujące, że pomija wiele możliwych metod pomocniczych, które sprowadzają się do prostych wyrażeń arytmetycznych.

+0

Zrozumiałem, że istnieje wiele * możliwych * pomocniczych metod, ale ten wydaje się szczególnie przydatny, biorąc pod uwagę interfejsy innych funkcji stdlib - czy uważasz, że warto zaproponować włączenie? To i tak będzie twoja rozmowa. ;-) – cdleary

+0

Szczerze, nie mam już czasu na setki wątków na python-dev - stało się to po prostu zbyt czasochłonne :-(. Sugeruję, żebyś podszedł do python-pomysłów i spróbował łącząc PEP z zestawem dodatkowych metod pomocniczych, które mogą okazać się popularne i nie budzą kontrowersji (moją ulubioną metodą byłoby totimestamp - posiadanie tylko oftimestamp jest absurdalne!), a następnie przekazanie go na python-dev i - * duck * ! -) –

+0

Powinienem zagłosować za komentarzem do szpinaku. :) Bardzo lubię mantrę, więc zamiast tego głosowałem. – Scott

3

Twoja troska o precyzję jest niewłaściwie umieszczona. Oto prosty dwa-liner w przybliżeniu obliczyć, ile lat można wycisnąć w to, co pozostało z 53 bitów precsion w IEEE 754 64-bit float:

>>> import math 
>>> 10 ** (math.log10(2 ** 53) - math.log10(60 * 60 * 24) - 6)/365.25 
285.42092094268787 
>>> 

uważaj na zaokrąglić; najpierw dodaj najmniejsze niezerowe numery:

return timedelta.seconds + timedelta.microseconds/1E6 + timedelta.days * 86400 
+0

Nie jestem pewien, czy jest on niewłaściwie umieszczony - nawet wiedząc o tym, musisz teraz ustalić, czy zezwolenie na liczbę dni <= 285 (co jest dość dziwnym ograniczeniem dla zapamiętania) jest lepsze niż odrzucanie ich z reguły (łatwe do zapamiętania). Dziękuję za wyliczenie - to jest praca, którą miałem nadzieję uniknąć w pierwszej kolejności. :-) – cdleary

+0

Punkt mojej odpowiedzi brzmiał, że możesz nadal mieć mikrosekundową precyzję, jeśli dodasz 280-cio letnich lat. Jednak ludzie, którzy pracują z latami, pewnie i tak nie przejmują się mikrosekundami. Jakie ograniczenie?Na pewno nie planowałeś sprawdzenia przez 285 lat kodu? Sheesh * 2 ** 53 !! Jeśli timedelta ma wynosić 300 * 366 dni, a sekundy i mikrosekundy wynoszą zero, żadna precyzja nie zostanie utracona. Pamiętaj, że F jest skrótem od Floating, a nie Fixed. –

+0

Rozumiem, po prostu myślałem, że obliczenie, czy precyzja była wystarczająca w locie, było znacznie bardziej skomplikowane niż ograniczenie go w najbardziej znaczącym wymiarze. (Łatwiej też dowiedzieć się, jak naprawić błąd). Sądzę, że masz rację - gdybym chciał uczynić tę funkcję poważniejszą, mogłem podnieść wartość ValueError, stwierdzając, że nie mogę osiągnąć wymaganej precyzji i pozwolić użytkownik radzi sobie z tym stamtąd. – cdleary