Преобразуйте 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)