使用datetime获取python中的UTC时间戳

时间:2011-02-21 14:36:30

标签: python datetime timestamp utc

有没有办法通过指定日期来获取UTC时间戳?我期待的是什么:

datetime(2008, 1, 1, 0, 0, 0, 0)

应该导致

 1199145600

创建天真的日期时间对象意味着没有时区信息。如果我查看datetime.utcfromtimestamp的文档,则创建UTC时间戳意味着省略时区信息。所以我猜,创建一个天真的日期时间对象(就像我做的那样)会产生一个UTC时间戳。但是:

then = datetime(2008, 1, 1, 0, 0, 0, 0)
datetime.utcfromtimestamp(float(then.strftime('%s')))

结果

2007-12-31 23:00:00

日期时间对象中是否还有隐藏的时区信息?我做错了什么?

10 个答案:

答案 0 :(得分:72)

什么是天真的datetime

默认datetime个对象被称为“天真”:它们保留时间信息而没有时区信息。将天真datetime视为相对数字(即:+4)而没有明确的起源(实际上,您的起源在整个系统边界内都是通用的)。考虑将datetime视为绝对数字(即:8),并为整个世界提供共同的起源。

没有时区信息你不能将“天真”的日期时间转换为任何非天真的时间表示(如果我们不知道从哪里开始,+4目标在哪里?)。这就是为什么你不能使用datetime.datetime.toutctimestamp()方法。 (cf:http://bugs.python.org/issue1457227

要检查datetime dt是否天真,请检查dt.tzinfo,如果None,那么它是天真的:

datetime.now()        ## DANGER: returns naïve datetime pointing on local time
datetime(1970, 1, 1)  ## returns naïve datetime pointing on user given time

我有天真的约会时间,我该怎么办?

您必须根据您的具体情况做出假设: 您必须问自己的问题是:您的datetime是否为UTC?还是当地时间?

  • 如果你使用UTC (你没有遇到麻烦):

    import 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的最后信息:

    import 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:Datetime Timezone conversion using pytz

    dt = dt.replace(tzinfo=timezone('Europe/Amsterdam'))  ## BAD !!
    

    为什么呢?因为.replace()盲目地取代tzinfo而没有 考虑到目标时间,将选择一个糟糕的DST对象。 而.localize()使用目标时间和is_dst提示 选择正确的DST对象。

OLD错误回答(感谢@ J.F.Sebastien提出这个问题):

希望您在创建天真datetime对象时很容易猜到时区(您的本地原点),因为它与系统配置相关,您希望在天真的日期时间对象创建和您想要获取UTC时间戳的那一刻。此技巧可用于提供不完美问题。

使用time.mktime我们可以创建utc_mktime

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

您必须确保datetime对象的创建时间与创建datetime的时区相同。

这最后一个解决方案是错误的,因为它假设从现在起的UTC偏移量与EPOCH的UTC偏移量相同。对于很多时区而言并非如此(在特定时刻)夏令时(DST)偏移的年份。

答案 1 :(得分:20)

另一种可能性是:

d = datetime.datetime.utcnow()
epoch = datetime.datetime(1970,1,1)
t = (d - epoch).total_seconds()

这适用于“d”和“epoch”都是天真的日期时间,使“ - ”运算符有效,并返回一个间隔。 total_seconds()将间隔变为秒。请注意,total_seconds()会返回一个浮点数,甚至是d.microsecond == 0

答案 2 :(得分:19)

另请注意calendar.timegm()博客条目

所述的this功能
import calendar
calendar.timegm(utc_timetuple)

输出应该与vaab的解决方案一致。

答案 3 :(得分:12)

如果输入日期时间对象是UTC:

>>> dt = datetime(2008, 1, 1, 0, 0, 0, 0)
>>> timestamp = (dt - datetime(1970, 1, 1)).total_seconds()
1199145600.0

注意:它返回float,即微秒表示为秒的分数。

如果输入日期对象是UTC:

>>> from datetime import date
>>> utc_date = date(2008, 1, 1)
>>> timestamp = (utc_date.toordinal() - date(1970, 1, 1).toordinal()) * 24*60*60
1199145600

点击Converting datetime.date to UTC timestamp in Python了解详情。

答案 4 :(得分:5)

我觉得主要答案仍然不太明确,值得花时间去理解 时间 时区

在处理时间时最重要的是时间是 相对

  • 2017-08-30 13:23:00 :(一个天真的日期时间)代表世界某处的 本地 时间,但请注意伦敦的2017-08-30 13:23:00是<在旧金山以2017-08-30 13:23:00为强>不同时

因为同一时间字符串可以被解释为不同的时间点,具体取决于您在世界中的位置,因此需要绝对时间概念。

UTC时间戳是一个以秒为单位(或毫秒)来自 Epoch的数字(在1 January 1970 00:00:00时区定义为GMT +00:00偏移)。

Epoch锚定在GMT时区,因此是绝对时间点。 UTC时间戳是绝对时间的偏移量因此定义绝对时间点

这样就可以及时订购活动。

没有时区信息,时间是相对的,并且不能转换为绝对时间概念,而不提供天真日期时间应锚定到的时区的一些指示。

计算机系统中使用的时间类型是什么?

  • 天真的日期时间:通常用于显示,在本地时间(即在浏览器中),操作系统可以向程序提供时区信息。

  • UTC时间戳:如上所述,UTC时间戳是一个绝对时间点,但它锚定在给定的时区中,因此UTC时间戳可以转换为日期时间任何时区,但它不包含时区信息。那是什么意思?这意味着1504119325对应2017-08-30T18:55:24Z2017-08-30T17:55:24-01002017-08-30T10:55:24-0800。它没有告诉您哪里记录的日期时间来自。它通常用于服务器端以记录事件(日志等)或用于将 时区感知日期时间 转换为 绝对点及时 并计算时差

  • ISO-8601 datetime 字符串:ISO-8601是一种标准格式,用于记录带时区的日期时间。 (实际上是几种格式,请在此处阅读:https://en.wikipedia.org/wiki/ISO_8601)它用于在系统之间以可序列化的方式传达时区感知日期时间信息。

何时使用哪个?或者更确切地说,何时需要关注时区?

  • 如果您需要以任何方式关心时间,您需要时区信息。日历或闹钟需要时间来为世界上任何用户在当天的正确时间设置会议。如果此数据保存在服务器上,则服务器需要知道日期时间对应的时区。

  • 要计算来自世界不同地方的事件之间的时差,UTC时间戳就足够了,但您无法分析一天中发生的事件(例如,对于网络分析,您可能希望知道用户何时以当地时间访问您的网站:您是否在早上或晚上看到更多用户?如果没有时间信息,您就无法理解这一点。

日期字符串中的时区偏移

另一点很重要,即日期字符串中的时区偏移不固定。这意味着,因为2017-08-30T10:55:24-0800表示偏移-0800或8小时后,并不意味着它总是会!

在夏天,它可能会在夏令时,而-0700

这意味着时区偏移(+0100)时区名称(欧洲/法国)或甚至时区指定(CET)不同

America/Los_Angeles时区是世界 的地方 ,但在冬季会变成PST(太平洋标准时间)时区偏移表示法和夏天的PDT(太平洋夏令时)。

因此,除了从日期字符串获取时区偏移之外,还应该让时区名称准确。

大多数软件包都能够将数字偏移从夏令时转换为标准时间,但这并不一定只有偏移量。例如,西非的WAT时区指定是UTC + 0100,就像法国的CET时区一样,但是法国观察夏令时,而西非没有(因为它们接近赤道)

因此,简而言之,它很复杂。非常复杂,这就是为什么你不应该自己做,但要相信一个为你做的包,并保持最新状态!

答案 5 :(得分:1)

使用utcfromtimestamp和指定时区确实存在问题。以下问题提供了一个很好的示例/解释:

How to specify time zone (UTC) when converting to Unix time? (Python)

答案 6 :(得分:1)

我认为表达您的问题的正确方法是 springBootVersion = "2.2.5.RELEASE" set('springCloudVersion', "Hoxton.SR3") implementation group:"org.springframework.cloud", name: "spring-cloud-stream" implementation group: "org.springframework.cloud", name: "spring-cloud-stream-binder-kafka-streams" implementation group: "org.springframework.cloud", name: "spring-cloud-starter-stream-kafka" ,因为时间戳只是一个绝对值,而不是相对值。相对(或时区知道)的部分是日期。

我发现熊猫非常适合时间戳,所以:

Is there a way to get the timestamp by specifying the date in UTC?

答案 7 :(得分:0)

接受的答案对我来说似乎不起作用。我的解决方案:

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

答案 8 :(得分:0)

不使用外部模块的简单解决方案:

from datetime import datetime, timezone

dt = datetime(2008, 1, 1, 0, 0, 0, 0)
int(dt.replace(tzinfo=timezone.utc).timestamp())

答案 9 :(得分:-1)

最简单的方法: <击>

<击>
>>> from datetime import datetime
>>> dt = datetime(2008, 1, 1, 0, 0, 0, 0)
>>> dt.strftime("%s")
'1199163600'

<击>

编辑:@Daniel是正确的,这会将其转换为机器的时区。以下是修改后的答案:

>>> 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'

事实上,甚至没有必要指定timezone.utc,因为只要两个datetime具有相同的时区(或没有时区),时差就相同。

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