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

Posted

技术标签:

【中文标题】将 datetime 转换为 Unix 时间戳并将其转换回 python【英文标题】:Convert datetime to Unix timestamp and convert it back in python 【发布时间】:2013-11-17 01:53:36 【问题描述】:

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

当我执行(dt - datetime(1970,1,1)).total_seconds() 时,我得到了时间戳1378033200

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

时间不匹配。我在这里错过了什么?

【问题讨论】:

相关:Converting datetime.date to UTC timestamp in Python 附带说明,如果您使用的是 Python 3.3+,那么您真的非常想使用 timestamp 方法,而不是自己尝试。一方面,这完全避免了从不同时区减去幼稚时间的可能性。 dt 来自哪里?是当地时间还是 UTC 时间? @abarnert 我还想提交清除所有代码页和 unicode 符号的请求,也就是说,禁止所有非 ascii 和非默认代码页语言。仍然允许绘制符号。 @DanielF:请求被拒绝。我对在这里创造一种单一世界的语言不感兴趣,即使我们这样做了,我也不想让历史语言学家和托尔金学者的生活变得不可能。 Unicode 已经解决了这个问题,除了某些组织和产品(TRON 联盟、在 UTF-8 上使用 Shift-JIS 的日本软件、Microsoft 仍在为用户文本文件提供默认为 cp1252 的操作系统以及各种假装 UTF -16 是一个固定宽度的字符集和/或与 Unicode 相同的字符集)需要受到惩罚才能使它们对齐。 【参考方案1】:

您在这里错过的是时区。

假设您已经离开 UTC 五个小时,所以 2013-09-01T11:00:00 local 和 2013-09-01T06:00:00Z 是同一时间。

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

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

另一方面,如果您最初的原始日期时间是本地的,那么您一开始就不应该从中减去 UTC 时间戳;请改用datetime.fromtimestamp(0)

或者,如果您有一个感知日期时间对象,您需要在双方都使用本地(感知)纪元,或者显式转换为 UTC。

如果您拥有或可以升级到 Python 3.3 或更高版本,则只需使用 timestamp 方法即可避免所有这些问题,而不是自己尝试弄清楚如何去做。即使你不这样做,你也可以考虑borrowing its source code。

(如果您可以等待 Python 3.4,看起来PEP 341 可能会进入最终版本,这意味着 JF Sebastian 和我在 cmets 中谈论的所有内容都应该只需要标准库,并且在 Unix 和 Windows 上以相同的方式工作。)

【讨论】:

如果dt 在本地时区,那么问题中的公式不正确datetime.fromtimestamp(0)(当前时区中的纪元)应该使用而不是datetime(1970, 1,1)(UTC 中的unix 纪元)。 @J.F.Sebastian:我不想详细介绍所有三种可能性,但我想你是对的,我应该。 btw, fromtimestamp(0) 可能会失败,如果系统不存储历史时区信息,例如,在 Windows 上。在这种情况下可以使用pytz @J.F.Sebastian:但是pytz 没有帮助,除非你已经知道你所在的时区;要以编程方式执行此操作,您需要一个不同的库来获取当前 Windows 时区并将其转换为 pytz 时区和/或按名称查找。 tzlocal 模块也可以在 Windows 上运行。这是您可以convert utc time to local time 的方法。【参考方案2】:

而不是这个表达式从dt创建一个POSIX时间戳,

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

使用这个:

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

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

编辑:一些后续行动......在一些 cmets 之后(见下文),我很好奇 strftime 中缺乏对 %s 的支持或文档。这是我发现的:

datetimetime 的Python source 中,字符串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 接受的答案。

【讨论】:

这是无证行为(我相信)。例如在 Windows 上,它会导致“无效的格式字符串”。 @CrescentFresh,很有趣。也许你是对的。虽然我在文档中没有看到strftime("%s"),但我只是确认它可以在 Mac 和 Linux 上运行。谢谢。 显然它忽略了 tzinfo 字段。 @DarrenStone:你不需要阅读源代码。 time.strftime()datetime.strftime 文档都委托给平台 strftime(3) 函数以获取不受支持的指令。 %s 即使在 Mac OS X 上也可能会失败,例如 datetime.strftime('%s') should respect tzinfo。 您永远不应该使用%s,因为您只会使用您所在系统的本地化系统时间。如果你想获取真正的 UNIX 时间戳,你想使用.timestamp()【参考方案3】:

好吧,当转换为 unix 时间戳时,python 基本上假设为 UTC,但在转换回来时,它会给你一个转换为本地时区的日期。

查看此问题/答案; Get timezone used by datetime.datetime.fromtimestamp()

【讨论】:

【参考方案4】:

解决方案是

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

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

【讨论】:

它假定 d 是一个表示本地时间的天真日期/日期时间对象(如果操作系统不提供历史 tz db (UTC过去本地时区的偏移量可能有所不同))。 More options. 看起来没人介意浮点解决方案。对每个人来说都那么明显吗? 这会减少微秒。可能很有趣。 唯一的问题是您没有考虑时区。 不应该。如果需要调整 TZ,则需要先进行调整。【参考方案5】:

如果你想将 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

【讨论】:

不考虑时区。 您不想使用%s,因为它将被本地化为您当前所在系统的时钟。您应该只使用 .timestamp() 来获得正确的 Epoch/UNIX 时间。 %s 不适用于 Windows 系统 (ValueError: Invalid format string) timestamp() 是浮点数的结果有什么特别的原因吗?将其变成int 是否安全? IE 的返回值timestamp() 是否会返回一些我应该考虑的小数?【参考方案6】:

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

arrow package 可以避免这种日期时间的折磨;它已经编写、测试、pypi-published、cross-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'

【讨论】:

【参考方案7】:

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

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

【讨论】:

最佳答案,在使用 UTC 时间时完美运行。非常感谢!【参考方案8】:
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 仅用于 local dt 。使用 calendar.timegm 是安全的,但 dt 必须是 utc 区域,因此将区域更改为 utc。如果 UTC 中的 dt 只需使用 calendar.timegm

【讨论】:

【参考方案9】:

使用 UTC 时区:

time_stamp = calendar.timegm(dt.timetuple())

datetime.utcfromtimestamp(time_stamp)

【讨论】:

经过一个小时的搜索,这是唯一有效的答案:')【参考方案10】:
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

【讨论】:

【参考方案11】:

这个类将满足您的需求,您可以将变量传递给 ConvertUnixToDatetime 并根据您希望它操作的函数调用它。

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

【讨论】:

【参考方案12】:
import time
from datetime import datetime
time.mktime(datetime.now().timetuple())

【讨论】:

以上是关于将 datetime 转换为 Unix 时间戳并将其转换回 python的主要内容,如果未能解决你的问题,请参考以下文章

将 DateTime 转换为 Unix 时间戳格式

如何将 Unix 时间戳转换为 DateTime,反之亦然?

如何将 Unix 时间戳转换为 DateTime,反之亦然?

PHP-MYSQL:将 Unix 时间戳转换为 DateTime,反之亦然

在 Select 语句中将 DateTime 转换为 Unix 时间戳?

将 Unix 时间戳转换为 AOE