#python #pandas #datetime #timezone #dst
#python #pandas #дата и время #Часовой пояс #летнее время
Вопрос:
У меня есть фрейм данных pandas с временными метками UNIX (это целые числа, а не временные объекты). Наблюдения происходят в нескольких географических точках и, следовательно, в нескольких часовых поясах. Я хотел бы преобразовать временную метку UNIX в местное время (в новом столбце) для каждого из этих часовых поясов на основе географии наблюдения (эта информация находится в столбце фрейма данных).
Простой рабочий пример:
Создание фрейма данных:
c1=[1546555701, 1546378818, 1546574677, 1546399159, 1546572278]
c2=['America/Detroit','America/Chicago','America/Los_Angeles','America/Los_Angeles','America/Detroit']
df3=pd.DataFrame(list(zip(c1,c2)),columns=['utc','tz'])
print(df3)
Ожидаемый результат:
utc tz
0 1546555701 America/Detroit
1 1546378818 America/Chicago
2 1546574677 America/Los_Angeles
3 1546399159 America/Los_Angeles
4 1546572278 America/Detroit
Текущая попытка:
df3['date_time']=pd.to_datetime(df3['utc'],unit='s')
print(df3)
ВОЗВРАТ:
utc tz date_time
0 1546555701 America/Detroit 2019-01-03 22:48:21
1 1546378818 America/Chicago 2019-01-01 21:40:18
2 1546574677 America/Los_Angeles 2019-01-04 04:04:37
3 1546399159 America/Los_Angeles 2019-01-02 03:19:19
4 1546572278 America/Detroit 2019-01-04 03:24:38
Это преобразуется в объект datetime, но я не уверен, как управлять часовым поясом (я полагаю, это дает мне время в моем местном часовом поясе). Это, конечно, не основано на столбце ‘tz’.
Я просмотрел функцию pandas tz_convert() и пакет arrow, но не смог понять, как заставить их работать. Я открыт и для других решений. Я обеспокоен не только часовым поясом, но и тем, чтобы обеспечить правильную обработку перехода на летнее время.
Комментарии:
1. Это не временные метки UTC. Это могут быть временные метки Unix. Это не придирки. Вне Unix-систем программирование временной метки обычно означает полную временную метку ISO8601. В базах
timestamp
данных тип или его эквиваленты представляют собой значение даты времени2. @PanagiotisKanavos вы правы, я соответствующим образом изменил вопрос.
3. если вам просто нужно работать с этими временными метками, я бы посоветовал оставить его в UTC и сохранить информацию о часовом поясе. Я бы преобразовал только в определенный tz, если вам это нужно для презентации или чего-то еще (нужно, чтобы это было доступно для чтения человеком).
4. @MrFuppes Мне нужно иметь возможность сравнивать наблюдения (например) в 5:00 утра в Детройте с тем, что происходит в 5:00 в Бостоне. Похоже, это требует такого преобразования, нет? Я (вероятно, очевидно) новичок в работе с временными метками, поэтому я открыт для предложений и улучшенных рабочих процессов.
5. Я внес еще одно редактирование; смешанные часовые пояса подходят, но вы не можете использовать средство
dt
доступа, поэтому отдельные атрибуты метки времени немного сложнее извлечь.
Ответ №1:
Предполагая временные метки POSIX (секунды с 1970-01-01 UTC), вы можете напрямую преобразовать в UTC с ключевым словом utc= True .
import pandas as pd
c1=[1546555701, 1546378818, 1546574677, 1546399159, 1546572278]
c2=['America/Detroit','America/Chicago','America/Los_Angeles','America/Los_Angeles','America/Detroit']
df3=pd.DataFrame(list(zip(c1,c2)),columns=['utc','tz'])
df3['date_time']=pd.to_datetime(df3['utc'], unit='s', utc=True)
# df3['date_time']
# 0 2019-01-03 22:48:21 00:00
# 1 2019-01-01 21:40:18 00:00
# 2 2019-01-04 04:04:37 00:00
# 3 2019-01-02 03:19:19 00:00
# 4 2019-01-04 03:24:38 00:00
# Name: date_time, dtype: datetime64[ns, UTC]
Затем вы можете применить часовой пояс к каждому значению с помощью apply , например
def setTZ(row):
return row['date_time'].tz_convert(row['tz'])
df3['date_time']=df3.apply(lambda r: setTZ(r), axis=1)
# df3
# utc tz date_time
# 0 1546555701 America/Detroit 2019-01-03 17:48:21-05:00
# 1 1546378818 America/Chicago 2019-01-01 15:40:18-06:00
# 2 1546574677 America/Los_Angeles 2019-01-03 20:04:37-08:00
# 3 1546399159 America/Los_Angeles 2019-01-01 19:19:19-08:00
# 4 1546572278 America/Detroit 2019-01-03 22:24:38-05:00
Обратите внимание, что при смешанных часовых поясах вы не можете использовать средство dt
доступа для ряда. Вместо этого вам нужен итеративный код, например
df3['date_time'].apply(lambda t: t.hour)
чтобы получить час для каждого datetime. Способ обойти это — создать столбец, который имеет местное время, но не учитывает часовой пояс:
def toLocalTime(row):
return row['date_time'].tz_convert(row['tz']).replace(tzinfo=None)
df3['local_time'] = df3.apply(lambda r: toLocalTime(r), axis=1)
Комментарии:
1. Я предполагаю, что tz_convert() также имеет дело с переходом на летнее время, верно?
2. @amquack: да, это так. И вы правы, для сравнения, как вы упомянули, кажется, проще просто преобразовать в часовые пояса. Поскольку у вас есть имена часовых поясов IANA, это не должно вызвать никаких проблем. Однако, поскольку у вас смешанные часовые пояса, средство
dt
доступа не будет работать, что может быть немного неудобно, потому что вам нужен интерактивный код.3. Интересно, есть ли способ сделать это, не переходя по строкам. Вы упомянули аксессуар dt (я не уверен, что это такое). Но мне интересно, является ли это полезным инструментом для ускорения процесса путем сортировки по часовым поясам перед выполнением преобразования. Я спрашиваю, потому что это стало узким местом в моем процессе. Начальная функция «to_datetime () выполняется очень быстро, но преобразование часовых поясов происходит довольно медленно (я думаю, потому что это построчно)
4. @amquack: для смешанных часовых поясов, насколько мне известно, нет. Вот почему я также предложил сохранить его в UTC, потому что эта часть выполняется быстро.