У меня есть 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)
.
Час не совпадает. Что я здесь упустил?
решение в
import time
import datetime
d = datetime.date(2015,1,5)
unixtime = time.mktime(d.timetuple())
Что вы упустили, так это часовые пояса.
Предположительно, вы отклонились от UTC на пять часов, поэтому 2013-09-01T11:00:00 по местному времени и 2013-09-01T06:00:00Z - одно и то же время.
Вам нужно прочитать верхнюю часть документации datetime
, где объясняется про часовые пояса и "наивные" и "знающие" объекты.
Если ваше первоначальное наивное время даты было UTC, способ восстановить его - использовать utcfromtimestamp
вместо fromtimestamp
.
С другой стороны, если ваше исходное наивное время было локальным, вам не следовало вычитать из него временную метку UTC; вместо этого используйте datetime.fromtimestamp(0)
.
Или, если у вас был объект aware datetime, вам нужно либо использовать локальную (aware) эпоху с обеих сторон, либо явно конвертировать в UTC и обратно.
Если у вас есть или вы можете перейти на Python 3.3 или более позднюю версию, вы можете избежать всех этих проблем, просто используя метод timestamp
вместо того, чтобы пытаться понять, как это сделать самостоятельно. И даже если это не так, вы можете рассмотреть возможность заимствования его исходного кода.
(И если вы можете подождать Python 3.4, похоже, что PEP 341, скорее всего, войдет в финальный релиз, что означает, что все вещи, о которых мы с Дж.Ф. Себастьяном говорили в комментариях, можно будет сделать с помощью только stdlib, и они будут работать одинаково как на Unix, так и на Windows).
Вместо этого выражения для создания временной метки POSIX из dt
,
(dt - datetime(1970,1,1)).total_seconds()
используйте это:
int(dt.strftime("%s"))
Я получаю правильный ответ в вашем примере, используя второй метод.
EDIT: Некоторое продолжение... После некоторых комментариев (см. ниже), мне стало интересно отсутствие поддержки или документации для %s
в strftime
. Вот что я нашел:
В Python source для 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-значений; он уже написан, проверен, pypi-опубликовано, крест-на Python (2.6 — 3.ХХ).
Все, что вам нужно: типун установить стрелку
(или добавить к зависимостям)
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'
Если ваш объект datetime представляет мирового времени, Дон'т использовать время.функцией mktime, как он предполагает Кортеж в ваш местный часовой пояс. Вместо этого, используйте календарь.timegm:
>>> import datetime, calendar
>>> d = datetime.datetime(1970, 1, 1, 0, 1, 0)
>>> calendar.timegm(d.timetuple())
60
Для работы с часовыми поясами по Гринвичу:
time_stamp = calendar.timegm(dt.timetuple())
datetime.utcfromtimestamp(time_stamp)
При преобразовании в unix timestamp python в основном принимает UTC, но при обратном преобразовании он выдает дату, преобразованную в ваш местный часовой пояс.
См. этот вопрос/ответ; https://stackoverflow.com/questions/18812638/get-timezone-used-by-datetime-datetime-fromtimestamp
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 : время.функцией mktime только на местное ДТ .Использовать календарь.timegm-это безопасный, но ДТ должны Гринвичу, таким образом, изменить зону на UTC. Если ДТ в формате просто использовать календарь.timegm`.
def datetime_to_epoch(d1):
# create 1,1,1970 in same timezone as d1
d2 = datetime(1970, 1, 1, tzinfo=d1.tzinfo)
time_delta = d1 - d2
ts = int(time_delta.total_seconds())
return ts
def epoch_to_datetime_string(ts, tz_name="UTC"):
x_timezone = timezone(tz_name)
d1 = datetime.fromtimestamp(ts, x_timezone)
x = d1.strftime("%d %B %Y %H:%M:%S")
return x