python-3.x - PyMongo/Python/Airflow - 将 CST 日期/日期时间转换为 UTC 并以 ISO 格式存储在 MongoDB 中?
问题描述
将 CST 日期和/或日期时间字段与 DST 感知设置一起转换为 UTC 并在 Python/PyMongo 中以 ISO 格式存储在 MongoDB 中的正确、理想或首选方法是什么?源日期/日期时间字段可以来自任何时区(现在我们知道它的 CST),我需要将它们全部转换为 UTC 并存储到目标 MongoDB 中。
根据 MongoDB 文档,MongoDB 默认以 UTC 存储时间,并将任何本地时间表示转换为这种形式。必须对某些未修改的本地时间值进行操作或报告的应用程序可以将时区与 UTC 时间戳一起存储,并在其应用程序逻辑中计算原始本地时间。
例子:
方法#1:使用时间戳(定义本地时区)
from datetime import datetime
import pytz
local_timezone = pytz.timezone("US/Central")
utc_datetime = local_timezone.localize(datetime.strptime ("1/2/2017 12:43 pm",'%m/%d/%Y %H:%M %p'),is_dst=True).astimezone(pytz.utc)
print(utc_datetime)
print(type(utc_datetime))
2017-01-02 18:43:00+00:00
<class 'datetime.datetime'>
没有时间戳,即只是日期: - 它在时间戳和 DST 5 小时内添加 6 小时的偏移值。删除或不删除astimezone(pytz.utc),它返回日期/时间,如 2017-01-02 00:00:00-06:00 即显示 -6 小时偏移差异。我们真的应该使用 astimezeon(pytz.utc) 吗?
from datetime import datetime
import pytz
local_timezone = pytz.timezone("US/Central")
utc_datetime = local_timezone.localize(datetime.strptime ("1/2/2017",'%m/%d/%Y'),is_dst=True).astimezone(pytz.utc)
print(utc_datetime)
print(type(utc_datetime))
2017-01-02 06:00:00+00:00
<class 'datetime.datetime'>
方法#2:带时间戳(本地时区未定义)
from datetime import datetime, timezone
utc_datetime=datetime.utcfromtimestamp(datetime.strptime ("1/2/2017 12:43 pm",'%m/%d/%Y %H:%M %p').replace(tzinfo = timezone.utc).timestamp())
print(utc_datetime)
print(type(utc_datetime))
2017-01-02 12:43:00
<class 'datetime.datetime'>
没有时间戳,即只是日期部分 - 没有偏移
from datetime import datetime, timezone
utc_datetime=datetime.utcfromtimestamp(datetime.strptime ("1/2/2017",'%m/%d/%Y').replace(tzinfo = timezone.utc).timestamp())
print(utc_datetime)
print(type(utc_datetime))
2017-01-02 00:00:00
<class 'datetime.datetime'>
加载到 MongoDB 后 - 它在日期/时间戳的末尾添加一个“Z”。在启动与 MongoClient 的连接时,我是否还应该添加“tz_aware=True”?
ISOFormat - 将 UTC 时间戳以上更改为 isoformat() 返回并在 MongoDB 中作为字符串而不是日期加载。那么,我们如何确保它仍然以 ISO 日期格式存储在 MongoDB 中?
utc_datetime_iso=datetime.utcfromtimestamp(datetime.strptime ("1/2/2017",'%m/%d/%Y').replace(tzinfo = timezone.utc).timestamp()).**isoformat()**
print(utc_datetime_iso)
print(type(utc_datetime_iso))
2017-01-02T00:00:00
<class 'str'>
解决方案
我从来没有使用过python,所以我只能给出一些一般性的注释。
永远不要将日期/时间值存储为字符串,使用适当的Date
对象。将日期/时间值存储为字符串通常是设计失败。
MongoDB 中的所有Date
值都以 UTC 存储 - 始终且仅。一些客户端应用程序将 UTC 隐式转换为本地时间并显示本地值,但是在 MongoDB 内部它始终是 UTC。
如果运行db.collection.insertOne({ts: ISODate("2020-09-07T14:00:00+02:00")})
then MongoDB stores ISODate("2020-09-07T12:00:00Z")
,原始时区信息会丢失。如果您需要保留原始时区,则必须将其存储在单独的字段中。
ISODate
只是new Date
. 但是,有区别。如果您未指定任何时区(例如"2020-09-07T14:00:00"
),则new Date()
假定为本地时间,但ISODate()
假定为 UTC 时间。我不知道python内部使用了哪种方法。
所以,new Date("2020-09-07T14:00:00")
结果是,2020-09-07 12:00:00Z
而ISODate("2020-09-07T14:00:00")
结果是2020-09-07 14:00:00Z