Как преобразовать строку местного времени в UTC?


308

Как преобразовать строку даты и времени по местному времени в строку по времени UTC ?

Я уверен, что я делал это раньше, но не могу найти его, и мы надеемся, что SO (и другие) поможет это сделать в будущем.

Разъяснение : Например, если у меня есть 2008-09-17 14:02:00в моей временной зоне ( +10), я хотел бы создать строку с эквивалентным UTCвременем: 2008-09-17 04:02:00.

Кроме того, из http://lucumr.pocoo.org/2011/7/15/eppur-si-muove/ обратите внимание, что в целом это невозможно, так как в случае летнего времени и других вопросов не существует уникального преобразования из местного времени в Время UTC


1
Помните, что метод mktime () принимает в качестве входных данных «местное время», которое может не соответствовать ожидаемому вами, я использовал его, и он все испортил. Пожалуйста, взгляните на эту ссылку
Хайфэн Чжан

Ответы:


288

Сначала проанализируйте строку в наивном объекте datetime. Это пример datetime.datetimeбез прикрепленной информации о часовом поясе. См. Документацию для datetime.strptimeполучения информации о разборе строки даты.

Используйте pytzмодуль, который поставляется с полным списком часовых поясов + UTC. Выясните, что такое местный часовой пояс, создайте из него объект часового пояса, манипулируйте им и присоединяйте его к наивному времени.

Наконец, используйте datetime.astimezone()метод для преобразования даты и времени в UTC.

Исходный код, используя местный часовой пояс "America / Los_Angeles", для строки "2001-2-3 10:11:12":

import pytz, datetime
local = pytz.timezone ("America/Los_Angeles")
naive = datetime.datetime.strptime ("2001-2-3 10:11:12", "%Y-%m-%d %H:%M:%S")
local_dt = local.localize(naive, is_dst=None)
utc_dt = local_dt.astimezone(pytz.utc)

Оттуда вы можете использовать strftime()метод для форматирования даты и времени UTC по мере необходимости:

utc_dt.strftime ("%Y-%m-%d %H:%M:%S")

7
Пожалуйста, измените ваш ответ следующим кодом: [code] local.localize (naive) [/ code] См. Документ: ссылка К сожалению, использование аргумента tzinfo стандартных конструкторов даты и времени '' не работает '' с pytz для многих часовых поясов. >>> datetime (2002, 10, 27, 12, 0, 0, tzinfo = amsterdam) .strftime (fmt) '2002-10-27 12:00:00 AMT + 0020'
Сэм Стоилинга

2
Очевидно, шаг «выяснить, что такое местный часовой пояс» оказывается сложнее, чем кажется (практически невозможно).
Джейсон Р. Кумбс

2
Используйте local.localize в соответствии с предложением @SamStoelinga, иначе вы не будете учитывать летнее время.
Эмиль Стенстрём

Этот ответ был очень полезен для меня, но я хотел бы указать на ловушку, с которой я столкнулся. Если вы укажете время, но не дату, вы можете получить неожиданные результаты. Поэтому убедитесь, что вы указали полную временную метку.
Стивен Меркатанте


145

Функция utcnow () модуля datetime может использоваться для получения текущего времени UTC.

>>> import datetime
>>> utc_datetime = datetime.datetime.utcnow()
>>> utc_datetime.strftime("%Y-%m-%d %H:%M:%S")
'2010-02-01 06:59:19'

Как упомянуто выше Томом: http://lucumr.pocoo.org/2011/7/15/eppur-si-muove/ говорит:

UTC - это часовой пояс без перехода на летнее время и, тем не менее, часовой пояс без изменений конфигурации в прошлом.

Всегда измеряйте и сохраняйте время в UTC .

Если вам нужно записать, где было занято время, сохраните его отдельно. Не храните информацию о местном времени + часовом поясе!

ПРИМЕЧАНИЕ. - Если какие-либо ваши данные находятся в регионе, использующем DST, используйте pytzи посмотрите ответ Джона Милликина.

Если вы хотите получить время UTC из заданной строки и вам посчастливилось оказаться в регионе мира, в котором либо не используется DST, либо у вас есть данные, которые только смещены относительно UTC без применения DST:

-> используя местное время в качестве основы для значения смещения:

