将datetime转换为Unix时间戳并将其转换回python


184

我有dt = datetime(2013,9,1,11),并且我想获取此datetime对象的Unix时间戳。

当我这样做的时候,(dt - datetime(1970,1,1)).total_seconds()我得到了时间戳1378033200

当使用datetime.fromtimestamp我将其转换回时datetime.datetime(2013, 9, 1, 6, 0)

时间不匹配。我在这里想念什么?



附带说明一下,如果您使用的是Python 3.3+,那么您确实非常想使用该timestamp方法,而不是自己尝试做。一方面,这完全避免了从不同时区减去原始时间的可能性。
abarnert

1
哪里dt来的?是当地时间还是UTC时间?
jfs

2
@abarnert我还想提交一个清除所有代码页和unicode符号的请求,也就是说,禁止所有非ascii和非默认代码页语言。仍然允许使用符号绘画。
Daniel F

6
@DanielF:请求被拒绝。我对在这里创建一种世界语言不感兴趣,即使我们这样做,我也不想让历史语言学家和托尔金学者无法生活。Unicode已经解决了这个问题,除了某些组织和产品(TRON联盟,在UTF-8上使用Shift-JIS的日文软件,Microsoft仍提供默认用于用户文本文件的cp1252操作系统以及各种伪装为UTF的SDK之外) -16是固定宽度的字符集和/或与Unicode相同的字符)需要进行惩罚才能使其一致。
abarnert 2014年

Answers:


104

您在这里错过的是时区。

大概您要在UTC下班5个小时,因此2013-09-01T11:00:00本地和2013-09-01T06:00:00Z是同一时间。

您需要阅读datetime文档的顶部,其中解释了时区以及“天真”和“感知”对象。

如果您原始的原始日期时间是UTC,则恢复它的方法是使用utcfromtimestamp而不是fromtimestamp

另一方面,如果原始的原始日期时间是本地的,那么您不应该首先从中减去UTC时间戳;使用datetime.fromtimestamp(0)代替。

或者,如果您有一个已知的日期时间对象,则需要在两侧都使用一个本地(感知)纪元,或者显式地与UTC进行转换。

如果您拥有或可以升级到Python 3.3或更高版本,则可以通过仅使用timestamp方法来避免所有这些问题,而不必尝试自己弄清楚该如何做。即使您不这样做,也可能要考虑借鉴其源代码

(而且,如果您可以等待Python 3.4,则似乎PEP 341可能会进入最终发行版,这意味着JF Sebastian和我在评论中谈论的所有内容都只能使用stdlib来完成,并且在Unix和Windows上均以相同的方式工作。)


1
如果dt在当地时区,则问题中的公式不正确datetime.fromtimestamp(0)(应使用当前时区中的纪元),而不是datetime(1970, 1,1)(UTC中的unix纪元)。
jfs

@JFSebastian:我不想详细介绍这三种可能性,但是我想你是对的,我应该。
abarnert

顺便说一句,fromtimestamp(0)如果系统未存储历史时区信息(例如在Windows上),则可能会失败。pytz在这种情况下可以使用。
jfs

@JFSebastian:但是pytz除非您已经知道您所在的时区,否则它无济于事。要以编程方式执行此操作,您需要一个不同的库来获取当前Windows时区并将其转换pytz为时区和/或按名称查找。
2013年

tzlocal在Windows上也可以使用的模块。这是将utc时间转换为本地时间的方法
jfs

141

解决方案是

import time
import datetime
d = datetime.date(2015,1,5)

unixtime = time.mktime(d.timetuple())

12
它假定d是一个表示本地时间的天真日期/日期时间对象(如果操作系统不提供历史tz db,则可能会因时间不明确或过去/将来的日期而失败(UTC偏移量过去在本地可能会有所不同)时区))。更多选择
jfs

6
似乎没有人介意浮点解决方案。对每个人都明显吗?
伊万·巴拉索夫

4
这降低了微秒。可能会很有趣。
Alfe

唯一的问题是您没有考虑时区。
布莱尔23年

不应该。如果需要调整TZ,则需要先进行调整。
Marcin Orlowski

69

如果要将python日期时间转换为自纪元以来的秒数,则应明确地执行以下操作:

>>> import datetime
>>> datetime.datetime(2012,04,01,0,0).strftime('%s')
'1333234800'
>>> (datetime.datetime(2012,04,01,0,0) - datetime.datetime(1970,1,1)).total_seconds()
1333238400.0

在Python 3.3+中,您可以timestamp()改用:

>>> import datetime
>>> datetime.datetime(2012,4,1,0,0).timestamp()
1333234800.0

5
不考虑时区。
布莱尔23年

3
您不想使用%s,因为它将被本地化为当前使用的系统的时钟。您应该只使用.timestamp()以获得正确的Epoch / UNIX时间。
Blairg23年

