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

pat*_*pat 73 python datetime timestamp utc

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

datetime(2008, 1, 1, 0, 0, 0, 0)
Run Code Online (Sandbox Code Playgroud)

应该导致

 1199145600
Run Code Online (Sandbox Code Playgroud)

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

then = datetime(2008, 1, 1, 0, 0, 0, 0)
datetime.utcfromtimestamp(float(then.strftime('%s')))
Run Code Online (Sandbox Code Playgroud)

结果是

2007-12-31 23:00:00
Run Code Online (Sandbox Code Playgroud)

datetime对象中是否还有隐藏的时区信息?我究竟做错了什么?

vaa*_*aab 80

什么是天真的datetime

默认datetime对象被称为"天真":它们保留时间信息而没有时区信息.把天真想象datetime成一个相对数字(即:) ,datetime没有明确的起源(实际上你的起源在整个系统边界都是常见的).考虑一下整个世界的共同起源的+4绝对数字(即datetime:).

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

要检查你datetime.datetime.toutctimestamp() datetime是否天真,检查dt,如果dt.tzinfo,那么天真:

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

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

您必须根据您的具体情况做出假设:您必须问自己的问题是:您None的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())
    
    Run Code Online (Sandbox Code Playgroud)
  • 如果你不使用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
    
    Run Code Online (Sandbox Code Playgroud)

    不提供的后果datetime:

    is_dst如果在向后DST到位时生成目标日期时间(例如,通过删除一小时来更改DST时间),则不使用将生成不正确的时间(和UTC时间戳).

    is_dst当然,提供不正确的意愿只会在DST重叠或空洞上产生不正确的时间(和UTC时间戳).并且,当提供不正确的时间时,在"漏洞"(由于DST向前移动而从未存在的时间)中发生,is_dst将给出如何考虑这个虚假时间的解释,这是唯一 is_dst一个在这里实际做某事的情况,因为它会将其翻译为实际有效时间(如果需要,可以更改日期时间和DST对象).请注意,.normalize(..)在最后使用正确的UTC时间戳不是必需的,但如果您不喜欢在变量中出现虚假时间的想法,可能会建议您使用,尤其是在其他地方重新使用此变量时.

    使用以下内容避免:(cf:使用pytz进行日期时区转换)

    dt = dt.replace(tzinfo=timezone('Europe/Amsterdam'))  ## BAD !!
    
    Run Code Online (Sandbox Code Playgroud)

    为什么?因为.normalize().replace()不考虑目标时间的情况下盲目地替换,并将选择一个糟糕的DST对象.而tzinfo使用目标时间和.localize()提示来选择正确的DST对象.

旧的错误答案(感谢@JFSebastien提出这个问题):

希望在您创建天真is_dst对象时很容易猜测时区(您的本地原点),因为它与系统配置相关,您希望在天真的日期时间对象创建和您希望获得UTC时间戳.这个技巧可以用来提出一个不完美的问题.

通过使用datetime我们可以创建一个time.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()))
Run Code Online (Sandbox Code Playgroud)

您必须确保utc_mktime在与创建对象相同的时区创建对象datetime.

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

  • 天真的日期时间对象应始终以UTC表示时间.其他时区应仅用于I/O(显示).Python 3.3中有`datetime.timestamp()`方法. (4认同)
  • -1.您的代码假定utc_offset(now)和utc_offset(epoch)在本地时区中是相同的.在116个时区(来自430个常见时区)并非如此. (4认同)
  • `time.mktime()`应该只用于当地时间.`calendar.timegm()`可用于将utc时间元组转换为posix时间戳.或者更好的是仅使用datetime方法.见[我的回答](http://stackoverflow.com/a/13423091/4279) (2认同)

Chr*_*don 24

另一种可能性是:

d = datetime.datetime.utcnow()
epoch = datetime.datetime(1970,1,1)
t = (d - epoch).total_seconds()
Run Code Online (Sandbox Code Playgroud)

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

  • 嗯,不是真的,这个想法是一样的,但这个更容易理解:) (12认同)
  • 您可能会认为时间库中只有一个方法或其他... (2认同)

Mr.*_*Mr. 19

另请注意博客条目所描述的calendar.timegm()函数:

import calendar
calendar.timegm(utc_timetuple)
Run Code Online (Sandbox Code Playgroud)

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


jfs*_*jfs 12

如果输入datetime对象是UTC:

>>> dt = datetime(2008, 1, 1, 0, 0, 0, 0)
>>> timestamp = (dt - datetime(1970, 1, 1)).total_seconds()
1199145600.0
Run Code Online (Sandbox Code Playgroud)

注意:它返回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
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅在Python中将datetime.date转换为UTC时间戳.


MrE*_*MrE 8

我觉得主要答案仍然不是那么清楚,值得花时间去理解时间时区.

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

  • 2017-08-30 13:23:00:(一个天真的约会时间),代表世界某个地方的当地时间,但请注意,2017-08-30 13:23:00在伦敦并不2017-08-30 13:23:00旧金山那样.

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

UTC时间戳是在秒(或毫秒)的数历元(定义为1 January 1970 00:00:00GMT时区00:00偏移).

Epoch锚定在GMT时区,因此是一个绝对的时间点.因此,UTC时间戳是与绝对时间的偏移,因此定义了绝对时间点.

这使得可以及时订购事件.

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

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

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

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

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

什么时候用哪个?或者更确切地说,何时需要关心时区?

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

  • 要计算来自世界不同地方的事件之间的时差,UTC时间戳就足够了,但是你无法分析在什么时间发生的事件(例如,对于网络分析,你可能想知道用户什么时候来到你的当地时间的网站:你在早上或晚上看到更多用户吗?没有时间信息,你无法弄明白.

日期字符串中的时区偏移量:

另一点很重要,即日期字符串中的时区偏移量不固定.这意味着,因为2017-08-30T10:55:24-0800说偏移-0800或8小时后,并不意味着它将永远!

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

这意味着时区偏移量(+0100)时区名称(欧洲/法国)时区名称(CET)不同

America/Los_Angeles时区是世界上的一个地方,但它PST在冬季变为(太平洋标准时间)时区偏移表示法,而夏季则变为PDT(太平洋夏令时).

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

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

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


Mik*_*kin 7

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

from datetime import datetime, timezone

dt = datetime(2008, 1, 1, 0, 0, 0, 0)
int(dt.replace(tzinfo=timezone.utc).timestamp())
Run Code Online (Sandbox Code Playgroud)