Pandas преобразует время UNIX в несколько разных часовых поясов в зависимости от значения столбца

#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, потому что эта часть выполняется быстро.