Преобразование строки python в localtime в временную метку времени UTC

У меня есть строки в формате hms в формате YMD, в которых был отключен часовой пояс. Но я знаю, что они в восточное время с летним временем.

Я пытаюсь преобразовать их в временные метки времени для UTC.

Я написал следующую функцию:

def ymdhms_timezone_dst_to_epoch(input_str,  tz="US/Eastern"):
    print(input_str)
    dt = datetime.datetime.fromtimestamp(time.mktime(time.strptime(input_str,'%Y-%m-%d %H:%M:%S')))
    local_dt = pytz.timezone(tz).localize(dt)
    print(local_dt.strftime('%Y-%m-%d %H:%M:%S %Z%z'))
    utc_dt = local_dt.astimezone(pytz.utc)
    print(utc_dt.strftime('%Y-%m-%d %H:%M:%S %Z%z'))    
    e = int(utc_dt.strftime("%s"))
    print(e)
    return e

Given string `2015-04-20 21:12:07` this prints:

    2015-04-20 21:12:07
    2015-04-20 21:12:07 EDT-0400 #<- so far so good?
    2015-04-21 01:12:07 UTC+0000 #<- so far so good?
    1429596727

который выглядит нормально до отметки времени эпохи. Но http://www.epochconverter.com/epoch/timezones.php?epoch=1429596727 говорит, что он должен Среднее время по Гринвичу Apr 21 2015 06:12:07 UTC.

Что не так?

Ответ 1

У меня есть строки в формате hms в формате YMD, в которых был отключен часовой пояс. Но я знаю, что они в восточное время с летним временем.

Портативный способ - использовать pytz:

#!/usr/bin/env python
from datetime import datetime
import pytz # $ pip install pytz

naive_dt = datetime.strptime('2015-04-20 21:12:07', '%Y-%m-%d %H:%M:%S')
tz = pytz.timezone('US/Eastern')
eastern_dt = tz.normalize(tz.localize(naive_dt))
print(eastern_dt)
# -> 2015-04-20 21:12:07-04:00

Я пытаюсь преобразовать их в временные метки эпохи для времени UTC.

timestamp = (eastern_dt - datetime(1970, 1, 1, tzinfo=pytz.utc)).total_seconds()
# -> 1429578727.0

Смотрите Преобразование datetime.date в метку времени UTC в Python.


В коде есть несколько проблем:

  • time.mktime() может возвращать неправильный результат для неоднозначного времени ввода (вероятность 50%), например, во время перехода "назад" DST на осень

  • time.mktime() и datetime.fromtimestamp() могут не работать для прошлых/будущих дат, если у них нет доступа к базе данных хронологического времени в системе (в частности, Windows)

  • localize(dt) может возвращать неправильный результат для двусмысленного или несуществующего времени, то есть во время перехода DST. Если вы знаете, что время соответствует летнему времени, используйте is_dst=True. tz.normalize() необходимо здесь, чтобы отрегулировать возможные несуществующие времена на входе

  • utc_dt.strftime("%s") не переносится и не поддерживает объект tzinfo. Он интерпретирует ввод как локальное время, то есть возвращает неверный результат, если ваш часовой пояс не является UTC.


Можно ли просто установить is_dst = True?

Вы можете, если вы не возражаете получить неточные результаты для двусмысленных или несуществующих времен, например, существует переход на летнее время в период падения в Америке /New _York:

>>> from datetime import datetime
>>> import pytz # $ pip install pytz
>>> tz = pytz.timezone('America/New_York')
>>> ambiguous_time = datetime(2015, 11, 1, 1, 30)
>>> time_fmt = '%Y-%m-%d %H:%M:%S%z (%Z)'
>>> tz.localize(ambiguous_time).strftime(time_fmt)
'2015-11-01 01:30:00-0500 (EST)'
>>> tz.localize(ambiguous_time, is_dst=False).strftime(time_fmt) # same
'2015-11-01 01:30:00-0500 (EST)'
>>> tz.localize(ambiguous_time, is_dst=True).strftime(time_fmt) # different
'2015-11-01 01:30:00-0400 (EDT)'
>>> tz.localize(ambiguous_time, is_dst=None).strftime(time_fmt) 
Traceback (most recent call last):
...
pytz.exceptions.AmbiguousTimeError: 2015-11-01 01:30:00

Часы возвращаются в 2a.m. в первое воскресенье ноября:

clocks are turned back

Флаг значений

is_dst может иметь три значения:

  • False - по умолчанию, предположим зимнее время
  • True - принять летнее время
  • None - создать исключение для неоднозначных/несуществующих времен.

is_dst значение игнорируется для существующих уникальных локальных времен.

Здесь приведен график из PEP 0495 - Локальное значение времени > , которое иллюстрирует переход DST: utc vs. local time in the fold

Местное время повторяется дважды в складке (летнее время - до складки, зима - после).

Чтобы иметь возможность автоматически дистанцировать локальное время, вам нужна дополнительная информация, например, если вы читаете серию локальных раз, то это может помочь, если вы знаете, что они отсортированы: Анализ устаревших временных меток в локальное время (до UTC) при наблюдении за летним временем.

Ответ 2

В первую очередь '%s' не поддерживается на всех платформах, он действительно работает для вас, потому что поддерживает его платформа C librarys strftime() (она называется Python). Эта функция является тем, что вызывает проблему, скорее всего, я предполагаю, что она не знает о часовом поясе, поэтому, принимая разницу с эпохи, она использует ваш часовой пояс, который, скорее всего, является EST (?)

Вместо того, чтобы полагаться на '%s', который работает только на нескольких платформах (linux, я считаю), вы должны вручную вычесть время, полученное вами из эпохи (1970/1/1 00:00:00), чтобы получить фактические секунды с эпохи. Пример -

e = (utc_dt - datetime.datetime(1970,1,1,0,0,0,tzinfo=pytz.utc)).total_seconds()

Демо -

>>> (utc_dt - datetime.datetime(1970,1,1,0,0,0,tzinfo=pytz.utc)).total_seconds()
1429578727.0

Это правильно соответствует дате времени.

Ответ 3

Я точно не знаю, почему, но вам нужно удалить информацию о часовом поясе с вашего utc_dt, прежде чем использовать %s для печати. ​​

e = int(utc_dt.replace(tzinfo=None).strftime("%s"))
print(e)
return e