Skip to content

Commit 7846065

Browse files
authored
Workaround for screwed up date values (#149)
* #143 Workaround for screwed up date values - Adds constant FIX_SCREWED_UP_MINIMAL_DATETIME_VALUE to return 0001-01-01 - Adds constant FIX_SCREWED_UP_MAXIMUM_DATETIME_VALUE to return 9999-12-31 - Add new unittests * fix elif after return
1 parent 9a3694d commit 7846065

File tree

2 files changed

+39
-5
lines changed

2 files changed

+39
-5
lines changed

pyodata/v2/model.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
from pyodata.exceptions import PyODataException, PyODataModelError, PyODataParserError
2222

2323
LOGGER_NAME = 'pyodata.model'
24+
FIX_SCREWED_UP_MINIMAL_DATETIME_VALUE = False
25+
FIX_SCREWED_UP_MAXIMUM_DATETIME_VALUE = False
2426

2527
IdentifierInfo = collections.namedtuple('IdentifierInfo', 'namespace name')
2628
TypeInfo = collections.namedtuple('TypeInfo', 'namespace name is_collection')
@@ -414,8 +416,19 @@ def from_json(self, value):
414416
try:
415417
# https://stackoverflow.com/questions/36179914/timestamp-out-of-range-for-platform-localtime-gmtime-function
416418
value = datetime.datetime(1970, 1, 1, tzinfo=current_timezone()) + datetime.timedelta(milliseconds=int(value))
417-
except ValueError:
418-
raise PyODataModelError(f'Cannot decode datetime from value {value}.')
419+
except (ValueError, OverflowError):
420+
if FIX_SCREWED_UP_MINIMAL_DATETIME_VALUE and int(value) < -62135596800000:
421+
# Some service providers return false minimal date values.
422+
# -62135596800000 is the lowest value PyOData could read.
423+
# This workaroud fixes this issue and returns 0001-01-01 00:00:00+00:00 in such a case.
424+
value = datetime.datetime(year=1, day=1, month=1, tzinfo=current_timezone())
425+
elif FIX_SCREWED_UP_MAXIMUM_DATETIME_VALUE and int(value) > 253402300799999:
426+
value = datetime.datetime(year=9999, day=31, month=12, tzinfo=current_timezone())
427+
else:
428+
raise PyODataModelError(f'Cannot decode datetime from value {value}. '
429+
f'Possible value range: -62135596800000 to 253402300799999. '
430+
f'You may fix this by setting `FIX_SCREWED_UP_MINIMAL_DATETIME_VALUE` '
431+
f' or `FIX_SCREWED_UP_MAXIMUM_DATETIME_VALUE` as a workaround.')
419432

420433
return value
421434

tests/test_model_v2.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
PolicyIgnore, Config, PolicyFatal, NullType, NullAssociation, current_timezone, StructType
1010
from pyodata.exceptions import PyODataException, PyODataModelError, PyODataParserError
1111
from tests.conftest import assert_logging_policy
12+
import pyodata.v2.model
1213

1314

1415
def test_edmx(schema):
@@ -537,10 +538,20 @@ def test_traits_datetime():
537538
assert testdate.microsecond == 0
538539
assert testdate.tzinfo == current_timezone()
539540

541+
# parsing below lowest value with workaround
542+
pyodata.v2.model.FIX_SCREWED_UP_MINIMAL_DATETIME_VALUE = True
543+
testdate = typ.traits.from_json("/Date(-62135596800001)/")
544+
assert testdate.year == 1
545+
assert testdate.month == 1
546+
assert testdate.day == 1
547+
assert testdate.tzinfo == current_timezone()
548+
540549
# parsing the lowest value
541-
with pytest.raises(OverflowError):
550+
pyodata.v2.model.FIX_SCREWED_UP_MINIMAL_DATETIME_VALUE = False
551+
with pytest.raises(PyODataModelError) as e_info:
542552
typ.traits.from_json("/Date(-62135596800001)/")
543-
553+
assert str(e_info.value).startswith('Cannot decode datetime from value -62135596800001.')
554+
544555
testdate = typ.traits.from_json("/Date(-62135596800000)/")
545556
assert testdate.year == 1
546557
assert testdate.month == 1
@@ -551,9 +562,19 @@ def test_traits_datetime():
551562
assert testdate.microsecond == 0
552563
assert testdate.tzinfo == current_timezone()
553564

565+
# parsing above highest value with workaround
566+
pyodata.v2.model.FIX_SCREWED_UP_MAXIMUM_DATETIME_VALUE = True
567+
testdate = typ.traits.from_json("/Date(253402300800000)/")
568+
assert testdate.year == 9999
569+
assert testdate.month == 12
570+
assert testdate.day == 31
571+
assert testdate.tzinfo == current_timezone()
572+
554573
# parsing the highest value
555-
with pytest.raises(OverflowError):
574+
pyodata.v2.model.FIX_SCREWED_UP_MAXIMUM_DATETIME_VALUE = False
575+
with pytest.raises(PyODataModelError) as e_info:
556576
typ.traits.from_json("/Date(253402300800000)/")
577+
assert str(e_info.value).startswith('Cannot decode datetime from value 253402300800000.')
557578

558579
testdate = typ.traits.from_json("/Date(253402300799999)/")
559580
assert testdate.year == 9999

0 commit comments

Comments
 (0)