Skip to content

Commit

Permalink
Merge pull request #190 from Scille/189_microsecond_overflow
Browse files Browse the repository at this point in the history
Fix millisecond overflow when milliseconds round to 1s in DateTimeField
  • Loading branch information
lafrech committed Apr 10, 2019
2 parents 3f53394 + cfaec9f commit 85df489
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 6 deletions.
13 changes: 13 additions & 0 deletions tests/test_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,19 @@ class MySchema(EmbeddedSchema):
})
assert data['a'].microsecond == 123000
assert data['b'].microsecond == 123000
s = MySchema()
data, _ = s.load({
'a': dt.datetime(2016, 8, 6, 12, 59, 59, 999876),
'b': dt.datetime(2016, 8, 6, 12, 59, 59, 999876),
})
assert data['a'].hour == 13
assert data['b'].hour == 13
assert data['a'].minute == 0
assert data['b'].minute == 0
assert data['a'].second == 0
assert data['b'].second == 0
assert data['a'].microsecond == 0
assert data['b'].microsecond == 0

def test_strictdatetime(self):

Expand Down
20 changes: 14 additions & 6 deletions umongo/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,16 +165,26 @@ class FloatField(BaseField, ma_fields.Float):
pass


def _round_to_millisecond(datetime):
"""Round a datetime to millisecond precision
MongoDB stores datetimes with a millisecond precision.
For consistency, use the same precision in the object representation.
"""
microseconds = round(datetime.microsecond, -3)
if microseconds == 1000000:
return datetime.replace(microsecond=0) + dt.timedelta(seconds=1)
return datetime.replace(microsecond=microseconds)


class DateTimeField(BaseField, ma_fields.DateTime):

def _deserialize(self, value, attr, data):
if isinstance(value, dt.datetime):
ret = value
else:
ret = super()._deserialize(value, attr, data)
# MongoDB stores datetimes with a millisecond precision.
# Don't keep more precision in the object than in the database.
return ret.replace(microsecond=round(ret.microsecond, -3))
return _round_to_millisecond(ret)


class LocalDateTimeField(BaseField, ma_fields.LocalDateTime):
Expand All @@ -184,9 +194,7 @@ def _deserialize(self, value, attr, data):
ret = value
else:
ret = super()._deserialize(value, attr, data)
# MongoDB stores datetimes with a millisecond precision.
# Don't keep more precision in the object than in the database.
return ret.replace(microsecond=round(ret.microsecond, -3))
return _round_to_millisecond(ret)


# class TimeField(BaseField, ma_fields.Time):
Expand Down

0 comments on commit 85df489

Please sign in to comment.