Прежде всего обратите внимание, что без смещения некоторые локальные моменты и, следовательно, их дата-время строки неоднозначны. Так, например, ISO 8601 DateTime строки
2000-10-29T01:00:00-07:00
2000-10-29T01:00:00-08:00
как карта для одной и той же строке 2000-10-29T01:00:00
, когда смещение удаляется.
Так что не всегда возможно восстановить уникальную информацию о времени, отличном от часового пояса, datetime из строки datetime без смещения.
Однако мы могли бы сделать выбор в этих неопределенных ситуациях и принять, что не все двусмысленные даты будут правильно преобразованы.
Если вы используете Unix, вы можете использовать time.tzset изменить локальный часовой пояс процесса в:
import os
import time
os.environ['TZ'] = tz
time.tzset()
Затем можно преобразовать даты-строки в NumPy datetime64, используя
def using_tzset(date_strings, tz):
os.environ['TZ'] = tz
time.tzset()
return np.array(date_strings, dtype='datetime64[ns]')
Обратите внимание, что using_tzset
не всегда производит то же значение, что и метод, который вы предложили:
import os
import time
import numpy as np
import pandas as pd
tz = 'US/Pacific'
N = 10**5
dates = pd.date_range('2000-1-1', periods=N, freq='H', tz=tz)
date_strings_tz = dates.format(formatter=lambda x: x.isoformat())
date_strings = [d.rsplit('-', 1)[0] for d in date_strings_tz]
def orig(date_strings, tz):
return [np.datetime64(pd.Timestamp(s, tz=tz)) for s in date_strings]
def using_tzset(date_strings, tz):
os.environ['TZ'] = tz
time.tzset()
return np.array(date_strings, dtype='datetime64[ns]')
npdates = dates.asi8.view('datetime64[ns]')
x = np.array(orig(date_strings, tz))
y = using_tzset(date_strings, tz)
df = pd.DataFrame({'dates': npdates, 'str': date_strings_tz, 'orig': x, 'using_tzset': y})
Это указывает на то, что оригинальный метод, orig
, не в состоянии восстановить первоначальную дату 172 раз:
print((df['dates'] != df['orig']).sum())
172
пока using_tzset
терпит неудачу в 11 раз:
print((df['dates'] != df['using_tzset']).sum())
11
Обратите внимание, однако, что 11 раз, что using_tzset
терпит неудачу, объясняются двусмысленностью локальных дат из-за DST.
Это показывает некоторые несоответствия:
mask = df['dates'] != df['using_tzset']
idx = np.where(mask.shift(1) | mask)[0]
print(df[['dates', 'str', 'using_tzset']].iloc[idx]).head(6)
# dates str using_tzset
# 7248 2000-10-29 08:00:00 2000-10-29T01:00:00-07:00 2000-10-29 08:00:00
# 7249 2000-10-29 09:00:00 2000-10-29T01:00:00-08:00 2000-10-29 08:00:00
# 15984 2001-10-28 08:00:00 2001-10-28T01:00:00-07:00 2001-10-28 08:00:00
# 15985 2001-10-28 09:00:00 2001-10-28T01:00:00-08:00 2001-10-28 08:00:00
# 24720 2002-10-27 08:00:00 2002-10-27T01:00:00-07:00 2002-10-27 08:00:00
# 24721 2002-10-27 09:00:00 2002-10-27T01:00:00-08:00 2002-10-27 08:00:00
Как вы можете увидеть несоответствия возникают, когда дата строка в столбце str
становится неоднозначной, когда смещение удаляются.
Вот timeit тест сравнения orig
и using_tzset
:
In [95]: %timeit orig(date_strings, tz)
1 loops, best of 3: 5.43 s per loop
In [96]: %timeit using_tzset(date_strings, tz)
10 loops, best of 3: 41.7 ms per loop
Так using_tzset
закончилась 100x быстрее, чем orig
при N = 10 ** 5.
Если производительность является проблемой, вы должны делать это миллионы раз, не так ли? Является ли смещение одинаковым каждый раз? Если это так, возможно, просто используйте 'numpy.datetime64 (s)' для всех из них, а затем используйте numpy-арифметику, чтобы сдвинуть все их на одну и ту же величину смещения за один падающий удар. – unutbu
@unutbu: К сожалению, смещение не обязательно одно и то же: некоторые из дат во время периодов летнего времени, а некоторые из них - нет. Кроме того, похоже, что даже вычисление DST-корректировки за время-времени было бы подвержено ошибкам? –
Я не уверен. Я не нашел более быстрый способ. Но в любом случае будьте осторожны: 'np.datetime64 (pd.Timestamp (s, tz = 'US/Pacific'))' может не дать желаемого результата. Рассмотрим строку даты и времени ISO 8601 ''2000-04-02T03: 00: 00-07: 00''. Без часовой пояс у вас будет 's = '2000-04-02T03: 00: 00''. Но 'np.datetime64 (pd.Timestamp (s, tz = 'US/Pacific'))' возвращает 'numpy.datetime64 ('2000-04-02T04: 00: 00.000000-0700')', поэтому это не round- правильное срабатывание. – unutbu