日期和时间
在此页面上
Overview
在本指南中,您可以了解如何在 PyMongo 中处理 Python datetime
对象。
术语
Python使用专用数据类型datetime.datetime
来表示日期和时间。 MongoDB以协调世界时 (UTC)存储datetime
值,UTC 是英国伦敦当地的全球时间标准。
Naive Datetimes
如果datetime
值不包含有关其UTC偏移量或时区域的补充信息,则该值为原生值。 以下是原生datetime
对象的示例:
datetime(2002, 10, 27, 14, 0, 0)
感知日期时间
当datetime
值包含tzinfo
属性时,它就会感知。 该属性指示该值相对于 UTC 时间的偏移量、时区以及夏令时是否有效。 以下是感知datetime
对象的示例:
datetime(2002, 10, 27, 6, 0, tzinfo=<DstTzInfo 'US/Pacific' PST-1 day, 16:00:00 STD>)
本地化
本地化是在datetime
值上增加或减少小时数以将其值转换为另一个时区域的进程。 要本地化datetime
值,请执行以下步骤:
使用 pip 在Python环境中安装
pytz
库:pip install pytz
创建一个
pytz.timezone
对象。 将目标时区域作为string传递给构造函数。对
timezone
对象调用localize()
方法,传入要本地化的datetime
值。
以下代码示例将datetime
值本地化为"US/Pacific"
时区,即偏移 8 小时:
from datetime import datetime from pytz import timezone utc_datetime = datetime(2002, 10, 27, 6, 0, 0) pacific = timezone("US/Pacific") local_datetime = pacific.localize(utc_datetime) print(f"UTC datetime: {utc_datetime}") print(f"Local datetime: {local_datetime}")
UTC datetime: 2002-10-27 06:00:00 Local datetime: 2002-10-27 06:00:00-08:00
有关时区域字符串的规范列表,请参阅 时区数据库 或维基百科上的相应文章。
重要
使用PyMongo时,您无法保存datetime.date
实例,因为没有时间的日期没有BSON类型。 在将所有date
对象保存到MongoDB之前,将其转换为datetime
对象。
读取日期时间
当您使用PyMongo检索datetime
值时,驾驶员可以将其格式化为原生 UTC、感知 UTC 或本地化值。 以下部分描述了如何检索每种值。
对于这些部分,假设名为sample_collection
的MongoDB集合包含以下文档。 "date"
字段的值是 UTC datetime
值。
{"date": datetime(2002, 10, 27, 14, 0, 0)}
原生 UTC 日期时间
默认, PyMongo检索没有补充信息的 UTC datetime
值。 以下代码示例检索示例文档并打印datetime
值。 打印的值与示例文档中的值相同。
from datetime import datetime collection = database["sample_collection"] find_result = collection.find_one()["date"] print(f"datetime: {find_result}") print(f"datetime.tzinfo: {find_result.tzinfo}")
datetime: 2002-10-27 14:00:00 datetime.tzinfo: None
感知 UTC 日期时间
要指示 PyMongo 检索感知的datetime
值,请创建一个CodecOptions
对象并将tz_aware = True
传递给构造函数。 然后,将CodecOptions
对象传递给get_collection()
方法。
以下代码示例从示例文档中检索datetime
值作为感知的datetime
:
from pymongo import MongoClient from datetime import datetime from bson.codec_options import CodecOptions options = CodecOptions(tz_aware = True) collection = database.get_collection("sample_collection", options) find_result = collection.find_one()["date"] print(f"datetime: {find_result}") print(f"datetime.tzinfo: {find_result.tzinfo}")
datetime: 2002-10-27 14:00:00+00:00 datetime.tzinfo: <bson.tz_util.FixedOffset object at 0x104db2b80>
本地化日期时间
如果计划向用户显示datetime
值,则可以指示 PyMongo 自动将从 MongoDB 读取的所有时间转换为特定时区。 为此,请为目标时区创建一个timezone
对象,如术语部分所述。 然后,创建一个CodecOptions
对象并将以下参数传递给构造函数:
tz_aware
:设置为True
。tzinfo
:timezone
对象。
以下代码示例检索示例文档,但使用tz_aware
和tzinfo
参数将datetime
值自动本地化为"US/Pacific"
时区域:
from pymongo import MongoClient from datetime import datetime from bson.codec_options import CodecOptions import pytz from pytz import timezone pacific = timezone("US/Pacific") options = CodecOptions(tz_aware = True, tzinfo = pacific) collection = database.get_collection("sample_collection", options) find_result = collection.find_one()["date"] print(f"datetime: {find_result}") print(f"datetime.tzinfo: {find_result.tzinfo}")
datetime: 2002-10-27 06:00:00-08:00 datetime.tzinfo: US/Pacific
提示
前面的示例在集合级别指定了编解码器选项。 您还可以在客户端或数据库级别指定编解码器选项。
存储日期时间
为了一致性,仅将 UTC datetime
值存储到MongoDB。 当您使用PyMongo创建或更新包含datetime
值的字段时,驾驶员会首先检查datetime
值是原生值还是感知值:
如果
datetime
为原生,PyMongo 假定datetime
采用 UTC 格式,并将其原封不动地存储到 MongoDB 中。如果
datetime
感知,PyMongo 会自动将时间转换为 UTC,然后再存储到 MongoDB。
以下代码示例插入一个包含本地化为"US/Pacific"
时区的datetime
值的文档。 PyMongo 使用附加时区将本地时间转换为 UTC。 从 MongoDB 检索文档时, datetime
值采用 UTC。
from pymongo import MongoClient from datetime import datetime from pytz import timezone utc_datetime = datetime(2002, 10, 27, 6, 0, 0) pacific = timezone("US/Pacific") local_datetime = pacific.localize(utc_datetime) print(f"datetime before storage: {local_datetime}") collection.insert_one({"date": local_datetime}) find_result = collection.find_one()["date"] print(f"datetime after storage: {find_result}")
datetime before storage: 2002-10-27 06:00:00-08:00 datetime after storage: 2002-10-27 14:00:00
重要
datetime.now()
避免调用不带参数的datetime.now()
方法。 这将返回当前本地时间。
相反,请始终调用datetime.now(tz=datetime.timezone.utc)
方法,该方法会返回 UTC 格式的当前时间。
处理超出范围的日期时间
Python 的datetime
类只能表示datetime
datetime.min
和datetime.max
(年份1 -9999 )之间的 值。您可以使用BSON表示更大范围的日期和时间,它允许来自64 Unix 纪元 的任何 位毫秒值。
要使用PyMongo表示BSON时间,请创建一个datetime_ms.DatetimeMS
对象,它是 Python内置int
类型的包装器。 您可以通过传入以下值之一来手动创建DatetimeMS
对象:
表示自 Unix 纪元以来的毫秒数的
int
datetime
对象
以下代码示例通过传入表示年份 - 146136543的int
值和datetime
范围之外的日期来构造一个DatetimeMS
对象:
from bson.datetime_ms import DatetimeMS out_of_range = DatetimeMS(-(2**62))
您还可以指示 PyMongo 自动将 UTC datetime
值解码为DatetimeMS
对象。 为此,请将CodecOptions
的datetime_conversion
参数设置为datetime_ms.DatetimeConversion
枚举中的值。 以下部分介绍了这些值。
提示
DatetimeMS
对象支持与DatetimeMS
的其他实例进行丰富的比较方法。 您还可以使用DatetimeMS.to_datetime()
方法将它们转换为datetime
对象。
DatetimeConversion.DATETIME
DatetimeConversion.DATETIME
是默认值。 当 PyMongo 尝试解码超出范围的日期时,该值会导致PyMongo引发错误,如以下示例所示:
from datetime import datetime from bson import encode, decode from bson.datetime_ms import DatetimeMS out_of_range = DatetimeMS(-(2**62)) val = encode({"date": out_of_range}) decoded = decode(val) print(decoded)
... bson.errors.InvalidBSON: year -146136543 is out of range (Consider Using CodecOptions(datetime_conversion=DATETIME_AUTO) or MongoClient(datetime_conversion='DATETIME_AUTO')). ...
DatetimeConversion.DATETIME_MS
此值指示 PyMongo 仅返回DatetimeMS
对象,即使日期在datetime
范围内:
from datetime import datetime from bson import encode, decode from bson.datetime_ms import DatetimeMS from bson.codec_options import CodecOptions, DatetimeConversion val = encode({"date": datetime(1970, 1, 2)}) codec_ms = CodecOptions(datetime_conversion=DatetimeConversion.DATETIME_MS) decoded = decode(val, codec_options=codec_ms) print(decoded)
{"date": DatetimeMS(86400000)}
DatetimeConversion.DATETIME_AUTO
如果该值在datetime
范围内,则该值指示 PyMongo 返回datetime
对象,否则返回DatetimeMS
对象。 以下代码示例对datetime
范围内的一个日期时间和该范围外的一个日期时间进行编码和解码:
from datetime import datetime from bson import encode, decode from bson.datetime_ms import DatetimeMS from bson.codec_options import CodecOptions, DatetimeConversion in_range = encode({"date": datetime(1970, 1, 1)}) out_of_range = encode({"date": DatetimeMS(-(2**62))}) codec_auto = CodecOptions(datetime_conversion=DatetimeConversion.DATETIME_AUTO) in_decoded = decode(in_range, codec_options=codec_auto) out_decoded = decode(out_of_range, codec_options=codec_auto) print(f"in-range date: {in_decoded}") print(f"out-of-range date: {out_decoded}")
in-range date: {"date": datetime.datetime(1970, 1, 1, 0, 0)} out-of-range date: {'x': DatetimeMS(-4611686018427387904)}
DatetimeConversion.DATETIME_CLAMP
此值“固定”生成的datetime
对象,强制它们处于datetime
范围内(修剪到999 、 000微秒)。
以下代码示例对早于datetime
范围的一个日期时间和晚于datetime
范围的一个日期时间进行编码和解码。 结果值位于允许范围的上下限之间。
from datetime import datetime from bson import encode, decode from bson.datetime_ms import DatetimeMS from bson.codec_options import CodecOptions, DatetimeConversion before = encode({"date": DatetimeMS(-(2**62))}) after = encode({"date": DatetimeMS(2**62)}) codec_clamp = CodecOptions(datetime_conversion=DatetimeConversion.DATETIME_CLAMP) before_decoded = decode(before, codec_options=codec_clamp) after_decoded = decode(after, codec_options=codec_clamp) print(f"datetime before the range: {before_decoded}") print(f"datetime after the range: {after_decoded}")
datetime before the range: {"date": datetime.datetime(1, 1, 1, 0, 0)} datetime after the range: {"date": datetime.datetime(9999, 12, 31, 23, 59, 59, 999000)}
API 文档
有关在PyMongo中处理日期和时间的更多信息,请参阅以下API文档:
datetime
在 docs.Python.orgpytz
at pypi.org