>>> # Obtain the UTC Offset for the current system:
>>> UTC_OFFSET_TIMEDELTA = datetime.datetime.utcnow() - datetime.datetime.now()
>>> local_datetime = datetime.datetime.strptime("2008-09-17 14:04:00", "%Y-%m-%d %H:%M:%S")
>>> result_utc_datetime = local_datetime + UTC_OFFSET_TIMEDELTA
>>> result_utc_datetime.strftime("%Y-%m-%d %H:%M:%S")
'2008-09-17 04:04:00'

-> Или из известного смещения, используя datetime.timedelta ():

>>> UTC_OFFSET = 10
>>> result_utc_datetime = local_datetime - datetime.timedelta(hours=UTC_OFFSET)
>>> result_utc_datetime.strftime("%Y-%m-%d %H:%M:%S")
'2008-09-17 04:04:00'

ОБНОВИТЬ:

Начиная с Python 3.2 datetime.timezoneдоступен. Вы можете создать объект datetime с учетом часового пояса с помощью команды ниже:

import datetime

timezone_aware_dt = datetime.datetime.now(datetime.timezone.utc)

Если вы готовы перейти на часовой пояс, прочитайте это:

https://medium.com/@eleroy/10-things-you-need-to-know-about-date-and-time-in-python-with-datetime-pytz-dateutil-timedelta-309bfbafb3f7


14
Это только преобразует текущее время, мне нужно взять любое заданное время (в виде строки) и преобразовать в UTC.
Том

Я не думаю, что это должно иметь значение, если вы используете стандартные значения смещения. local_time = utc_time + utc_offset AND utc_time = local_time - utc_offset.
Monkut

5
Это работает только с текущим временем, потому что прошлые и будущие временные метки могут иметь различное смещение UTC из-за перехода на летнее время.
Алекс Б

хороший момент ... если вам приходится иметь дело с DST, вы, вероятно, должны использовать pytz, как упомянуто Джоном Милликиным.
Monkut

1
Между вызовами utcnow () и now () есть спорадическая дельта. Это опасная строка кода, которая может привести к странным ошибкам, например, tzinfo.utcoffset() must return a whole number of minutesи так далее.
Павел Власов

62

Благодаря @rofly, полное преобразование строки в строку выглядит следующим образом:

time.strftime("%Y-%m-%d %H:%M:%S", 
              time.gmtime(time.mktime(time.strptime("2008-09-17 14:04:00", 
                                                    "%Y-%m-%d %H:%M:%S"))))

Мое резюме функций time/ calendar:

time.strptime
string -> tuple (часовой пояс не применяется, поэтому соответствует строке)

time.mktime
кортеж по местному времени -> секунды с начала эпохи (всегда по местному времени)

time.gmtime
секунд с начала эпохи -> кортеж в UTC

и

calendar.timegm
кортеж в UTC -> секунд с начала эпохи

time.localtime
секунд с начала эпохи -> кортеж в местном часовом поясе


4
(always local time)кажется неправильным: вход в mktime () - местное время, выход - секунды с момента epoch ( 1970-01-01 00:00:00 +0000 (UTC)), которые не зависят от часового пояса.
JFS

3
Также есть 50% вероятность того, что он потерпит неудачу во время перехода на летнее время. См. Проблемы с местным временем
jfs

38

Вот краткое изложение общих преобразований времени Python.

