简体   繁体   English

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

[英]Convert datetime to Unix timestamp and convert it back in python

I have dt = datetime(2013,9,1,11) , and I would like to get a Unix timestamp of this datetime object.我有dt = datetime(2013,9,1,11) ,我想获得这个 datetime 对象的 Unix 时间戳。

When I do (dt - datetime(1970,1,1)).total_seconds() I got the timestamp 1378033200 .当我这样做时(dt - datetime(1970,1,1)).total_seconds()我得到了时间戳1378033200

When converting it back using datetime.fromtimestamp I got datetime.datetime(2013, 9, 1, 6, 0) .使用datetime.fromtimestamp将其转换回来时,我得到了datetime.datetime(2013, 9, 1, 6, 0)

The hour doesn't match.小时不匹配。 What did I miss here?我在这里错过了什么?

solution is解决方案是

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

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

If you want to convert a python datetime to seconds since epoch you should do it explicitly:如果要将 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

In Python 3.3+ you can use timestamp() instead:在 Python 3.3+ 中,您可以使用timestamp()代替:

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

What you missed here is timezones.您在这里错过的是时区。

Presumably you've five hours off UTC, so 2013-09-01T11:00:00 local and 2013-09-01T06:00:00Z are the same time.大概你有五个小时的 UTC,所以 2013-09-01T11:00:00 local 和 2013-09-01T06:00:00Z 是同一时间。

You need to read the top of the datetime docs, which explain about timezones and "naive" and "aware" objects.您需要阅读datetime文档的顶部,其中解释了时区以及“幼稚”和“感知”对象。

If your original naive datetime was UTC, the way to recover it is to use utcfromtimestamp instead of fromtimestamp .如果您最初的原始日期时间是 UTC,则恢复它的方法是使用utcfromtimestamp而不是fromtimestamp

On the other hand, if your original naive datetime was local, you shouldn't have subtracted a UTC timestamp from it in the first place;另一方面,如果您最初的原始日期时间是本地的,那么您首先不应该从中减去 UTC 时间戳; use datetime.fromtimestamp(0) instead.请改用datetime.fromtimestamp(0)

Or, if you had an aware datetime object, you need to either use a local (aware) epoch on both sides, or explicitly convert to and from UTC.或者,如果您有一个感知日期时间对象,您需要在双方都使用本地(感知)纪元,或者显式转换为 UTC。

If you have, or can upgrade to, Python 3.3 or later, you can avoid all of these problems by just using the timestamp method instead of trying to figure out how to do it yourself.如果您拥有或可以升级到 Python 3.3 或更高版本,您可以通过使用timestamp方法来避免所有这些问题,而不是尝试自己弄清楚如何去做。 And even if you don't, you may want to consider borrowing its source code .即使你不这样做,你也可以考虑借用它的源代码

(And if you can wait for Python 3.4, it looks like PEP 341 is likely to make it into the final release, which means all of the stuff JF Sebastian and I were talking about in the comments should be doable with just the stdlib, and working the same way on both Unix and Windows.) (如果你可以等待 Python 3.4,看起来PEP 341很可能会进入最终版本,这意味着 JF Sebastian 和我在评论中谈论的所有内容都应该只使用 stdlib 就可以实现,并且在 Unix 和 Windows 上以相同的方式工作。)

Rather than this expression to create a POSIX timestamp from dt ,而不是这个表达式从dt创建一个 POSIX 时间戳,

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

Use this:用这个:

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

I get the right answer in your example using the second method.我使用第二种方法在您的示例中得到了正确的答案。

EDIT: Some followup... After some comments (see below), I was curious about the lack of support or documentation for %s in strftime .编辑:一些后续行动......经过一些评论(见下文),我很好奇strftime中缺乏对%s的支持或文档。 Here's what I found:这是我发现的:

In the Python source for datetime and time , the string STRFTIME_FORMAT_CODES tells us:datetimetimePython 源代码中,字符串STRFTIME_FORMAT_CODES告诉我们:

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

So now if we man strftime (on BSD systems such as Mac OS X), you'll find support for %s :所以现在如果我们man strftime (在诸如 Mac OS X 之类的 BSD 系统上),你会发现对%s支持:

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

Anyways, that's why %s works on the systems it does.无论如何,这就是%s在它所使用的系统上工作的原因。 But there are better solutions to OP's problem (that take timezones into account).但是对于 OP 的问题有更好的解决方案(考虑时区)。 See @abarnert's accepted answer here.在此处查看@abarnert 接受的答案。

For working with UTC timezones:使用 UTC 时区:

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

datetime.utcfromtimestamp(time_stamp)

You've missed the time zone info (already answered, agreed)您错过了时区信息(已回答,同意)

arrow package allows to avoid this torture with datetimes; arrow可以避免这种日期时间的折磨; It is already written, tested, pypi-published, cross-python (2.6 — 3.xx).它已经编写、测试、pypi-published、cross-python (2.6 - 3.xx)。

All you need: pip install arrow (or add to dependencies)所有你需要的: pip install arrow (或添加到依赖项)

Solution for your case适合您的情况的解决方案

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'

If your datetime object represents UTC time, don't use time.mktime, as it assumes the tuple is in your local timezone.如果您的 datetime 对象表示 UTC 时间,请不要使用 time.mktime,因为它假定元组位于您的本地时区。 Instead, use calendar.timegm:相反,使用 calendar.timegm:

>>> import datetime, calendar
>>> d = datetime.datetime(1970, 1, 1, 0, 1, 0)
>>> calendar.timegm(d.timetuple())
60
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)

If you want UTC timestamp : time.mktime just for local dt .Use calendar.timegm is safe but dt must the utc zone so change the zone to utc.如果您想要 UTC 时间戳: time.mktime仅用于本地dt。使用calendar.timegm是安全的,但 dt 必须是 utc 区域,因此将区域更改为 utc。 If dt in UTC just use calendar.timegm .如果 UTC 中的 dt 只需使用calendar.timegm

def datetime_to_epoch(d1):
"""
January 1st, 1970 at 00:00:00 UTC is referred to as the Unix epoch
:param d1: input date
:return: seconds since unix epoch
"""
if not d1.tzinfo:
    raise ValueError("date is missing timezone information")

d2 = datetime(1970, 1, 1, tzinfo=timezone.utc)
time_delta = d1 - d2
ts = int(time_delta.total_seconds())
return ts


def epoch_to_datetime_string(timestamp, tz_name="UTC", **kwargs):
"""
method to convert unix timestamp to date time string
:param ts: 10 digit unix timestamp in seconds
:param tz_name: timezone name
:param kwargs: formatter=<formatter-string>
:return: date time string in timezone
"""

naive_date = datetime.fromtimestamp(timestamp)
aware_date = naive_date.astimezone(pytz.timezone(tz_name))
formatter = kwargs.pop("formatter", "%d %b %Y %H:%M:%S")
return aware_date.strftime(formatter)

Well, when converting TO unix timestamp, python is basically assuming UTC, but while converting back it will give you a date converted to your local timezone.好吧,当转换为 unix 时间戳时,python 基本上假设 UTC,但是在转换回来时,它会给你一个转换为本地时区的日期。

See this question/answer;请参阅此问题/答案; Get timezone used by datetime.datetime.fromtimestamp() 获取 datetime.datetime.fromtimestamp() 使用的时区

This class will cover your needs, you can pass the variable into ConvertUnixToDatetime & call which function you want it to operate based off.此类将满足您的需求,您可以将变量传递给 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())
import time
from datetime import datetime
time.mktime(datetime.now().timetuple())

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM