在Python中将datetime.date转换为UTC时间戳


295

我正在使用Python处理日期,因此需要将其转换为UTC时间戳以在Javascript中使用。以下代码不起作用:

>>> d = datetime.date(2011,01,01)
>>> datetime.datetime.utcfromtimestamp(time.mktime(d.timetuple()))
datetime.datetime(2010, 12, 31, 23, 0)

首先将日期对象转换为datetime也无济于事。我从以下链接尝试了此示例,但是:

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将日期转换为自纪元以来的秒数?



29
我不确定是否同意将其标记为重复。尽管解决方案相似,但问题并非如此。一个(此一个)正尝试从创建一个时间戳datetime.date,另一个正尝试将字符串表示形式从一个时区转换为另一个时区。作为寻求该问题解决方案的人,我可能不会得出结论,后者将提供我正在寻找的答案。
DRH 2012年

5
datetime(date.year,date.month,date.day).timestamp()
朱利安

Answers:


462

如果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)

timestamp1timestamp2如果午夜在本地时区是不一样的时间实例作为午夜UTC可能会有所不同。

mktime()如果d对应于一个不明确的本地时间(例如,在DST过渡期间),或者d是utc偏移可能已经不同并且 C mktime()无法访问给定平台上的tz数据库的过去(未来)日期,则可能返回错误结果。您可以使用pytz模块(例如via tzlocal.get_localzone())来访问所有平台上的tz数据库。此外,如果使用timezone,则utcfromtimestamp()可能会失败并mktime()可能返回非POSIX时间戳"right"


要转换datetime.date不使用UTC表示日期的对象calendar.timegm()

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时间戳(a float)。

Python 3.3以上

datetime.timestamp()

from datetime import timezone

timestamp = dt.replace(tzinfo=timezone.utc).timestamp()

注意:有必要timezone.utc明确地提供其他条件,.timestamp()假设您朴素的datetime对象位于本地时区。

Python 3(<3.3)

从文档中获取datetime.utcfromtimestamp()

没有从日期时间实例获取时间戳的方法,但是可以很容易地如下计算对应于日期时间实例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)

有趣的读物:大纪元时间与一天中的时间之间的时差是几点?多少秒过去了?

另请参见:datetime需要一种“时代”方法

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启用真除法的情况下进行的计算。

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)

当心浮点问题

输出量

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()

2
对于Python 2,为什么不timestamp = (dt - datetime.fromtimestamp(0)).total_seconds()呢?
m01 2012年

7
@ m01:datetime(1970, 1, 1)更明确。fromtimestamp()在此处不正确(使用dtUTC,因此utcfromtimestamp()应改用)。
jfs 2012年

1
@fedorqui看看totimestamp()答案中的函数。
jfs 2015年

14
尽管我喜欢python,但它的日期时间库严重损坏。
Realfun

3
@Realfun:时区,DST转换,tz数据库,leap秒都独立于Python而存在。
jfs

81

适用于Unix系统

>>> import datetime
>>> d = datetime.date(2011,01,01)
>>> d.strftime("%s")  # <-- THIS IS THE CODE YOU WANT
'1293832800'

注1: dizzyf观察到这适用于本地时区。不要在生产中使用。

注意2: JakubNarębski指出,即使对于具有偏移量的日期时间,它也会忽略时区信息(已针对Python 2.7测试)。


4
如果您知道代码将在哪个系统上运行,这是一个很好的答案,但必须注意,并非所有操作系统都存在'%s'格式字符串,因此此代码不可移植。如果要检查是否受支持,可以man strftime在类似Unix的系统上进行检查。
爱丽丝·希顿

5
应该提到的是,这会减少小数秒部分(微秒或其他)。
Alfe

11
警告:这适用于本地时区!对于相同的日期时间对象,您将获得不同的strftime行为,具体取决于机器时间
dizzyf

3
而且,这会忽略时区信息,并假设即使设置了tzinfo的偏移量为datetime,datetime也位于本地时区。好吧,至少在Python 2.7中。
JakubNarębski18年

1
javascript timestamp = python timestamp * 1000
Trinh Hoang Nhu

38
  • 假设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 转换为timestamp),但是仍然…令人赞叹。
塔纳托斯(Thanatos)2012年

9
小心。假设“您希望将日期当作本地系统时区一样对待,这是python中时区所有问题的根源。除非您100%确定将运行脚本的计算机的本地化,尤其是如果服务于可能来自世界各地的客户,则始终假定日期在UTC,并尽早进行转换。相信我,这将使您
Romain G

8

按照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)

3
如果使用UTC,与我的答案有何不同d
jfs

8

我定义了我自己的两个功能

  • utc_time2datetime(utc_time,tz =无)
  • datetime2utc_time(日期时间)

这里:

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

1
我直接浏览了您的示例。.如此简单的事情变得混乱而复杂..根本不是pythonic。
生气

@Mayhem:我整理了一下并添加了评论。如果您有更好的,更通用的解决方案可以将时间转换为日期时间,并且可以设置时区,那么请告知我们。还请让我知道我的代码的更Python化示例应该是什么样子。
agittarius

3

这个问题有点困惑。时间戳不是UTC,而是Unix。日期可能是UTC?假设是这样,并且如果您使用的是Python 3.2+,则简单日期使此操作变得无关紧要:

>>> 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.8pytz==2014.7)。
jfs 2014年

我在上收到错误消息pip install simple-date,看起来只有python3 / pip3。
NoBugs 2016年

3

使用箭头包:

>>> 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已经知道与时区处理相关的错误很多年了 。如果您需要具有非固定UTC偏移量的时区的正确结果,请不要使用它(可以将其用于UTC时区,但stdlib也可以处理UTC情况)。
jfs

@JFSebastian该错误仅过渡期间,模棱两可的时间内发生。
保罗

像臭虫看起来固定在3月28日
马修Longtin

看起来,这是最好的跨Python解决方案。只需使用箭头。谢谢;)
maxkoryukov

@MathieuLongtin dateutil可能还有其他问题
jfs

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

6
这如何回答我的问题?
Andreas Jung

1
@ user908088转换1970-01-01 06:00:00 +05003600为你问。
kev 2012年

1
@ user908088有没有timezonepython2,你可以做计算(06:00:00- +0500= 01:00:00)手动。
2012年

5
为什么在上面这个答案,即使它有-1票,有毛病SO
Umair

1

考虑到您有一个datetime名为的对象d,请使用以下命令获取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")

0

我对深入的讨论印象深刻。

我的2美分:

从datetime导入datetime导入时间

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.