Подтвердить что ты не робот

Преобразование даты и времени в временную метку Unix и преобразование ее обратно в python

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

Когда я делаю (dt - datetime(1970,1,1)).total_seconds() я 1378033200 метку времени 1378033200.

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

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

4b9b3361

Ответ 1

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

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

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

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

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

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

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

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

Ответ 2

решение

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

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

Ответ 3

Вместо этого выражения для создания метки времени 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 здесь.

Ответ 4

Если вы хотите преобразовать дату и время 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

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

arrow package позволяет избежать этой пытки с помощью datetime; Он уже написан, протестирован, опубликован pypi, 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'

Ответ 6

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

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

Ответ 7

Для работы с часовыми поясами UTC:

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

datetime.utcfromtimestamp(time_stamp)

Ответ 9

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 timestamp: time.mktime только для локального dt. Используйте calendar.timegm безопасно, но dt должна указывать зону utc, поэтому измените зону на utc. Если dt в UTC, просто используйте calendar.timegm.