Python: преобразование строки в метку времени с помощью микросекунд

Я хотел бы преобразовать строковый формат даты в метку времени с микросекундами Я пробую следующее, но не ожидая результата:

"""input string date -> 2014-08-01 04:41:52,117
expected result -> 1410748201.117"""

import time
import datetime

myDate = "2014-08-01 04:41:52,117"
timestamp = time.mktime(datetime.datetime.strptime(myDate, "%Y-%m-%d %H:%M:%S,%f").timetuple())

print timestamp
> 1410748201.0

Где прошло миллисекунды?

Ответ 1

В кортеже времени нет слота для компонента микросекунд:

>>> import time
>>> import datetime
>>> myDate = "2014-08-01 04:41:52,117"
>>> datetime.datetime.strptime(myDate, "%Y-%m-%d %H:%M:%S,%f").timetuple()
time.struct_time(tm_year=2014, tm_mon=8, tm_mday=1, tm_hour=4, tm_min=41, tm_sec=52, tm_wday=4, tm_yday=213, tm_isdst=-1)

Вам придется добавить их вручную:

>>> dt = datetime.datetime.strptime(myDate, "%Y-%m-%d %H:%M:%S,%f")
>>> time.mktime(dt.timetuple()) + (dt.microsecond / 1000000.0)
1406864512.117

Другой метод, который вы могли бы использовать, - создать объект timedelta() относительно эпохи, а затем получить метку времени с помощью timedelta.total_seconds():

epoch = datetime.datetime.fromtimestamp(0)
(dt - epoch).total_seconds()

Использование эпохи локального времени вполне осознанно, поскольку у вас есть наивное (не учитывающее часовой пояс) значение даты и времени. Этот метод может быть неточным, основываясь на истории вашего локального часового пояса, однако, см. Комментарий JF Sebastian. Вам нужно будет преобразовать наивное значение datetime в значение datetime с учетом часового пояса, сначала используя локальный часовой пояс, а затем вычесть эпоху с учетом часового пояса.

Таким образом, легче придерживаться timetuple() + микросекунды.

Демо-версия:

>>> dt = datetime.datetime.strptime(myDate, "%Y-%m-%d %H:%M:%S,%f")
>>> epoch = datetime.datetime.fromtimestamp(0)
>>> (dt - epoch).total_seconds()
1406864512.117

Ответ 2

В Python 3.4 и позже вы можете использовать

timestamp = datetime.datetime.strptime(myDate, "%Y-%m-%d %H:%M:%S,%f").timestamp()

Это не требует импорта модуля time. Он также использует меньше шагов, поэтому он должен быть быстрее. Для более старых версий Python другие ответы, вероятно, ваш лучший вариант.

Однако полученная временная метка будет интерпретировать myDate по местному времени, а не по UTC, что может вызвать проблемы, если myDate было указано в UTC

Ответ 3

Где прошло миллисекунды?

Это легкая часть. Показ .timetuple() вызывает их падение. Вы можете добавить их обратно с помощью атрибута .microsecond. Метод datetime.timestamp() из стандартной библиотеки работает таким образом для наивных объектов datetime:

def timestamp(self):
    "Return POSIX timestamp as float"
    if self._tzinfo is None:
        return _time.mktime((self.year, self.month, self.day,
                             self.hour, self.minute, self.second,
                             -1, -1, -1)) + self.microsecond / 1e6
    else:
        return (self - _EPOCH).total_seconds()

Достаточно, если возможно, в вашем случае можно проигнорировать 1 час ошибок. Я предполагаю, что вам нужны микросекунды, и поэтому вы не можете игнорировать ошибки продолжительностью 1 час без изменений.

Преобразование локального времени, заданного как строка в метку времени POSIX, является сложной задачей в целом. Вы можете преобразовать местное время в UTC, а затем получить временную метку времени UTC.

Существуют две основные проблемы:

  • местное время может быть несуществующим или неоднозначным, например. во время переходов DST одно и то же время может происходить дважды
  • Смещение UTC для локального часового пояса может отличаться в прошлом и, следовательно, наивное: local time minus epoch in local time формула может выйти из строя

Оба могут быть решены с использованием базы данных tz (модуль pytz в Python):

from datetime import datetime
import pytz # $ pip install pytz
from tzlocal import get_localzone # $ pip install tzlocal

tz = get_localzone() # get pytz timezone corresponding to the local timezone

naive_d = datetime.strptime(myDate, "%Y-%m-%d %H:%M:%S,%f")
# a) raise exception for non-existent or ambiguous times
d = tz.localize(naive_d, is_dst=None)
## b) assume standard time, adjust non-existent times
#d = tz.normalize(tz.localize(naive_d, is_dst=False))
## c) assume DST is in effect, adjust non-existent times
#d = tz.normalize(tz.localize(naive_d, is_dst=True))
timestamp = d - datetime(1970, 1, 1, tzinfo=pytz.utc)

В результате объект timestamp - a timedelta, вы можете преобразовать его в секунды, миллисекунды и т.д.

Также разные системы могут вести себя по-разному вокруг/в течение прыжковых секунд. Большинство приложений могут игнорировать то, что они существуют.

В общем, может быть проще хранить метки времени POSIX в дополнение к местному времени, а не пытаться угадать его с локального времени.