Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"27 years from now" tests fail on platforms with 32-bit time_t (y2k38 problem) #176

Closed
mgorny opened this issue Feb 29, 2024 · 3 comments · Fixed by #177
Closed

"27 years from now" tests fail on platforms with 32-bit time_t (y2k38 problem) #176

mgorny opened this issue Feb 29, 2024 · 3 comments · Fixed by #177

Comments

@mgorny
Copy link
Contributor

mgorny commented Feb 29, 2024

What did you do?

tox -e py311 on a 32-bit x86 system.

What did you expect to happen?

Tests passing (possibly by skipping these tests on OverflowError).

What actually happened?

.pkg: install_requires> python -I -m pip install hatch-vcs hatchling
.pkg: _optional_hooks> python /usr/lib/python3.11/site-packages/pyproject_api/_backend.py True hatchling.build
.pkg: get_requires_for_build_sdist> python /usr/lib/python3.11/site-packages/pyproject_api/_backend.py True hatchling.build
.pkg: build_sdist> python /usr/lib/python3.11/site-packages/pyproject_api/_backend.py True hatchling.build
py311: install_package_deps> python -I -m pip install freezegun pytest pytest-cov
py311: install_package> python -I -m pip install --force-reinstall --no-deps /home/mgorny/humanize/.tox/.tmp/package/1/humanize-4.9.1.dev38.tar.gz
py311: commands[0]> .tox/py311/bin/python -m pytest --cov humanize --cov tests --cov-report html --cov-report term --cov-report xml
========================================================= test session starts =========================================================
platform linux -- Python 3.11.7, pytest-8.0.2, pluggy-1.4.0
cachedir: .tox/py311/.pytest_cache
rootdir: /home/mgorny/humanize
configfile: pyproject.toml
plugins: cov-4.1.0
collected 572 items                                                                                                                   

tests/test_filesize.py ....................                                                                                     [  3%]
tests/test_i18n.py sssssssssssssssssssssss.....                                                                                 [  8%]
tests/test_number.py .......................................................................................................... [ 26%]
..........................................................................................................                      [ 45%]
tests/test_time.py ............................................................................................................ [ 64%]
............................................................................................................................... [ 86%]
..F......................F...................................................                                                   [100%]

============================================================== FAILURES ===============================================================
______________________________________ test_naturaltime_timezone[test_input19-27 years from now] ______________________________________

test_input = FakeDatetime(2047, 6, 20, 0, 0, tzinfo=datetime.timezone.utc), expected = '27 years from now'

    @freeze_time("2020-02-02")
    @pytest.mark.parametrize(
        "test_input, expected",
        [
            (NOW_UTC, "now"),
            (NOW_UTC - dt.timedelta(seconds=1), "a second ago"),
            (NOW_UTC - dt.timedelta(seconds=30), "30 seconds ago"),
            (NOW_UTC - dt.timedelta(minutes=1, seconds=30), "a minute ago"),
            (NOW_UTC - dt.timedelta(minutes=2), "2 minutes ago"),
            (NOW_UTC - dt.timedelta(hours=1, minutes=30, seconds=30), "an hour ago"),
            (NOW_UTC - dt.timedelta(hours=23, minutes=50, seconds=50), "23 hours ago"),
            (NOW_UTC - dt.timedelta(days=1), "a day ago"),
            (NOW_UTC - dt.timedelta(days=500), "1 year, 4 months ago"),
            (NOW_UTC - dt.timedelta(days=365 * 2 + 35), "2 years ago"),
            (NOW_UTC + dt.timedelta(seconds=1), "a second from now"),
            (NOW_UTC + dt.timedelta(seconds=30), "30 seconds from now"),
            (NOW_UTC + dt.timedelta(minutes=1, seconds=30), "a minute from now"),
            (NOW_UTC + dt.timedelta(minutes=2), "2 minutes from now"),
            (NOW_UTC + dt.timedelta(hours=1, minutes=30, seconds=30), "an hour from now"),
            (NOW_UTC + dt.timedelta(hours=23, minutes=50, seconds=50), "23 hours from now"),
            (NOW_UTC + dt.timedelta(days=1), "a day from now"),
            (NOW_UTC + dt.timedelta(days=500), "1 year, 4 months from now"),
            (NOW_UTC + dt.timedelta(days=365 * 2 + 35), "2 years from now"),
            # regression tests for bugs in post-release humanize
            (NOW_UTC + dt.timedelta(days=10000), "27 years from now"),
            (NOW_UTC - dt.timedelta(days=365 + 35), "1 year, 1 month ago"),
            (NOW_UTC - dt.timedelta(days=365 * 2 + 65), "2 years ago"),
            (NOW_UTC - dt.timedelta(days=365 + 4), "1 year, 4 days ago"),
        ],
    )
    def test_naturaltime_timezone(test_input: dt.datetime, expected: str) -> None:
