在 Python 中将 datetime.date 转换为 UTC 时间戳
Posted
技术标签:
【中文标题】在 Python 中将 datetime.date 转换为 UTC 时间戳【英文标题】:Converting datetime.date to UTC timestamp in Python 【发布时间】:2012-02-05 08:35:48 【问题描述】:我正在处理 Python 中的日期,我需要将它们转换为 UTC 时间戳以供使用 在 javascript 中。以下代码不起作用:
>>> d = datetime.date(2011,01,01)
>>> datetime.datetime.utcfromtimestamp(time.mktime(d.timetuple()))
datetime.datetime(2010, 12, 31, 23, 0)
首先将日期对象转换为日期时间也无济于事。我在link 尝试了这个例子,但是:
from pytz import utc, timezone
from datetime import datetime
from time import mktime
input_date = datetime(year=2011, month=1, day=15)
现在要么:
mktime(utc.localize(input_date).utctimetuple())
或
mktime(timezone('US/Eastern').localize(input_date).utctimetuple())
确实有效。
如此笼统的问题:如何根据 UTC 将日期转换为自纪元以来的秒数?
【问题讨论】:
How do I convert local time to UTC in Python?的可能重复 我不确定是否同意将其标记为副本。虽然解决方案相似,但问题却不同。一个(这个)正在尝试从datetime.date
创建时间戳,另一个正在尝试将字符串表示形式从一个时区转换为另一个时区。作为正在寻找解决此问题的方法的人,我可能无法得出结论,后者会提供我正在寻找的答案。
datetime(date.year,date.month,date.day).timestamp()
In Python, how do you convert a `datetime` object to seconds?的可能重复
注意:mktime 比其他方法慢 10 倍。由于您不太可能在热门路径中执行此操作,因此这很重要。
【参考方案1】:
一个完整的时间字符串包含:
日期 时间 utcoffset[+HHMM or -HHMM]
例如:
1970-01-01 06:00:00 +0500
== 1970-01-01 01:00:00 +0000
== UNIX timestamp:3600
$ python3
>>> from datetime import datetime
>>> from calendar import timegm
>>> tm = '1970-01-01 06:00:00 +0500'
>>> fmt = '%Y-%m-%d %H:%M:%S %z'
>>> timegm(datetime.strptime(tm, fmt).utctimetuple())
3600
注意:
UNIX timestamp
是一个浮点数,以自纪元以来的秒数表示,以 UTC 为单位。
编辑:
$ python3
>>> from datetime import datetime, timezone, timedelta
>>> from calendar import timegm
>>> dt = datetime(1970, 1, 1, 6, 0)
>>> tz = timezone(timedelta(hours=5))
>>> timegm(dt.replace(tzinfo=tz).utctimetuple())
3600
【讨论】:
@user908088 按照您的要求将1970-01-01 06:00:00 +0500
转换为3600
。
@user908088 python2
中没有timezone
,你可以手动计算(06:00:00
- +0500
= 01:00:00
)。【参考方案2】:
如果d = date(2011, 1, 1)
是UTC:
>>> from datetime import datetime, date
>>> import calendar
>>> timestamp1 = calendar.timegm(d.timetuple())
>>> datetime.utcfromtimestamp(timestamp1)
datetime.datetime(2011, 1, 1, 0, 0)
如果d
在本地时区:
>>> import time
>>> timestamp2 = time.mktime(d.timetuple()) # DO NOT USE IT WITH UTC DATE
>>> datetime.fromtimestamp(timestamp2)
datetime.datetime(2011, 1, 1, 0, 0)
如果本地时区的午夜与 UTC 的午夜不是同一时间实例,timestamp1
和 timestamp2
可能会有所不同。
如果d
对应于ambiguous local time (e.g., during DST transition) 或者如果d
是过去(未来)日期,此时UTC 偏移量可能不同并且
mktime()
可能返回错误结果C mktime()
在给定平台上无权访问 the tz database。你可以use pytz
module (e.g., via tzlocal.get_localzone()
) to get access to the tz database on all platforms。另外,utcfromtimestamp()
may fail and mktime()
may return non-POSIX timestamp if "right"
timezone is used。
在没有calendar.timegm()
的情况下转换代表UTC日期的datetime.date
对象:
DAY = 24*60*60 # POSIX day in seconds (exact value)
timestamp = (utc_date.toordinal() - date(1970, 1, 1).toordinal()) * DAY
timestamp = (utc_date - date(1970, 1, 1)).days * DAY
如何根据 UTC 将日期转换为自纪元以来的秒数?
将已经以 UTC 表示时间的 datetime.datetime
(不是 datetime.date
)对象转换为相应的 POSIX 时间戳(float
)。
Python 3.3+
datetime.timestamp()
:
from datetime import timezone
timestamp = dt.replace(tzinfo=timezone.utc).timestamp()
注意:必须明确提供timezone.utc
,否则.timestamp()
假定您的天真日期时间对象位于本地时区。
Python 3 (
来自datetime.utcfromtimestamp()
的文档:
没有从 datetime 实例中获取时间戳的方法, 但是对应于日期时间实例 dt 的 POSIX 时间戳可以是 很容易计算如下。对于一个天真的 dt:
timestamp = (dt - datetime(1970, 1, 1)) / timedelta(seconds=1)
对于有意识的 dt:
timestamp = (dt - datetime(1970,1,1, tzinfo=timezone.utc)) / timedelta(seconds=1)
有趣的阅读:Epoch time vs. time of day 关于现在几点了?和已经过了多少秒?
另见:datetime needs an "epoch" method
Python 2
为 Python 2 改编上述代码:
timestamp = (dt - datetime(1970, 1, 1)).total_seconds()
其中timedelta.total_seconds()
相当于(td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
在启用真除法的情况下计算得出。
Example
from __future__ import division
from datetime import datetime, timedelta
def totimestamp(dt, epoch=datetime(1970,1,1)):
td = dt - epoch
# return td.total_seconds()
return (td.microseconds + (td.seconds + td.days * 86400) * 10**6) / 10**6
now = datetime.utcnow()
print now
print totimestamp(now)
小心floating-point issues。
输出
2012-01-08 15:34:10.022403
1326036850.02
如何将感知的datetime
对象转换为 POSIX 时间戳
assert dt.tzinfo is not None and dt.utcoffset() is not None
timestamp = dt.timestamp() # Python 3.3+
在 Python 3 上:
from datetime import datetime, timedelta, timezone
epoch = datetime(1970, 1, 1, tzinfo=timezone.utc)
timestamp = (dt - epoch) / timedelta(seconds=1)
integer_timestamp = (dt - epoch) // timedelta(seconds=1)
在 Python 2 上:
# utc time = local time - utc offset
utc_naive = dt.replace(tzinfo=None) - dt.utcoffset()
timestamp = (utc_naive - datetime(1970, 1, 1)).total_seconds()
【讨论】:
对于 Python 2 的情况,为什么不:timestamp = (dt - datetime.fromtimestamp(0)).total_seconds()
?
@m01: datetime(1970, 1, 1)
更明确。 fromtimestamp()
在这里不正确(dt
是 UTC,所以应该使用 utcfromtimestamp()
)。
@fedorqui 查看答案中的totimestamp()
函数。
尽管我很喜欢 python,但它的日期时间库已严重损坏。
@Realfun:时区、夏令时转换、tz 数据库、闰秒独立于 Python 存在。【参考方案3】:
假设 1: 您正在尝试将日期转换为时间戳,但由于日期涵盖 24 小时,因此没有一个时间戳代表该日期。我假设您想表示该日期在午夜 (00:00:00.000) 的时间戳。
假设 2: 您提供的日期与特定时区无关,但是您希望确定与特定时区 (UTC) 的偏移量。在不知道日期所在的时区的情况下,无法计算特定时区的时间戳。我假设您希望将日期视为本地系统时区。
首先,您可以使用timetuple()
成员将日期实例转换为表示各种时间分量的元组:
dtt = d.timetuple() # time.struct_time(tm_year=2011, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=5, tm_yday=1, tm_isdst=-1)
然后您可以使用time.mktime
将其转换为时间戳:
ts = time.mktime(dtt) # 1293868800.0
您可以通过使用纪元时间本身 (1970-01-01) 对其进行测试来验证此方法,在这种情况下,该函数应返回该日期本地时区的时区偏移量:
d = datetime.date(1970,1,1)
dtt = d.timetuple() # time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=-1)
ts = time.mktime(dtt) # 28800.0
28800.0
是 8 小时,这对于太平洋时区(我所在的地方)是正确的。
【讨论】:
我不确定为什么这被否决了。它解决了 OP 的问题(OP 标记为“不工作”的工作代码)。它没有回答我的问题(将 UTC datetime.datetime 转换为时间戳),但仍然......赞成。 小心。 “您希望将日期视为在 本地系统 时区中的假设是 python 中时区所有问题的根源。除非您 100% 确定机器的本地化这将运行您的脚本,特别是如果为来自世界任何地方的客户提供服务,请始终假定日期为 UTC,并尽早进行转换。相信我,它会让您头疼。【参考方案4】:这个问题有点混乱。时间戳不是 UTC - 它们是 Unix 的东西。日期可能是UTC?假设是这样,并且如果您使用的是 Python 3.2+,simple-date 使这变得微不足道:
>>> SimpleDate(date(2011,1,1), tz='utc').timestamp
1293840000.0
如果您确实有年、月和日,则无需创建date
:
>>> SimpleDate(2011,1,1, tz='utc').timestamp
1293840000.0
如果日期在其他时区(这很重要,因为我们假设 午夜 没有相关时间):
>>> SimpleDate(date(2011,1,1), tz='America/New_York').timestamp
1293858000.0
[simple-date 背后的想法是在一个一致的类中收集所有 python 的日期和时间内容,因此您可以进行任何转换。所以,例如,它也会走另一条路:
>>> SimpleDate(1293858000, tz='utc').date
datetime.date(2011, 1, 1)
]
【讨论】:
SimpleDate(date(2011,1,1), tz='America/New_York')
引发NoTimezone
,而pytz.timezone('America/New_York')
不会引发任何异常(simple-date==0.4.8
、pytz==2014.7
)。
我在pip install simple-date
上收到一个错误,看起来它只是 python3/pip3。【参考方案5】:
按照python2.7文档,你必须使用calendar.timegm()而不是time.mktime()
>>> d = datetime.date(2011,01,01)
>>> datetime.datetime.utcfromtimestamp(calendar.timegm(d.timetuple()))
datetime.datetime(2011, 1, 1, 0, 0)
【讨论】:
如果d
是UTC,它与my answer 有何不同?【参考方案6】:
仅适用于 unix 系统:
>>> import datetime
>>> d = datetime.date(2011, 1, 1)
>>> d.strftime("%s") # <-- THIS IS THE CODE YOU WANT
'1293832800'
注意 1: dizzyf 观察到这适用于本地化时区。不要在生产中使用。
注 2:Jakub Narębski 指出,即使对于可感知偏移的日期时间(已针对 Python 2.7 测试),这忽略时区信息。
【讨论】:
如果您知道您的代码将在哪个系统下运行,这是一个很好的答案,但重要的是要注意并非所有操作系统上都存在“%s”格式字符串,因此此代码不可移植。如果你想检查它是否受支持,你可以在类 Unix 系统上检查man strftime
。
应该提到的是,这会减少小数秒部分(微秒或其他)。
警告:这适用于本地化的时区!根据机器时间,对于相同的 datetime 对象,您将获得不同的 strftime 行为
此外,此忽略时区信息并假设日期时间在本地时区即使对于偏移感知日期时间,设置了 tzinfo。好吧,至少在 Python 2.7 中。
javascript 时间戳 = python 时间戳 * 1000【参考方案7】:
使用arrow 包:
>>> import arrow
>>> arrow.get(2010, 12, 31).timestamp
1293753600
>>> time.gmtime(1293753600)
time.struct_time(tm_year=2010, tm_mon=12, tm_mday=31,
tm_hour=0, tm_min=0, tm_sec=0,
tm_wday=4, tm_yday=365, tm_isdst=0)
【讨论】:
注意:arrow
使用 dateutil
和 dateutil
已知与时区处理相关的 for many years bugs。如果您需要具有非固定 UTC 偏移量的时区的正确结果,请不要使用它(可以将其用于 UTC 时区,但 stdlib 也可以处理 UTC 情况)。
@J.F.Sebastian 该错误仅在在过渡期间发生,时间不明确。
这个bug好像在3月28日修复了
看起来,它是最好的跨 python 解决方案。只需使用箭头。谢谢;)
@MathieuLongtin dateutil 可能有 other issues【参考方案8】:
我定义了我自己的两个函数
utc_time2datetime(utc_time, tz=None) datetime2utc_time(datetime)这里:
import time
import datetime
from pytz import timezone
import calendar
import pytz
def utc_time2datetime(utc_time, tz=None):
# convert utc time to utc datetime
utc_datetime = datetime.datetime.fromtimestamp(utc_time)
# add time zone to utc datetime
if tz is None:
tz_datetime = utc_datetime.astimezone(timezone('utc'))
else:
tz_datetime = utc_datetime.astimezone(tz)
return tz_datetime
def datetime2utc_time(datetime):
# add utc time zone if no time zone is set
if datetime.tzinfo is None:
datetime = datetime.replace(tzinfo=timezone('utc'))
# convert to utc time zone from whatever time zone the datetime is set to
utc_datetime = datetime.astimezone(timezone('utc')).replace(tzinfo=None)
# create a time tuple from datetime
utc_timetuple = utc_datetime.timetuple()
# create a time element from the tuple an add microseconds
utc_time = calendar.timegm(utc_timetuple) + datetime.microsecond / 1E6
return utc_time
【讨论】:
我直接浏览了您的示例。对于这样一个简单的事情来说,方式变得混乱和复杂。根本不是 Python 的。 @Mayhem:我稍微清理了一下并添加了 cmets。如果您有更好和更通用的解决方案来将时间转换为日期时间并返回能够设置时区的蜜蜂 - 请告诉我们。也让我知道我的代码的更多 pythonic 示例应该是什么样子。【参考方案9】:我对深入的讨论印象深刻。
我的 2 美分:
from datetime import datetime
import time
UTC 时间戳为:
timestamp = \
(datetime.utcnow() - datetime(1970,1,1)).total_seconds()
或者,
timestamp = time.time()
如果现在来自 datetime.now(),在同一个 DST 中
utcoffset = (datetime.now() - datetime.utcnow()).total_seconds()
timestamp = \
(now - datetime(1970,1,1)).total_seconds() - utcoffset
【讨论】:
【参考方案10】:考虑到您有一个名为d
的datetime
对象,
使用以下方法获取 UTC 时间戳:
d.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
对于相反的方向,使用以下:
d = datetime.strptime("2008-09-03T20:56:35.450686Z", "%Y-%m-%dT%H:%M:%S.%fZ")
【讨论】:
【参考方案11】:这对我有用,通过一个函数。
from datetime import timezone, datetime, timedelta
import datetime
def utc_converter(dt):
dt = datetime.datetime.now(timezone.utc)
utc_time = dt.replace(tzinfo=timezone.utc)
utc_timestamp = utc_time.timestamp()
return utc_timestamp
# create start and end timestamps
_now = datetime.datetime.now()
str_start = str(utc_converter(_now))
_end = _now + timedelta(seconds=10)
str_end = str(utc_converter(_end))
【讨论】:
以上是关于在 Python 中将 datetime.date 转换为 UTC 时间戳的主要内容,如果未能解决你的问题,请参考以下文章