Docs 菜单
Docs 主页
/ / /
pymongo
/

日期和时间

在此页面上

  • Overview
  • 术语
  • Naive Datetimes
  • 感知日期时间
  • 本地化
  • 读取日期时间
  • 原生 UTC 日期时间
  • 感知 UTC 日期时间
  • 本地化日期时间
  • 存储日期时间
  • 处理超出范围的日期时间
  • DatetimeConversion.DATETIME
  • DatetimeConversion.DATETIME_MS
  • DatetimeConversion.DATETIME_AUTO
  • DatetimeConversion.DATETIME_CLAMP
  • API 文档

在本指南中,您可以了解如何在 PyMongo 中处理 Python datetime对象。

Python使用专用数据类型datetime.datetime来表示日期和时间。 MongoDB以协调世界时 (UTC)存储datetime值,UTC 是英国伦敦当地的全球时间标准。

如果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值,请执行以下步骤:

  1. 使用 pip 在Python环境中安装pytz库: pip install pytz

  2. 创建一个pytz.timezone对象。 将目标时区域作为string传递给构造函数。

  3. 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)}

默认, 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

要指示 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

  • tzinfotimezone对象。

以下代码示例检索示例文档,但使用tz_awaretzinfo参数将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.mindatetime.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对象。 为此,请将CodecOptionsdatetime_conversion参数设置为datetime_ms.DatetimeConversion枚举中的值。 以下部分介绍了这些值。

提示

DatetimeMS 对象支持与DatetimeMS的其他实例进行丰富的比较方法。 您还可以使用DatetimeMS.to_datetime()方法将它们转换为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')).
...

此值指示 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范围内,则该值指示 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)}

此值“固定”生成的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)}

有关在PyMongo中处理日期和时间的更多信息,请参阅以下API文档:

后退

自定义类型