arrow icon indicating copy to clipboard operation
arrow copied to clipboard

MAX_TIMESTAMP calculation error

Open JosEnerv opened this issue 3 years ago • 2 comments

Issue Description

There are some issues related to the way max values are handled (partially because of how python's datetime works) :

The way how Arrow calculates the max timestamp constant value also fails on Linux in constants.py :

_MAX_TIMESTAMP = datetime.max.timestamp()

Which will raise a ValueError in non-utc timezones (timestamp() ) will try to return a timestamp in the local timezone):

ValueError: year 10000 is out of range

Therefore I suggest making this more robust and replacing this with :

datetime.max.replace(tzinfo=timezone.utc).timestamp()

Which is more in line with python documentation : https://docs.python.org/3/library/datetime.html#datetime.datetime.timestamp

Using Arrow.max has its own issues , as

Arrow.utcfromtimestamp(Arrow.max.float_timestamp)

does not behave as expected and returns a date in 1978, due to normalize_timestamp (util) division by 1000 :

def normalize_timestamp(timestamp: float) -> float:
    """Normalize millisecond and microsecond timestamps into normal timestamps."""
    if timestamp > MAX_TIMESTAMP:
        if timestamp < MAX_TIMESTAMP_MS:
            timestamp /= 1000
        elif timestamp < MAX_TIMESTAMP_US:
            timestamp /= 1_000_000
        else:
            raise ValueError(f"The specified timestamp {timestamp!r} is too large.")
    return timestamp

System Info

  • 🖥 OS name and version: Debian 11
  • 🐍 Python version: 3.9.2
  • 🏹 Arrow version: 1.2.2

JosEnerv avatar Mar 01 '22 09:03 JosEnerv

Hi @JosEnerv, thanks for the bug report, we've struggled a lot with max timestamp calculations in the past. Can you put together a minimal example so we can try to reproduce on our end?

systemcatch avatar Mar 07 '22 17:03 systemcatch

Sure, this is the example :

from datetime import datetime

import arrow.constants
from arrow import Arrow

if __name__ == '__main__':
    print(arrow.constants.MAX_TIMESTAMP) # 32503762800.0

    print(arrow.Arrow.max) # 9999-12-31T23:59:59.999999+00:00
    print(arrow.Arrow.max.timestamp()) # 253402300800.0
    a = Arrow.utcfromtimestamp(arrow.Arrow.max.timestamp())
    print(a) # 1978-01-11T21:31:40.800000+00:00

    datetime.max.timestamp()  # ValueError: year 10000 is out of range

As background info, the ticket I opened on the python bugtracker : https://bugs.python.org/issue46856

JosEnerv avatar Mar 09 '22 11:03 JosEnerv