Некоторые методы отбрасывают доли секунд и помечаются символом (ами) . ts = (d - epoch) / unitВместо этого можно использовать явную формулу, например, (спасибо jfs).

  • struct_time (UTC) → POSIX (s) :
    calendar.timegm(struct_time)
  • Наивное время (местное) → POSIX (s) :
    calendar.timegm(stz.localize(dt, is_dst=None).utctimetuple())
    (исключение при переходах на летнее время, см. Комментарий от jfs)
  • Наивная дата и время (UTC) → POSIX (s) :
    calendar.timegm(dt.utctimetuple())
  • Знать дату и время → POSIX (s) :
    calendar.timegm(dt.utctimetuple())
  • POSIX → struct_time (UTC, s ):
    time.gmtime(t)
    (см. Комментарий от jfs)
  • Наивная дата-время (локальная) → struct_time (UTC, s ):
    stz.localize(dt, is_dst=None).utctimetuple()
    (исключение при переходах на летнее время, см. Комментарий от jfs)
  • Наивная дата-время (UTC) → struct_time (UTC, с ):
    dt.utctimetuple()
  • Знать дату и время → struct_time (UTC, s ):
    dt.utctimetuple()
  • POSIX → Наивная дата-время (локальная):
    datetime.fromtimestamp(t, None)
    (может не работать при определенных условиях, см. Комментарий от jfs ниже)
  • struct_time (UTC) → Наивная дата-время (локальная, с ):
    datetime.datetime(struct_time[:6], tzinfo=UTC).astimezone(tz).replace(tzinfo=None)
    (не может представлять високосные секунды, см. комментарий от jfs)
  • Наивное время (UTC) → Наивное время (местное):
    dt.replace(tzinfo=UTC).astimezone(tz).replace(tzinfo=None)
  • Знать дату и время → Наивное время (местное):
    dt.astimezone(tz).replace(tzinfo=None)
  • POSIX → Наивное время (UTC):
    datetime.utcfromtimestamp(t)
  • struct_time (UTC) → Наивная дата-время (UTC, s ):
    datetime.datetime(*struct_time[:6])
    (не может представлять високосные секунды, см. комментарий от jfs)
  • Наивная дата-время (локальная) → Наивная дата-время (UTC):
    stz.localize(dt, is_dst=None).astimezone(UTC).replace(tzinfo=None)
    (исключение при переходах на летнее время, см. Комментарий от jfs)
  • Зная дату и время → Наивное время (UTC):
    dt.astimezone(UTC).replace(tzinfo=None)
  • POSIX → Aware datetime:
    datetime.fromtimestamp(t, tz)
    (может не работать для часовых поясов, отличных от pytz)
  • struct_time (UTC) → Зная дату (ы) :
    datetime.datetime(struct_time[:6], tzinfo=UTC).astimezone(tz)
    (не может представлять високосные секунды, см. комментарий от jfs)
  • Наивное datetime (локальное) → Aware datetime:
    stz.localize(dt, is_dst=None)
    (исключение во время перехода на летнее время, см. Комментарий от jfs)
  • Наивное время и дата (UTC) → Зная время и дата:
    dt.replace(tzinfo=UTC)

Источник: taaviburns.ca


1
(1) fromtimestamp(t, None)может потерпеть неудачу, если локальный часовой пояс имеет различное смещение utc в, t а библиотека C не имеет доступа к базе данных tz на данной платформе. Вы можете использовать tzlocal.get_localzone()для предоставления tzdata в портативном виде. (2) fromtimestamp(t, tz)может потерпеть неудачу для часовых поясов, отличных от pytz. (3) datetime(*struct_time[:6])вы пропали без вести *. (4) timegm(), utctimetuple(), struct_timeоснованные растворы падение доли секунды. Вы можете использовать явную формулу, такую ​​как: ts = (d - epoch) / unitвместо.
JFS

1
(5) stz.localize(dt, is_dst=None)выдвигает исключение для неоднозначных или несуществующих локальных времен, например, во время переходов DST. Чтобы избежать исключения, используйте, stz.normalize(stz.localize(dt))которые могут вернуть неточные результаты. (6) datetime () не может представлять високосную секунду. Преобразование struct_timeв «секунды с эпохи» в качестве обходного пути в первую очередь. (7) в time.gmtime(t)отличие от calendar.timegm()ожидаемого ввода не-POSIX, если используется «правильный» часовой пояс. Используйте явную формулу, если вместо этого gmtime = lambda t: datetime(1970,1,1, tzinfo=utc) + timedelta(seconds=t)
вводится

Я хотел бы, чтобы это было в таблице, легче читать (это в ссылке)
MichaelChirico

1
@MichaelChirico, в этом ответе говорится, что «мы не разрешаем (и не будем) разрешать <table>теги. Извините. Это сделано намеренно и специально. Если вам нужна быстрая и грязная« таблица », используйте <pre>и ASCII-макет». Я не верю, что таблица ASCII была бы более читабельной, чем список выше.
акайхола

ну, это прискорбно. В любом случае, у вас есть мое возражение ... может быть, ссылка на таблицу в ссылке в вашем ответе?
MichaelChirico

25
def local_to_utc(t):
    secs = time.mktime(t)
    return time.gmtime(secs)

def utc_to_local(t):
    secs = calendar.timegm(t)
    return time.localtime(secs)

Источник: http://feihonghsu.blogspot.com/2008/02/converting-from-local-time-to-utc.html

Пример использования от bd808 : если ваш источник является datetime.datetimeобъектом t, вызовите как:

local_to_utc(t.timetuple())

