Преобразование даты и времени в временную метку 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)
.
Час не совпадает. Что я здесь пропустил?
Ответы
Ответ 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)
Ответ 8
Ну, при преобразовании timestamp в unix, python в основном принимает UTC, но при преобразовании обратно он даст вам дату, преобразованную в ваш часовой пояс.
См. этот вопрос/ответ;
Получить часовой пояс, используемый datetime.datetime.fromtimestamp()
Ответ 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
.