日期和时间
本页内容
概述
在本指南中,您可以学习如何处理Pythondatetime
对象在PyMongo中。
术语
Python使用一个专门的数据类型datetime.datetime
来表示日期和时间。MongoDB以协调世界时(UTC)存储datetime
值,这是一个以英国伦敦为本地时间的全球时间标准。
天真日期时间
当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
对象。将目标时区作为字符串传递给构造函数。在您的
timezone
对象上调用localize()
方法,传入要本地化的datetime
值。
以下代码示例将 datetime
值本地化到 "US/Pacific"
时区,偏移量为八小时
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 类型。在将日期对象保存到 MongoDB 之前,请将所有 date
对象转换为 datetime
对象。
读取日期时间
当您使用 PyMongo 获取 datetime
值时,驱动程序可以将它格式化为无时区的 UTC、带时区的 UTC 或本地化的值。以下各节将描述如何检索每种类型的值。
对于这些部分,假设名为 sample_collection
的 MongoDB 集合包含以下文档。字段 "date"
的值是一个 UTC datetime
值。
{"date": datetime(2002, 10, 27, 14, 0, 0)}
无知的 UTC datetime
默认情况下,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 datetime
要指示 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
如果您计划向用户显示 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
值是 naive 还是 aware
如果
datetime
是 naive,PyMongo 假设datetime
在 UTC,并按原样存储到 MongoDB。如果
datetime
是 aware,PyMongo 在将其存储到 MongoDB 之前自动将时间转换为 UTC。
以下代码示例插入一个包含本地化为 "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.min
到datetime.max
(年份1-9999)之间的datetime
值。通过使用BSON,您可以表示一个更广泛的日期和时间范围,它允许使用Unix纪元(Unix纪元。)的任何64位毫秒值。
要使用PyMongo表示BSON时间,创建一个datetime_ms.DatetimeMS
对象,它是Python内置的int
类型的包装器。您可以通过传递以下值之一手动创建一个DatetimeMS
对象
表示自Unix纪元以来经过的毫秒数的整数
datetime
对象
以下代码示例通过传递表示年份-146136543的整数值来构建一个DatetimeMS
对象,这是一个在datetime
范围之外的日期
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
是默认值。此值会导致PyMongo在尝试解码范围之外的日期时引发错误,如下例所示
DatetimeConversion.DATETIME
是默认值。此值会导致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')). ...
日期时间转换.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)}
日期时间转换.DATETIME_AUTO
此值指示当值在datetime
范围内时,PyMongo返回datetime
对象;否则返回一个DatetimeMS
对象。以下代码示例将日期时间范围内的一个日期和一个范围外的日期进行编码和解码。
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)}
日期时间转换.DATETIME_CLAMP
此值“限制”了结果datetime
对象,强制它们位于datetime
范围内(裁剪到999,000微秒)。
以下代码示例将日期时间范围之前的一个日期和一个日期时间范围之后的日期进行编码和解码。结果值位于允许范围的开始和结束。
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
在 pypi.org