>       assert humanize.naturaltime(test_input) == expected

tests/test_time.py:449: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.tox/py311/lib/python3.11/site-packages/humanize/time.py:249: in naturaltime
    value = _convert_aware_datetime(value)
.tox/py311/lib/python3.11/site-packages/humanize/time.py:275: in _convert_aware_datetime
    value = dt.datetime.fromtimestamp(value.timestamp())
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

cls = <class 'freezegun.api.FakeDatetime'>, t = 2444601600.0, tz = None

    @classmethod
    def fromtimestamp(cls, t, tz=None):
        if tz is None:
>           return real_datetime.fromtimestamp(
                    t, tz=dateutil.tz.tzoffset("freezegun", cls._tz_offset())
                ).replace(tzinfo=None)
E           OverflowError: timestamp out of range for platform time_t

.tox/py311/lib/python3.11/site-packages/freezegun/api.py:375: OverflowError
___________________________________ test_naturaltime_timezone_when[test_input19-27 years from now] ____________________________________

test_input = FakeDatetime(2047, 6, 20, 0, 0, tzinfo=datetime.timezone.utc), expected = '27 years from now'

    @freeze_time("2020-02-02")
    @pytest.mark.parametrize(
        "test_input, expected",
        [
            (NOW_UTC, "now"),
            (NOW_UTC - dt.timedelta(seconds=1), "a second ago"),
            (NOW_UTC - dt.timedelta(seconds=30), "30 seconds ago"),
            (NOW_UTC - dt.timedelta(minutes=1, seconds=30), "a minute ago"),
            (NOW_UTC - dt.timedelta(minutes=2), "2 minutes ago"),
            (NOW_UTC - dt.timedelta(hours=1, minutes=30, seconds=30), "an hour ago"),
            (NOW_UTC - dt.timedelta(hours=23, minutes=50, seconds=50), "23 hours ago"),
            (NOW_UTC - dt.timedelta(days=1), "a day ago"),
            (NOW_UTC - dt.timedelta(days=500), "1 year, 4 months ago"),
            (NOW_UTC - dt.timedelta(days=365 * 2 + 35), "2 years ago"),
            (NOW_UTC + dt.timedelta(seconds=1), "a second from now"),
            (NOW_UTC + dt.timedelta(seconds=30), "30 seconds from now"),
            (NOW_UTC + dt.timedelta(minutes=1, seconds=30), "a minute from now"),
            (NOW_UTC + dt.timedelta(minutes=2), "2 minutes from now"),
            (NOW_UTC + dt.timedelta(hours=1, minutes=30, seconds=30), "an hour from now"),
            (NOW_UTC + dt.timedelta(hours=23, minutes=50, seconds=50), "23 hours from now"),
            (NOW_UTC + dt.timedelta(days=1), "a day from now"),
            (NOW_UTC + dt.timedelta(days=500), "1 year, 4 months from now"),
            (NOW_UTC + dt.timedelta(days=365 * 2 + 35), "2 years from now"),
            # regression tests for bugs in post-release humanize
            (NOW_UTC + dt.timedelta(days=10000), "27 years from now"),
            (NOW_UTC - dt.timedelta(days=365 + 35), "1 year, 1 month ago"),
            (NOW_UTC - dt.timedelta(days=365 * 2 + 65), "2 years ago"),
            (NOW_UTC - dt.timedelta(days=365 + 4), "1 year, 4 days ago"),
        ],
    )
    def test_naturaltime_timezone_when(test_input: dt.datetime, expected: str) -> None:
>       assert humanize.naturaltime(test_input, when=NOW_UTC) == expected

tests/test_time.py:483: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.tox/py311/lib/python3.11/site-packages/humanize/time.py:249: in naturaltime
    value = _convert_aware_datetime(value)
.tox/py311/lib/python3.11/site-packages/humanize/time.py:275: in _convert_aware_datetime
    value = dt.datetime.fromtimestamp(value.timestamp())
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

