MongoDB
BSON Date is UTC milliseconds since the epoch — no zone fidelity.
MongoDB’s BSON format includes a Date type: a signed 64-bit integer representing milliseconds since the Unix epoch (1970-01-01T00:00:00Z). It always represents a UTC instant. Millisecond precision means values like 2026-06-05T14:00:00.123Z round-trip cleanly, but sub-millisecond precision (microseconds, nanoseconds) is lost. No time zone or UTC offset is stored — only the numeric distance from the epoch.
MongoDB drivers automatically convert BSON Date to and from the host language’s date type (Python datetime, JavaScript Date, Java Instant, etc.). The conversion is handled transparently, but the underlying semantics are the same: you get back an instant in UTC, not a zoned date-time. If you need to preserve what time zone a user was in, or store a civil date-time (e.g. “the meeting is at 9 AM Tokyo time”), you must store that zone information in a separate field.
Preserving zone context
A common pattern is to store a parallel string field alongside the BSON Date:
{
"scheduledAt": ISODate("2026-06-05T00:00:00Z"),
"scheduledAtZone": "Asia/Tokyo"
}
The Date field handles indexing, sorting, and range queries efficiently. The zone field preserves the original intent for display and recurrence logic.
Pitfall: Storing civil times as BSON Date values, then reading them back and displaying them in the original zone by relying on the driver to “remember” the zone. The driver cannot; it returns a UTC instant. Without a stored zone name, you cannot reconstruct the original wall-clock representation reliably.
For a pure date with no time at all — a birthday, an invoice date — there is no lossless native type, since BSON Date is always an instant. Storing it as a plain ISO date string ("1990-05-23") is often the more honest option: a few extra bytes and a cast to a real date object on read, in exchange for a value that stays explicit about what it is instead of inventing a midnight-UTC time and offset. The small upfront cost buys you a representation that cannot silently drift across a day boundary. See Store vs display.
Go deeper: millisecond precision and the shell's ISODate()
The MongoDB shell and drivers accept ISO 8601 strings to construct BSON Date values — ISODate("2026-06-05T14:00:00Z") — but any sub-millisecond component is truncated silently. Applications that produce nanosecond-precision timestamps (common with system clocks on Linux) will lose that precision on insert. If you need finer granularity, store the sub-millisecond remainder as a separate integer field, or consider storing the entire value as a Decimal128 or string.
Because BSON Date is a 64-bit signed integer of milliseconds, it covers a range of roughly ±292 million years from the epoch, so range overflow is not a practical concern. However, many drivers use the host language’s Date or datetime type, which may have narrower ranges — Python’s datetime is valid from year 1 to 9999, for instance.
For applications where zone identity matters (scheduling, user-facing times, audit logs), adopt a schema convention: always pair a BSON Date instant with an IANA zone string. Validate this in your application layer rather than relying on MongoDB schema validation, since $jsonSchema does not enforce cross-field semantic rules.
See also Instant vs civil time and Time zones vs offsets.