Skip to content

Commit

Permalink
Fix overflow error on 32bit systems
Browse files Browse the repository at this point in the history
This fixes #87.
  • Loading branch information
kiorky committed Jul 26, 2024
1 parent 99295c9 commit 2cbe76a
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/croniter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from __future__ import absolute_import
from .croniter import (
croniter,
OVERFLOW32B_MODE,
datetime_to_timestamp,
croniter_range,
CroniterBadTypeRangeError, # noqa
Expand Down
28 changes: 23 additions & 5 deletions src/croniter/croniter.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@
# python2, just test that it's well installed
import pytz # noqa

EPOCH = datetime.datetime.fromtimestamp(0)
try:
# https://github.com/python/cpython/issues/101069 detection
datetime.datetime.fromtimestamp(3999999999)
OVERFLOW32B_MODE = False
except OverflowError:
OVERFLOW32B_MODE = True

try:
from collections import OrderedDict
except ImportError:
Expand Down Expand Up @@ -80,10 +88,15 @@ def timedelta_to_seconds(td):


def datetime_to_timestamp(d):
if d.tzinfo is not None:
d = d.replace(tzinfo=None) - d.utcoffset()
try:
if d.tzinfo is not None:
d = d.replace(tzinfo=None) - d.utcoffset()

return timedelta_to_seconds(d - datetime.datetime(1970, 1, 1))
except OverflowError:
import pdb;pdb.set_trace() ## Breakpoint ##
raise

return timedelta_to_seconds(d - datetime.datetime(1970, 1, 1))


def _get_caller_globals_and_locals():
Expand Down Expand Up @@ -274,7 +287,12 @@ def _timestamp_to_datetime(self, timestamp):
"""
Converts a UNIX timestamp `timestamp` into a `datetime` object.
"""
result = datetime.datetime.fromtimestamp(timestamp, tz=tzutc()).replace(tzinfo=None)
if OVERFLOW32B_MODE:
# degraded mode to workaround Y2038
# see https://github.com/python/cpython/issues/101069
result = EPOCH + datetime.timedelta(seconds=timestamp)
else:
result = datetime.datetime.fromtimestamp(timestamp, tz=tzutc()).replace(tzinfo=None)
if self.tzinfo:
result = result.replace(tzinfo=tzutc()).astimezone(self.tzinfo)

Expand Down Expand Up @@ -379,7 +397,7 @@ def _get_next(self, ret_type=None, start_time=None, is_prev=None, update_current
# dates feed using 'itertools' module
def all_next(self, ret_type=None, start_time=None, update_current=None):
'''Generator of all consecutive dates. Can be used instead of
implicit call to __iter__, whenever non-default
implicit call to f_iter__, whenever non-default
'ret_type' has to be specified.
'''
# In a Python 3.7+ world: contextlib.suppress and contextlib.nullcontext could be used instead
Expand Down
10 changes: 9 additions & 1 deletion src/croniter/tests/test_croniter.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import pytz
from croniter.croniter import VALID_LEN_EXPRESSION
from croniter import (croniter, CroniterBadDateError, CroniterBadCronError, datetime_to_timestamp,
CroniterNotAlphaError, CroniterUnsupportedSyntaxError)
CroniterNotAlphaError, CroniterUnsupportedSyntaxError, OVERFLOW32B_MODE)
from croniter.tests import base
import dateutil.tz

Expand Down Expand Up @@ -1962,6 +1962,14 @@ def test_get_next_update_current(self):
self.assertEqual(uretp, uretap)
self.assertEqual(uretn, uretan)

def test_issue_2038y(self):
base = datetime(2040, 1, 1, 0, 0)
itr = croniter('* * * * *', base)
try:
itr.get_next()
except OverflowError:
raise Exception("overflow not fixed!")


if __name__ == '__main__':
unittest.main()

0 comments on commit 2cbe76a

Please sign in to comment.