get UTC timestamp in python with datetime
有没有办法通过指定日期来获取UTC时间戳? 我期待的是:
1 | datetime(2008, 1, 1, 0, 0, 0, 0) |
应该导致
1 | 1199145600 |
创建天真的日期时间对象意味着没有时区信息。 如果我查看datetime.utcfromtimestamp的文档,则创建UTC时间戳意味着省略时区信息。 所以我猜,创建一个天真的日期时间对象(就像我做的那样)会产生一个UTC时间戳。 然而:
1 2 | then = datetime(2008, 1, 1, 0, 0, 0, 0) datetime.utcfromtimestamp(float(then.strftime('%s'))) |
结果是
1 | 2007-12-31 23:00:00 |
datetime对象中是否还有隐藏的时区信息? 我究竟做错了什么?
什么是na?ve
默认
没有时区信息,您无法将"天真"的日期时间转换为任何非天真的时间表示(如果我们不知道从哪里开始,
要检查
1 2 | datetime.now() ## DANGER: returns na?ve datetime pointing on local time datetime(1970, 1, 1) ## returns na?ve datetime pointing on user given time |
我有很多日期,我该怎么办?
您必须根据您的具体情况做出假设:
您必须问自己的问题是:您的
-
如果你使用UTC(你没有遇到麻烦):
1
2
3
4
5
6
7
8
9
10import calendar
def dt2ts(dt):
"""Converts a datetime object to UTC timestamp
naive datetime will be considered UTC.
"""
return calendar.timegm(dt.utctimetuple()) -
如果你不使用UTC,欢迎来到地狱。
在使用前者之前,你必须让你的
datetime 非天真
功能,通过给他们回到他们想要的时区。您需要时区名称和相关信息
如果DST在产生目标天然日期时生效(
角柜需要有关DST的最后信息):1
2
3
4
5import pytz ## pip install pytz
mytz = pytz.timezone('Europe/Amsterdam') ## Set your timezone
dt = mytz.normalize(mytz.localize(dt, is_dst=True)) ## Set is_dst accordingly不提供
is_dst 的后果:不使用
is_dst 将生成不正确的时间(和UTC时间戳)
如果在落后DST到位时生成目标日期时间
(例如,通过删除一小时来改变DST时间)。提供不正确的
is_dst 当然会产生错误
时间(和UTC时间戳)仅限于DST重叠或孔。什么时候
提供
也是不正确的时间,发生在"洞"中(从未存在的时间到期)
转发DST),is_dst 将给出解释
如何考虑这个虚假的时间,这是唯一的情况
.normalize(..) 实际上会在这里做点什么,因为它会
将其翻译为实际有效时间(更改日期时间和
DST对象(如果需要)。请注意,.normalize() 不是必需的
在最后有一个正确的UTC时间戳,但可能是
如果您不喜欢在您的虚假时间中出现虚假时间的建议,建议您使用
变量,特别是如果你在其他地方重用这个变量。并使用以下内容避免:(cf:使用pytz进行日期时区转换)
1dt = dt.replace(tzinfo=timezone('Europe/Amsterdam')) ## BAD !!为什么?因为
.replace() 盲目地替换tzinfo 而没有
考虑到目标时间,将选择一个糟糕的DST对象。
而.localize() 使用目标时间和is_dst 提示
选择正确的DST对象。
旧的错误答案(感谢@ J.F.Sebastien提出这个问题):
希望在创建天真的
通过使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | def utc_mktime(utc_tuple): """Returns number of seconds elapsed since epoch Note that no timezone are taken into consideration. utc tuple must be: (year, month, day, hour, minute, second) """ if len(utc_tuple) == 6: utc_tuple += (0, 0, 0) return time.mktime(utc_tuple) - time.mktime((1970, 1, 1, 0, 0, 0, 0, 0, 0)) def datetime_to_timestamp(dt): """Converts a datetime object to UTC timestamp""" return int(utc_mktime(dt.timetuple())) |
您必须确保在与创建
最后一个解决方案是不正确的,因为它假设从现在起的UTC偏移量与EPOCH的UTC偏移量相同。对于很多时区而言并非如此(在夏令时(DST)偏移的一年中的特定时刻)。
另一种可能性是:
1 2 3 | d = datetime.datetime.utcnow() epoch = datetime.datetime(1970,1,1) t = (d - epoch).total_seconds() |
这适用于"d"和"epoch"都是天真的日期时间,使" -"运算符有效,并返回一个间隔。
另请注意此博客条目所描述的calendar.timegm()函数:
1 2 | import calendar calendar.timegm(utc_timetuple) |
输出应该与vaab的解决方案一致。
如果输入datetime对象是UTC:
1 2 3 | >>> dt = datetime(2008, 1, 1, 0, 0, 0, 0) >>> timestamp = (dt - datetime(1970, 1, 1)).total_seconds() 1199145600.0 |
注意:它返回浮点数,即微秒数表示为秒的分数。
如果输入日期对象是UTC:
1 2 3 4 | >>> from datetime import date >>> utc_date = date(2008, 1, 1) >>> timestamp = (utc_date.toordinal() - date(1970, 1, 1).toordinal()) * 24*60*60 1199145600 |
有关详细信息,请参阅在Python中将datetime.date转换为UTC时间戳。
我觉得主要答案仍然不是那么清楚,值得花时间去理解时间和时区。
处理时间时最重要的是时间是相对的!
因为同一时间字符串可以被解释为不同的时间点,具体取决于您在世界中的位置,因此需要绝对的时间概念。
UTC时间戳是Epoch的秒数(或毫秒)数(定义为
Epoch锚定在GMT时区,因此是一个绝对的时间点。因此,UTC时间戳是与绝对时间的偏移,因此定义了绝对时间点。
这使得可以及时订购事件。
没有时区信息,时间是相对的,并且不能转换为绝对的时间概念,而不提供天真日期时间应锚定到的时区的一些指示。
计算机系统中使用的时间类型是什么?
天真日期时间:通常用于显示,在本地时间(即在浏览器中),OS可以向程序提供时区信息。
UTC时间戳:UTC时间戳是绝对时间点,如上所述,但它锚定在给定时区,因此UTC时间戳可以在任何时区转换为日期时间,但不包含时区信息。那是什么意思?这意味着1504119325对应于
ISO-8601日期时间字符串:ISO-8601是一种标准格式,用于记录带有时区的日期时间。 (实际上有几种格式,请在此处阅读:https://en.wikipedia.org/wiki/ISO_8601)它用于在系统之间以可序列化的方式传达时区感知日期时间信息。
什么时候用哪个?或者更确切地说,何时需要关心时区?
如果您需要以任何方式关心时间,您需要时区信息。日历或闹钟需要时间来为世界上任何用户在当天的正确时间设置会议。如果此数据保存在服务器上,则服务器需要知道datetime对应的时区。
要计算来自世界不同地方的事件之间的时差,UTC时间戳就足够了,但是你无法分析在什么时间发生的事件(例如,对于网络分析,你可能想知道用户什么时候来到你的当地时间的网站:你在早上或晚上看到更多用户吗?没有时间信息,你无法弄明白。
日期字符串中的时区偏移量:
另一点很重要,即日期字符串中的时区偏移量不固定。这意味着因为
在夏天,它可能是夏令时,它将是
这意味着时区偏移量(+0100)与时区名称(欧洲/法国)或时区名称(CET)不同
因此,除了从日期字符串中获取时区偏移之外,还应该使时区名称准确。
大多数软件包都能够将数字偏移从夏令时转换为标准时间,但这并不一定只有偏移量。例如,西非的
所以,简而言之,它很复杂。非常复杂,这就是为什么你不应该自己做,但相信一个为你做的包,并保持最新!
好。
使用utcfromtimestamp并指定时区确实存在问题。以下问题提供了一个很好的示例/解释:
如何在转换为Unix时指定时区(UTC)? (Python)
接受的答案似乎对我不起作用。 我的解决方案
1 2 3 4 5 | import time utc_0 = int(time.mktime(datetime(1970, 01, 01).timetuple())) def datetime2ts(dt): """Converts a datetime object to UTC timestamp""" return int(time.mktime(dt.utctimetuple())) - utc_0 |
最简单的方法:
<击>
1 2 3 4 | >>> from datetime import datetime >>> dt = datetime(2008, 1, 1, 0, 0, 0, 0) >>> dt.strftime("%s") '1199163600' |
击>
编辑:@Daniel是正确的,这会将其转换为机器的时区。 这是修改后的答案:
1 2 3 4 5 | >>> from datetime import datetime, timezone >>> epoch = datetime(1970, 1, 1, 0, 0, 0, 0, timezone.utc) >>> dt = datetime(2008, 1, 1, 0, 0, 0, 0, timezone.utc) >>> int((dt-epoch).total_seconds()) '1199145600' |
实际上,它甚至不需要指定
1 2 3 4 5 | >>> from datetime import datetime >>> epoch = datetime(1970, 1, 1, 0, 0, 0, 0) >>> dt = datetime(2008, 1, 1, 0, 0, 0, 0) >>> int((dt-epoch).total_seconds()) 1199145600 |