5
Если ваш источник является объектом datetime.datetime t, вызовите как: local_to_utc (t.timetuple ())
bd808

2
.timetuple()наборы вызовов tm_isdstдля -1; вероятность mktime()перехода 50% во время перехода на летнее время
JFS

1
Решение Чака теряет миллисекундную информацию.
Лука

21

Мне повезло с dateutil (который широко рекомендуется на SO для других связанных вопросов):

from datetime import *
from dateutil import *
from dateutil.tz import *

# METHOD 1: Hardcode zones:
utc_zone = tz.gettz('UTC')
local_zone = tz.gettz('America/Chicago')
# METHOD 2: Auto-detect zones:
utc_zone = tz.tzutc()
local_zone = tz.tzlocal()

# Convert time string to datetime
local_time = datetime.strptime("2008-09-17 14:02:00", '%Y-%m-%d %H:%M:%S')

# Tell the datetime object that it's in local time zone since 
# datetime objects are 'naive' by default
local_time = local_time.replace(tzinfo=local_zone)
# Convert time to UTC
utc_time = local_time.astimezone(utc_zone)
# Generate UTC time string
utc_string = utc_time.strftime('%Y-%m-%d %H:%M:%S')

(Код был получен из этого ответа для преобразования строки даты и времени UTC в локальную дату и время )


dateutilможет потерпеть неудачу для прошлых дат, если местный часовой пояс имел другое смещение utc, чем (не связанное с переходами DST) в системах, где реализация не использует базу данных исторических часовых поясов (особенно Windows). pytz+ tzlocalможно использовать вместо.
JFS

@ JFSebastian- Разве не слышал об этом, где мы можем получить больше информации?
Ярин

возьмите Windows-машину, установите любой часовой пояс, который имел различное смещение utc в прошлом, например, Европа / Москва. Сравните результаты с pytz . Кроме того, вы можете проверить эту ошибку, которая не работает даже в Ubuntu, хотя я не уверен в правильном использовании API в этом случае.
ДЖФс

Какой выход? Пожалуйста, опубликуйте результаты.
not2qubit

18

Еще один пример с pytz, но включает localize (), который спас мой день.

import pytz, datetime
utc = pytz.utc
fmt = '%Y-%m-%d %H:%M:%S'
amsterdam = pytz.timezone('Europe/Amsterdam')

dt = datetime.datetime.strptime("2012-04-06 10:00:00", fmt)
am_dt = amsterdam.localize(dt)
print am_dt.astimezone(utc).strftime(fmt)
'2012-04-06 08:00:00'


7
import time

import datetime

def Local2UTC(LocalTime):

    EpochSecond = time.mktime(LocalTime.timetuple())
    utcTime = datetime.datetime.utcfromtimestamp(EpochSecond)

    return utcTime

>>> LocalTime = datetime.datetime.now()

>>> UTCTime = Local2UTC(LocalTime)

>>> LocalTime.ctime()

'Thu Feb  3 22:33:46 2011'

>>> UTCTime.ctime()

'Fri Feb  4 05:33:46 2011'

mktime(dt.timetuple())может потерпеть неудачу во время перехода DST . Есть LocalTimezoneв документах (это работает для самого последнего определения часового пояса, но может потерпеть неудачу для прошлых дат (не связанных с DST))
jfs

5

если вы предпочитаете datetime.datetime:

dt = datetime.strptime("2008-09-17 14:04:00","%Y-%m-%d %H:%M:%S")
utc_struct_time = time.gmtime(time.mktime(dt.timetuple()))
utc_dt = datetime.fromtimestamp(time.mktime(utc_struct_time))
print dt.strftime("%Y-%m-%d %H:%M:%S")

1
Конечно, но я не понимаю, почему ты предпочитаешь это. Требуется дополнительный импорт и на 3 вызова больше функций, чем моей версии ...
Том

% Z и% z по-прежнему печатает пробелы.
Павел Власов

2
это неверно. Это терпит неудачу, если местный часовой пояс не UTC. mktime()ожидает местное время в качестве входа. fromtimestamp()возвращает местное время, а не utc. Если вы это исправите, то увидите, что эти дополнительные проблемы (например dateutil, решение только для stdlib может дать сбой)
jfs

5

просто

Я сделал это так:

>>> utc_delta = datetime.utcnow()-datetime.now()
>>> utc_time = datetime(2008, 9, 17, 14, 2, 0) + utc_delta
>>> print(utc_time)
2008-09-17 19:01:59.999996

