PYTHON-3376/PYTHON-3378 Update FAQ about OverflowError when decoding out of range datetimes (#1025)
This commit is contained in:
parent
13e2715af0
commit
92a6fa79b6
@ -125,33 +125,53 @@ To decode UTC datetime values as :class:`~bson.datetime_ms.DatetimeMS`,
|
||||
:attr:`~bson.datetime_ms.DatetimeConversionOpts.DATETIME_AUTO`,
|
||||
:attr:`~bson.datetime_ms.DatetimeConversionOpts.DATETIME_CLAMP`.
|
||||
:attr:`~bson.datetime_ms.DatetimeConversionOpts.DATETIME` is the default
|
||||
option and has the behavior of raising an exception upon attempting to
|
||||
decode an out-of-range date.
|
||||
option and has the behavior of raising an :class:`~builtin.OverflowError` upon
|
||||
attempting to decode an out-of-range date.
|
||||
:attr:`~bson.datetime_ms.DatetimeConversionOpts.DATETIME_MS` will only return
|
||||
:class:`~bson.datetime_ms.DatetimeMS` objects, regardless of whether the
|
||||
represented datetime is in- or out-of-range.
|
||||
:attr:`~bson.datetime_ms.DatetimeConversionOpts.DATETIME_AUTO` will return
|
||||
:class:`~datetime.datetime` if the underlying UTC datetime is within range,
|
||||
or :class:`~bson.datetime_ms.DatetimeMS` if the underlying datetime
|
||||
cannot be represented using the builtin Python :class:`~datetime.datetime`.
|
||||
:attr:`~bson.datetime_ms.DatetimeConversionOpts.DATETIME_CLAMP` will clamp
|
||||
resulting :class:`~datetime.datetime` objects to be within
|
||||
:attr:`~datetime.datetime.min` and :attr:`~datetime.datetime.max`
|
||||
(trimmed to `999000` microseconds).
|
||||
|
||||
An example of encoding and decoding using `DATETIME_MS` is as follows:
|
||||
represented datetime is in- or out-of-range:
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> from datetime import datetime
|
||||
>>> from bson import encode, decode
|
||||
>>> from bson.datetime_ms import DatetimeMS
|
||||
>>> from bson.codec_options import CodecOptions,DatetimeConversionOpts
|
||||
>>> from bson.codec_options import CodecOptions, DatetimeConversionOpts
|
||||
>>> x = encode({"x": datetime(1970, 1, 1)})
|
||||
>>> x
|
||||
b'\x10\x00\x00\x00\tx\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
>>> decode(x, codec_options=CodecOptions(datetime_conversion=DatetimeConversionOpts.DATETIME_MS))
|
||||
>>> codec_ms = CodecOptions(datetime_conversion=DatetimeConversionOpts.DATETIME_MS)
|
||||
>>> decode(x, codec_options=codec_ms)
|
||||
{'x': DatetimeMS(0)}
|
||||
|
||||
:attr:`~bson.datetime_ms.DatetimeConversionOpts.DATETIME_AUTO` will return
|
||||
:class:`~datetime.datetime` if the underlying UTC datetime is within range,
|
||||
or :class:`~bson.datetime_ms.DatetimeMS` if the underlying datetime
|
||||
cannot be represented using the builtin Python :class:`~datetime.datetime`:
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> x = encode({"x": datetime(1970, 1, 1)})
|
||||
>>> y = encode({"x": DatetimeMS(-2**62)})
|
||||
>>> codec_auto = CodecOptions(datetime_conversion=DatetimeConversionOpts.DATETIME_AUTO)
|
||||
>>> decode(x, codec_options=codec_auto)
|
||||
{'x': datetime.datetime(1970, 1, 1, 0, 0)}
|
||||
>>> decode(y, codec_options=codec_auto)
|
||||
{'x': DatetimeMS(-4611686018427387904)}
|
||||
|
||||
:attr:`~bson.datetime_ms.DatetimeConversionOpts.DATETIME_CLAMP` will clamp
|
||||
resulting :class:`~datetime.datetime` objects to be within
|
||||
:attr:`~datetime.datetime.min` and :attr:`~datetime.datetime.max`
|
||||
(trimmed to `999000` microseconds):
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> x = encode({"x": DatetimeMS(2**62)})
|
||||
>>> y = encode({"x": DatetimeMS(-2**62)})
|
||||
>>> codec_clamp = CodecOptions(datetime_conversion=DatetimeConversionOpts.DATETIME_CLAMP)
|
||||
>>> decode(x, codec_options=codec_clamp)
|
||||
{'x': datetime.datetime(9999, 12, 31, 23, 59, 59, 999000)}
|
||||
>>> decode(y, codec_options=codec_clamp)
|
||||
{'x': datetime.datetime(1, 1, 1, 0, 0)}
|
||||
|
||||
:class:`~bson.datetime_ms.DatetimeMS` objects have support for rich comparison
|
||||
methods against other instances of :class:`~bson.datetime_ms.DatetimeMS`.
|
||||
They can also be converted to :class:`~datetime.datetime` objects with
|
||||
|
||||
41
doc/faq.rst
41
doc/faq.rst
@ -264,7 +264,7 @@ collection, configured to use :class:`~bson.son.SON` instead of dict:
|
||||
>>> from bson import CodecOptions, SON
|
||||
>>> opts = CodecOptions(document_class=SON)
|
||||
>>> opts
|
||||
CodecOptions(document_class=...SON..., tz_aware=False, uuid_representation=UuidRepresentation.UNSPECIFIED, unicode_decode_error_handler='strict', tzinfo=None, type_registry=TypeRegistry(type_codecs=[], fallback_encoder=None))
|
||||
CodecOptions(document_class=...SON..., tz_aware=False, uuid_representation=UuidRepresentation.UNSPECIFIED, unicode_decode_error_handler='strict', tzinfo=None, type_registry=TypeRegistry(type_codecs=[], fallback_encoder=None), datetime_conversion=DatetimeConversionOpts.DATETIME)
|
||||
>>> collection_son = collection.with_options(codec_options=opts)
|
||||
|
||||
Now, documents and subdocuments in query results are represented with
|
||||
@ -489,9 +489,42 @@ limited to years between :data:`datetime.MINYEAR` (usually 1) and
|
||||
driver) can store BSON datetimes with year values far outside those supported
|
||||
by :class:`datetime.datetime`.
|
||||
|
||||
There are a few ways to work around this issue. One option is to filter
|
||||
out documents with values outside of the range supported by
|
||||
:class:`datetime.datetime`::
|
||||
There are a few ways to work around this issue. Starting with PyMongo 4.3,
|
||||
:func:`bson.decode` can decode BSON datetimes in one of four ways, and can
|
||||
be specified using the ``datetime_conversion`` parameter of
|
||||
:class:`~bson.codec_options.CodecOptions`.
|
||||
|
||||
The default option is
|
||||
:attr:`~bson.codec_options.DatetimeConversionOpts.DATETIME`, which will
|
||||
attempt to decode as a :class:`datetime.datetime`, allowing
|
||||
:class:`~builtin.OverflowError` to occur upon out-of-range dates.
|
||||
:attr:`~bson.codec_options.DatetimeConversionOpts.DATETIME_AUTO` alters
|
||||
this behavior to instead return :class:`~bson.datetime_ms.DatetimeMS` when
|
||||
representations are out-of-range, while returning :class:`~datetime.datetime`
|
||||
objects as before:
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> from datetime import datetime
|
||||
>>> from bson.datetime_ms import DatetimeMS
|
||||
>>> from bson.codec_options import DatetimeConversionOpts
|
||||
>>> from pymongo import MongoClient
|
||||
>>> client = MongoClient(datetime_conversion=DatetimeConversionOpts.DATETIME_AUTO)
|
||||
>>> client.db.collection.insert_one({"x": datetime(1970, 1, 1)})
|
||||
<pymongo.results.InsertOneResult object at 0x...>
|
||||
>>> client.db.collection.insert_one({"x": DatetimeMS(2**62)})
|
||||
<pymongo.results.InsertOneResult object at 0x...>
|
||||
>>> for x in client.db.collection.find():
|
||||
... print(x)
|
||||
{'_id': ObjectId('...'), 'x': datetime.datetime(1970, 1, 1, 0, 0)}
|
||||
{'_id': ObjectId('...'), 'x': DatetimeMS(4611686018427387904)}
|
||||
|
||||
For other options, please refer to
|
||||
:class:`~bson.codec_options.DatetimeConversionOpts`.
|
||||
|
||||
Another option that does not involve setting `datetime_conversion` is to to
|
||||
filter out documents values outside of the range supported by
|
||||
:class:`~datetime.datetime`:
|
||||
|
||||
>>> from datetime import datetime
|
||||
>>> coll = client.test.dates
|
||||
|
||||
Loading…
Reference in New Issue
Block a user