cls = <class 'freezegun.api.FakeDatetime'>, t = 2444601600.0, tz = None

    @classmethod
    def fromtimestamp(cls, t, tz=None):
        if tz is None:
>           return real_datetime.fromtimestamp(
                    t, tz=dateutil.tz.tzoffset("freezegun", cls._tz_offset())
                ).replace(tzinfo=None)
E           OverflowError: timestamp out of range for platform time_t

.tox/py311/lib/python3.11/site-packages/freezegun/api.py:375: OverflowError

---------- coverage: platform linux, python 3.11.7-final-0 -----------
Name                                                           Stmts   Miss  Cover
----------------------------------------------------------------------------------
.tox/py311/lib/python3.11/site-packages/humanize/__init__.py       8      0   100%
.tox/py311/lib/python3.11/site-packages/humanize/filesize.py      24      0   100%
.tox/py311/lib/python3.11/site-packages/humanize/i18n.py          56      4    93%
.tox/py311/lib/python3.11/site-packages/humanize/number.py       165      7    96%
.tox/py311/lib/python3.11/site-packages/humanize/time.py         224      0   100%
tests/__init__.py                                                  0      0   100%
tests/test_filesize.py                                            10      0   100%
tests/test_i18n.py                                               106     19    82%
tests/test_number.py                                              32      0   100%
tests/test_time.py                                               124      0   100%
----------------------------------------------------------------------------------
TOTAL                                                            749     30    96%
Coverage HTML written to dir htmlcov
Coverage XML written to file coverage.xml

======================================================= short test summary info =======================================================
FAILED tests/test_time.py::test_naturaltime_timezone[test_input19-27 years from now] - OverflowError: timestamp out of range for platform time_t
FAILED tests/test_time.py::test_naturaltime_timezone_when[test_input19-27 years from now] - OverflowError: timestamp out of range for platform time_t
============================================== 2 failed, 547 passed, 23 skipped in 4.97s ==============================================
py311: exit 1 (5.42 seconds) /home/mgorny/humanize> .tox/py311/bin/python -m pytest --cov humanize --cov tests --cov-report html --cov-report term --cov-report xml pid=37634
.pkg: _exit> python /usr/lib/python3.11/site-packages/pyproject_api/_backend.py True hatchling.build
  py311: FAIL code 1 (21.29=setup[15.87]+cmd[5.42] seconds)
  evaluation failed :( (21.38 seconds)

What versions are you using?

  • OS: Gentoo Linux x86
  • Python: 3.11.7
  • Humanize: 218a86e
@hugovk
Copy link
Member

hugovk commented Feb 29, 2024

Thanks for the report!

.tox/py311/lib/python3.11/site-packages/freezegun/api.py:375: OverflowError

Looks like the exception is coming from the https://github.com/spulec/freezegun test library, so might be worth reporting something there.

Anyway, skipping sounds reasonable in this case, would you like to create a PR? I don't have a setup to test it.

@mgorny
Copy link
Contributor Author

mgorny commented Feb 29, 2024

Thanks for the report!

.tox/py311/lib/python3.11/site-packages/freezegun/api.py:375: OverflowError

Looks like the exception is coming from the https://github.com/spulec/freezegun test library, so might be worth reporting something there.

It's basically coming from Python, when given a date that's outside time_t range for the system. I don't really see what freezegun could do there.

Anyway, skipping sounds reasonable in this case, would you like to create a PR? I don't have a setup to test it.

Sure, I will file one in a minute.

mgorny added a commit to mgorny/humanize that referenced this issue Feb 29, 2024
Change the frozen date in test_time from 2020 to 2010, in order to fix
overflow when processing "27 years from now" date on systems with 32-bit
time_t.  Since the date is arbitrary and frozen anyway, this seems to be
the cleanest solution to keep the test suite working portably.

Fixes python-humanize#176
@mgorny
Copy link
Contributor Author

mgorny commented Feb 29, 2024

Filed #177. In the end, I've figured out it's cleaner to change the base date not to trigger overflows in the first place.

hugovk added a commit that referenced this issue Mar 1, 2024
Fixes #176

Changes proposed in this pull request:

* Change the frozen date from 2020 to 2010, in order to avoid going past
2038 that breaks systems with 32-bit `time_t`. Since the tests are run
against frozen time anyway, this shouldn't have any negative
consequences, and will resolve the y2k38 issue that's not really related
to the project.

---------

Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants