2015-01-23 11 views
11

W python 2, mamy:Dziwne zachowanie datetime zaokrąglenia między python 2 & 3

>>> datetime.datetime.utcfromtimestamp(1000000000005.0/1000.0) 
datetime.datetime(2001, 9, 9, 1, 46, 40, 5000) 

Ale w Pythonie 3, mamy:

>>> datetime.datetime.utcfromtimestamp(1000000000005.0/1000.0) 
datetime.datetime(2001, 9, 9, 1, 46, 40, 4999) 

Co jest przyczyną tego dziwnego zaokrąglania zachowanie i czy jest to zamierzone? Czy nie jest jeszcze w zasięgu gry podwójnej z kilkoma cyframi do stracenia?

+0

Interesujące znalezisko. Czy mógłbyś opublikować swój system operacyjny, python sys.version? – dmg

+0

@dmg Testowałem to na pythonie 3.4.1, 3.4.2, linux i windows 7. – simonzack

+0

zdecydowanie ma to związek z tym, jak zaokrąglanie jest wykonywane w python3, jeśli używasz dowolnej wartości od 5 w dół to zaokrągla w dół i do wartości> 5 –

Odpowiedz

1

Poniżej zasadniczo zawierałem utcfromtimestamp (zmieniłem go nieznacznie na samodzielny).

W Pythonie 2:

import time, datetime 
def utcfromtimestamp(t): 
    y, m, d, hh, mm, ss, weekday, jday, dst = time.gmtime(t) 
    us = int((t % 1.0) * 1000000) 
    ss = min(ss, 59) 
    return datetime.datetime(y, m, d, hh, mm, ss, us) 

W Pythonie 3:

import time, datetime 
def utcfromtimestamp(t): 
    t, frac = divmod(t, 1.0) 
    us = int(frac * 1e6) 
    if us == 1000000: 
     t += 1 
     us = 0 
    y, m, d, hh, mm, ss, weekday, jday, dst = time.gmtime(t) 
    ss = min(ss, 59) 
    return datetime.datetime(y, m, d, hh, mm, ss, us) 

(Wejście 1000000000005.0/1000.0 oblicza się 1000000000.005).

W moim wersja autonomiczna

Pythonie 2 używa operatora modulusa % do określić, czy dane wejściowe są liczbą całkowitą czy ułamkową. Oświadczenie (t % 1.0) * 1000000 następnie mnoży ułamek (w naszym przypadku 0.004999995231628418) przez 1000000. Zwraca to 4999.995231628418, zaokrąglone w dół do 4999 przez int.

Pythona 3 wykorzystuje divmod powrót liczby całkowitej (t) 1000000000.0 a frakcję (frac) 0.005. Zamiast zwracać to, zwraca t jako 1000000000 i frac jako 0.004999995231628418. Następnie przechodzi do obliczania us przy użyciu frac * 1e6. To pomnaża liczbę 0.004999995231628418 przez 1000000, co daje 4999.995231628418, zaokrągloną w dół do 4999 przez int.

Nie ma rzeczywistej różnicy w stosowanych metodach. Oba są dokładne i zwracają ten sam wynik. Mój wniosek jest taki, że Python 2 zaokrągla mikrosekundy, a Python 3 zaokrągla je.