Преобразуйте datetime в метку времени Unix и преобразуйте ее обратно в python

Я dt = datetime(2013,9,1,11), и я хотел бы получить временную метку Unix этого объекта datetime.

когда я делаю dt - datetime(1970,1,1)).total_seconds() Я получил метку 1378033200.

при преобразовании его обратно через datetime.fromtimestamp я получил datetime.datetime(2013, 9, 1, 6, 0).

час не совпадает. Что я пропустил?

9 ответов


то, что вы пропустили здесь, это часовые пояса.

предположительно у вас есть пять часов от UTC, поэтому 2013-09-01T11:00:00 local и 2013-09-01T06:00:00Z-одно и то же время.

нужно читать сверху datetime docs, которые объясняют о часовых поясах и "наивных" и "осведомленных" объектах.

если ваш оригинальный наивный datetime был UTC, способ его восстановления-использовать utcfromtimestamp вместо fromtimestamp.

С другой стороны, если ваш исходный наивный datetime был локальным, вы не должны были вычитать из него временную метку UTC в первую очередь; используйте .

или, если у вас был объект aware datetime, вам нужно либо использовать локальную (aware) эпоху с обеих сторон, либо явно преобразовать в UTC и из UTC.

если у вас есть или вы можете обновить до Python 3.3 или более поздней версии, вы можете избежать всех этих проблем, просто используя timestamp метод вместо того, чтобы пытаться выяснить, как это сделать себе. И даже если вы этого не сделаете, вы можете рассмотреть заимствование исходного кода.

(и если вы можете подождать Python 3.4, это выглядит как PEP 341 вероятно, попадет в финальную версию, что означает, что все вещи, о которых мы с Себастьяном говорили в комментариях, должны быть выполнимы только с помощью stdlib и работать одинаково как в Unix, так и в Windows.)


решение

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

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

вместо этого выражения для создания метки времени POSIX из dt,

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

используйте этот:

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

Я получаю правильный ответ в вашем примере, используя второй способ.

EDIT: некоторые последующие действия... После некоторых комментариев (см. ниже) мне было любопытно об отсутствии поддержки или документации для %s на strftime. Вот что я нашел:

на исходным кодом на Python на datetime и time строка STRFTIME_FORMAT_CODES говорит нам:

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

Итак, если мы man strftime (в системах BSD, таких как Mac OS X), вы найдете поддержку %s:

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

вот почему %s работает на системах его вовсе. Но есть лучшие решения проблемы OP (которые учитывают часовые пояса). См. принятый ответ @abarnert здесь.


Если вы хотите преобразовать Python datetime в секунды с эпохи, вы должны сделать это явно:

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

если объект datetime представляет время UTC, не используйте время.mktime, поскольку предполагается, что кортеж находится в вашем локальном часовом поясе. Вместо этого, используйте календарь.timegm:

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

ну, при преобразовании в метку времени unix python в основном предполагает UTC, но при обратном преобразовании он даст вам дату, преобразованную в ваш локальный часовой пояс.

посмотреть этот вопрос/ответ; получить часовой пояс, используемый datetime.значение datetime.fromtimestamp ()


вы пропустили информацию о часовом поясе (уже ответили, договорились)

arrow пакета позволяет избежать этой пытки с датами; он уже написан, протестирован, PyPI-опубликован, кросс-python (2.6 - 3.обман.)

все, что вам нужно: 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'

def dt2ts(dt):
    import calendar
    import time
    from dateutil import tz

    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:

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

datetime.utcfromtimestamp(time_stamp)