3
%s在Windows系统上不起作用(ValueError: Invalid format string
chrki'5

1
@ amitnair92刚放进89
Francisco Costa

54

而不是使用此表达式从创建一个POSIX时间戳dt

(dt - datetime(1970,1,1)).total_seconds()

用这个:

int(dt.strftime("%s"))

在使用第二种方法的示例中,我得到了正确的答案。

编辑:一些跟进...经过一些评论(请参阅下文),我很好奇缺少%sin 的支持或文档strftime。这是我发现的:

Python源datetimetime,串STRFTIME_FORMAT_CODES告诉我们:

"Other codes may be available on your platform.
 See documentation for the C library strftime function."

所以现在,如果我们man strftime(在Mac OS X等BSD系统上)可以找到对以下内容的支持%s

"%s is replaced by the number of seconds since the Epoch, UTC (see mktime(3))."

无论如何,这就是为什么%s可以在它可以运行的系统上工作。但是有更好的解决OP问题的方法(考虑了时区)。请参阅此处的@abarnert可接受的答案。


4
这是未记录的行为(我相信)。例如,在Windows上,它会导致“无效格式字符串”。

@CrescentFresh,有趣。你可能是对的。虽然我没有strftime("%s")在文档中看到,但我只是确认了它可以在Mac和Linux上使用。谢谢。
达伦·斯通

1
显然,它忽略了tzinfo字段。
Daniel F

1
@DarrenStone:您不需要阅读源代码。无论time.strftime()datetime.strftime文档代表对平台strftime(3)功能不支持的指令。%s即使在Mac OS X上也可能失败,例如datetime.strftime('%s')应该尊重tzinfo
jfs 2015年

1
绝对不要使用,%s因为您将只使用所用系统的本地化系统时间。如果要.timestamp()获取真实的UNIX时间戳,则要使用。
布莱尔23年


4

您错过了时区信息(已回答,已同意)

arrow包装允许避免约会时间的折磨;它已经被编写,测试,pypi发布,交叉python(2.6 — 3.xx)。

您需要的全部:(pip install arrow或添加到依赖项)

您的情况的解决方案

dt = datetime(2013,9,1,11)
arrow.get(dt).timestamp
# >>> 1378033200

bc = arrow.get(1378033200).datetime
print(bc)
# >>> datetime.datetime(2013, 9, 1, 11, 0, tzinfo=tzutc())
print(bc.isoformat())
# >>> '2013-09-01T11:00:00+00:00'

3

如果您的datetime对象表示UTC时间,请不要使用time.mktime,因为它假定元组位于您的本地时区中。而是使用calendar.timegm:

>>> import datetime, calendar
>>> d = datetime.datetime(1970, 1, 1, 0, 1, 0)
>>> calendar.timegm(d.timetuple())
60


1
def dt2ts(dt, utc=False):
    if utc:
        return calendar.timegm(dt.timetuple())
    if dt.tzinfo is None:
        return int(time.mktime(dt.timetuple()))
    utc_dt = dt.astimezone(tz.tzutc()).timetuple()
    return calendar.timegm(utc_dt)

如果您想使用UTC时间戳:time.mktime仅用于本地 dt,使用calendar.timegm是安全的,但dt必须是utc区域,因此请将区域更改为utc。如果在UTC中使用dt,请使用calendar.timegm


1
def datetime_to_epoch(d1):

    # create 1,1,1970 in same timezone as d1
    d2 = datetime(1970, 1, 1, tzinfo=d1.tzinfo)
    time_delta = d1 - d2
    ts = int(time_delta.total_seconds())
    return ts


def epoch_to_datetime_string(ts, tz_name="UTC"):
    x_timezone = timezone(tz_name)
    d1 = datetime.fromtimestamp(ts, x_timezone)
    x = d1.strftime("%d %B %Y %H:%M:%S")
    return x

0

该类将满足您的需求,您可以将变量传递给ConvertUnixToDatetime&call,然后基于该变量来运行该函数。

from datetime import datetime
import time

class ConvertUnixToDatetime:
    def __init__(self, date):
        self.date = date

    # Convert unix to date object
    def convert_unix(self):
        unix = self.date

        # Check if unix is a string or int & proceeds with correct conversion
        if type(unix).__name__ == 'str':
            unix = int(unix[0:10])
        else:
            unix = int(str(unix)[0:10])

        date = datetime.utcfromtimestamp(unix).strftime('%Y-%m-%d %H:%M:%S')

        return date

    # Convert date to unix object
    def convert_date(self):
        date = self.date

        # Check if datetime object or raise ValueError
        if type(date).__name__ == 'datetime':
            unixtime = int(time.mktime(date.timetuple()))
        else:
            raise ValueError('You are trying to pass a None Datetime object')
        return type(unixtime).__name__, unixtime


if __name__ == '__main__':

    # Test Date
    date_test = ConvertUnixToDatetime(datetime.today())
    date_test = date_test.convert_date()
    print(date_test)

    # Test Unix
    unix_test = ConvertUnixToDatetime(date_test[1])
    print(unix_test.convert_unix())
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.