Необычная реализация

Если вы хотите получить фантазию, вы можете превратить это в функтор:

class to_utc():
    utc_delta = datetime.utcnow() - datetime.now()

    def __call__(cls, t):
        return t + cls.utc_delta

Результат:

>>> utc_converter = to_utc()
>>> print(utc_converter(datetime(2008, 9, 17, 14, 2, 0)))
2008-09-17 19:01:59.999996

5
это не работает в летнее время - например, если сейчас лето, а дата, которую вы конвертируете, - зима. и вопрос был о преобразовании дат, хранящихся в виде строк ...
Том

1
FYI. Самая большая проблема этого метода (помимо перехода на летнее время) состоит в том, что дельта отключится на несколько миллисекунд. Все мои приглашения в календаре отображаются отключенными на 1 минуту.
Nostalg.io


3

Как насчет -

time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(seconds))

если секунд, Noneто он преобразует местное время в UTC, иначе преобразует переданное время в UTC.


2

Для перехода на летнее время и т. Д.

Ни один из приведенных выше ответов не помог мне. Код ниже работает для GMT.

def get_utc_from_local(date_time, local_tz=None):
    assert date_time.__class__.__name__ == 'datetime'
    if local_tz is None:
        local_tz = pytz.timezone(settings.TIME_ZONE) # Django eg, "Europe/London"
    local_time = local_tz.normalize(local_tz.localize(date_time))
    return local_time.astimezone(pytz.utc)

import pytz
from datetime import datetime

summer_11_am = datetime(2011, 7, 1, 11)
get_utc_from_local(summer_11_am)
>>>datetime.datetime(2011, 7, 1, 10, 0, tzinfo=<UTC>)

winter_11_am = datetime(2011, 11, 11, 11)
get_utc_from_local(winter_11_am)
>>>datetime.datetime(2011, 11, 11, 11, 0, tzinfo=<UTC>)

2

Использование http://crsmithdev.com/arrow/

arrowObj = arrow.Arrow.strptime('2017-02-20 10:00:00', '%Y-%m-%d %H:%M:%S' , 'US/Eastern')

arrowObj.to('UTC') or arrowObj.to('local') 

Эта библиотека облегчает жизнь :)


Стрелка потрясающая: arrow.get (datetime.now (), 'local'). to ('utc'). naive
SteveJ

1

Я нашел лучший ответ на другой вопрос здесь . Он использует только встроенные библиотеки Python и не требует ввода вашего местного часового пояса (требование в моем случае)

import time
import calendar

local_time = time.strptime("2018-12-13T09:32:00.000", "%Y-%m-%dT%H:%M:%S.%f")
local_seconds = time.mktime(local_time)
utc_time = time.gmtime(local_seconds)

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


1

У меня есть этот код в одном из моих проектов:

from datetime import datetime
## datetime.timezone works in newer versions of python
try:
    from datetime import timezone
    utc_tz = timezone.utc
except:
    import pytz
    utc_tz = pytz.utc

def _to_utc_date_string(ts):
    # type (Union[date,datetime]]) -> str
    """coerce datetimes to UTC (assume localtime if nothing is given)"""
    if (isinstance(ts, datetime)):
        try:
            ## in python 3.6 and higher, ts.astimezone() will assume a
            ## naive timestamp is localtime (and so do we)
            ts = ts.astimezone(utc_tz)
        except:
            ## in python 2.7 and 3.5, ts.astimezone() will fail on
            ## naive timestamps, but we'd like to assume they are
            ## localtime
            import tzlocal
            ts = tzlocal.get_localzone().localize(ts).astimezone(utc_tz)
    return ts.strftime("%Y%m%dT%H%M%SZ")

0

В python3:

pip install python-dateutil

from dateutil.parser import tz

mydt.astimezone(tz.gettz('UTC')).replace(tzinfo=None) 

это, похоже, не работает, оно вызывает исключение ValueError: ValueError: astimezone () нельзя применить к наивной дате и времени
Stormsson

Это должно быть: from dateutil import tz
Хавьер

-3

Как насчет -

time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(seconds))

если секунд, Noneто он преобразует местное время в UTC, иначе преобразует переданное время в UTC.


1
Это не помогает, вопрос заключался в том, чтобы преобразовать данную строку местного времени в строку utc.
Том
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.