[Bug] Negative POSIX timestamps cannot be deserialized after timestamp serialization

Author: Sohel2309Created Aug 13, 2026Updated Aug 18, 2026

Bug description

fields.DateTime(format="timestamp") can serialize valid datetimes before the Unix epoch (1970) into negative POSIX timestamps, but marshmallow then rejects those same negative values when deserializing them.

This creates a round-trip failure where a value produced by Marshmallow cannot be read back by the same field.

Reproduction

python
from datetime import datetime, timezone

from marshmallow import fields

field = fields.DateTime(format="timestamp")

value = datetime(1950, 5, 3, tzinfo=timezone.utc)

serialized = field.serialize("date", {"date": value})
print(serialized)
# -620568000.0

field.deserialize(serialized)
# marshmallow.exceptions.ValidationError:
# Not a valid datetime.

The underlying Python datetime.fromtimestamp() supports negative timestamps, so the negative value itself is valid.

Expected behavior

A timestamp produced by fields.DateTime(format="timestamp") should be accepted by the corresponding deserializer, including valid negative POSIX timestamps representing dates before 1970.

Actual behavior

Negative POSIX timestamps are rejected during deserialization, even though the serializer can produce them from valid pre-1970 datetimes.

This means timestamp serialization is not reliably round-tripable for dates before the Unix epoch.

Root cause

marshmallow.utils.from_timestamp() explicitly rejects values below zero before calling Python's timestamp conversion.

The underlying datetime.fromtimestamp() implementation can correctly handle these negative values, so the explicit negative-value restriction is unnecessarily broad.

Existing OSError and OverflowError handling can continue to handle genuine platform-specific timestamp conversion failures.

Proposed fix

Remove the explicit rejection of negative timestamp values from from_timestamp() and rely on the existing timestamp conversion and exception handling.

Add regression coverage that:

  1. Serializes valid pre-1970 datetimes using both timestamp and timestamp_ms.
  2. Confirms the serialized values are negative.
  3. Deserializes those values.
  4. Confirms the original datetimes are recovered.

Validation

I have reproduced the issue on the current development branch.

The regression test fails on the unfixed implementation and passes after the proposed fix.

The full test suite passes with the fix.

I would like to contribute a fix for this issue.

Source: marshmallow-code/marshmallow