Странное поведение округления datetime между python 2 и 3

В python 2 мы имеем:

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

Но в python 3 мы имеем:

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

В чем причина этого странного поведения округления и он предназначен? Разве не 1000000000005.0 все еще находится в диапазоне удвоений с несколькими цифрами, чтобы сэкономить?

Ответ 1

Ниже я по существу включил utcfromtimestamp (я слегка изменил его на автономный).

В Python 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)

В Python 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)

(Вход 1000000000005.0/1000.0 рассчитан как 1000000000.005.)

В моей автономной версии:

Python 2 использует оператор модуля %, чтобы определить, является ли вход целым числом или дробью. Утверждение (t % 1.0) * 1000000 затем умножает дробь (в нашем случае 0.004999995231628418) на 1000000. Это возвращает 4999.995231628418, который округляется до 4999 на int.

Python 3 использует divmod для возврата всего числа (t) 1000000000.0 и фракции (frac) 0.005. Вместо этого он возвращает t как 1000000000 и frac как 0.004999995231628418. Затем идет вычисление us с помощью frac * 1e6. Это умножает ваш 0.004999995231628418 на 1000000, что приводит к 4999.995231628418, который округляется до 4999 на int.

В используемых методах нет никакой реальной разницы. Оба являются точными и возвращают один и тот же результат. Я пришел к выводу, что Python 2 округляет микросекунды вверх, а Python 3 округляет их.