将 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
的支持或文档。这是我发现的:
在datetime
和time
的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的主要内容,如果未能解决你的问题,请参考以下文章
如何将 Unix 时间戳转换为 DateTime,反之亦然?
如何将 Unix 时间戳转换为 DateTime,反之亦然?
PHP-MYSQL:将 Unix 时间戳转换为 DateTime,反之亦然