Хотя неточности Float
, о которых вы уже знаете, играют здесь роль, в конечном счете, это «ошибка» спецификатора преобразования %N
, которая хочет помешать вам отправиться в будущее. Из документации :
The digits under the specified length are truncated to avoid
carry up.
Другие преобразования (например, sprintf
с '%.3f'
) были бы округлены в этом случае. Таким образом, миллисекунды вашего Time
объекта на самом деле не 123
, а 122.9???
, который из-за %3N
становится 122
. Для точной обработки (под) секунд Time
поддерживает целые и рациональные числа:
Time.at(*timestamp.divmod(1000), :millisecond, in: 'utc')
# or
Time.at(Rational(timestamp, 1000), in: 'utc')
Time.at(timestamp / 1000r, in: 'utc')