日期和时间
本页内容
概述
在本指南中,您可以学习如何处理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