用datetime在python中获取UTC时间戳

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

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

应该导致

  1199145600 

创build一个天真的date时间对象意味着没有时区信息。 如果我查看datetime.utcfromtimestamp的文档,创build一个UTC时间戳意味着省去时区信息。 所以我猜,创build一个天真的date时间对象(就像我做的)会导致一个UTC时间戳。 然而:

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

结果是

 2007-12-31 23:00:00 

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

什么是天真的datetime

默认的datetime对象被认为是“天真的”:它们保留没有时区信息的时间信息。 把天真的datetime想象成一个没有明确起源的相对数字(即: +4 )(实际上你的起源在整个系统边界是相同的)。 将认识的datetime考虑为绝对数字(即: 8 ),对于整个世界来说都是一个共同的起源。

没有时区信息, 你不能把“天真”的date时间转换为任何非天真的时间表示(如果我们不知道从哪里开始,那么+4目标是在哪里)。 这就是为什么你不能有一个datetime.datetime.toutctimestamp()方法。 (参见: 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 

我有天真的date时间,我能做什么?

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

  • 如果你使用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不是天真的,通过给他们返回他们预期的时区。

    您将需要时区的名称有关生成目标naïvedatetime时DST是否有效的信息(有关DST的最后一个信息是angular点所必需的):

     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

    如果目标date时间是在is_dst DST放置时产生的(例如,通过移除一个小时来改变DST时间), is_dst使用is_dst会生成不正确的时间(和UTC时间戳)。

    提供不正确的is_dst当然会产生不正确的时间(和UTC时间戳)只有在DST重叠或漏洞。 而且,当提供不正确的时间时,出现在“漏洞”(由于向前移动DST而从来不存在的时间), is_dst将给出如何考虑这个假时间的解释,并且这是唯一的情况.normalize(..)实际上会在这里做一些事情,因为它会把它翻译成实际的有效时间(如果需要,改变date时间和DST对象)。 请注意,。在最后使用UTC时间戳不需要.normalize() ,但如果您不喜欢在variables中使用伪造时间的想法,那么可能会推荐使用.normalize() ,尤其是在其他地方重新使用此variables时。

    避免使用以下内容 🙁 cf: 使用pytz进行Datetime时区转换 )

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

    为什么? 因为.replace()在不考虑目标时间的情况下盲目replacetzinfo ,并select一个不好的DST对象。 而.localize()使用目标时间和您的is_dst提示来select正确的DST对象。

旧的不正确的答案 (感谢@ JFSebastien为此提出):

希望当你创build你自己的datetime对象时,很容易猜出时区(你的本地来源),因为它与系统configuration有关,你希望不会在无用的date时间对象创build和你想获得的时刻之间改变UTC时间戳。 这个技巧可以用来给出一个不完美的问题。

通过使用time.mktime我们可以创build一个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对象创build在与创builddatetime时间相同的时区。

最后一个解决scheme是不正确的,因为它假设现在的UTC偏移量与EPOCH的UTC偏移量相同。 夏时制(DST)偏移在一年中的特定时刻,情况并非如此。

还要注意这个博客条目所描述的calendar.timegm()函数:

 import calendar calendar.timegm(utc_timetuple) 

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

如果inputdate时间对象在UTC:

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

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

如果inputdate对象是UTC:

 >>> 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时间戳 。

另一种可能性是:

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

这是因为“d”和“epoch”都是天真的date时间,使得“ – ”运算符有效,并返回间隔。 total_seconds()将间隔转换为秒。 请注意, total_seconds()返回一个浮点数,甚至d.microsecond == 0

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

转换为Unix时如何指定时区(UTC)? (python)

我觉得主要的答案还不是很清楚,值得花时间去了解时间时区

处理时间最重要的事情是时间是相对的

  • 2017-08-30 13:23:00 :(天真的date时间),代表当地时间在世界某个地方,但是请注意2017-08-30 13:23:00在伦敦和2017-08-30 13:23:00 不是同一时间 2017-08-30 13:23:00在旧金山。

因为同一时间string可以被解释为不同的时间点,这取决于你在世界上的哪个地方,所以需要绝对的时间概念。

UTC时间戳 Epoch(定义为1 January 1970 00:00:00 GMT时区+00:00偏移量)以秒(或毫秒)表示的数字。

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

这使得有可能按时排列事件。

没有时区信息,时间是相对的,不能转化为绝对的时间概念,而没有提供一些指示天真date时间应该锚定到什么时区。

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

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

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

  • ISO-8601date时间string :ISO-8601是一种标准格式,用于loggingdate时间和时区。 (实际上有几种格式,请阅读: https : //en.wikipedia.org/wiki/ISO_8601 )它用于在系统之间以可序列化的方式传递时区感知的date时间信息。

什么时候用哪个? 或者说,你什么时候需要关心时区?

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

  • 要计算来自世界各地的事件之间的时间差异,UTC时间戳就足够了,但是您无法分析事件发生的时间(例如,对于网站分析,您可能想知道用户何时来到您的网站在当地时间 :你有没有在早上或晚上看到更多的用户?没有时间信息,你无法弄清楚。

datestring中的时区偏移量

还有一点很重要,就是datestring中的时区偏移量是不固定的 。 这意味着,因为2017-08-30T10:55:24-0800说的抵消-0800或8小时后,并不意味着它将永远是!

在夏季,夏季时间可能会是-0700

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

America/Los_Angeles时区是世界上的一个地方 ,但在冬季变成PST (太平洋标准时间)时区偏移符号,在夏季变成PDT (太平洋夏令时)。

因此,除了从datestring中获取时区偏移之外,还应该使时区名称准确无误。

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

所以,总之,这很复杂。 非常复杂,这就是为什么你不应该自己做这件事,而是要相信一个能为你做的包,并保持它的date!

接受的答案似乎不适合我。 我的解决scheme

 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