在非本地时区中快速解析Python日期时间,以节省夏令时

我需要快速将ISO 8601日期时间字符串(该字符串中没有时区,但已知在美国/太平洋时区中)转换为一个numpy datetime64对象.

如果我的计算机在美国/太平洋时间,则可以简单地运行numpy.datetime64(s).但是,这假定没有时区的字符串在本地时区中.此外,我不能轻易以ISO 8601格式指定美国/太平洋时区,因为根据夏令时,有时是-0800,有时是-0700.

到目前为止,我拥有的最快解决方案是numpy.datetime64(pandas.Timestamp(s).tz_localize(tz =’US / Pacific’,ambiguous = True)).这在我的机器上需要70µs.如果可以使此速度至少快一个数量级(本地时间的numpy.datetime64(s)需要4 µs,但如上所述是错误的),那将是很好的.这可能吗?

解决方法:

首先请注意,没有偏移量的某些本地时间及其日期时间
字符串不明确.例如,ISO 8601日期时间字符串

2000-10-29T01:00:00-07:00
2000-10-29T01:00:00-08:00

删除偏移量后,两者都映射到相同的字符串2000-10-29T01:00:00.

因此,不一定总是可以重新构造唯一的时区感知
来自没有偏移量的日期时间字符串的datetime.

但是,我们可以在这些模棱两可的地方做出选择
情况,并接受并非所有不确定的日期都将正确转换.

如果使用的是Unix,则可以使用time.tzset更改进程的本地时区:

import os
import time
os.environ['TZ'] = tz
time.tzset()

然后,您可以使用以下命令将datetime字符串转换为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  

但是请注意,using_tzset失败的11次是由于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列中的日期字符串
偏移消除后变得模糊.

因此using_tzset似乎可以在不明确的日期时间产生正确的结果.

这是比较orig和using_tzset的timeit基准:

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

因此,当N = 10 ** 5时,using_tzset比orig快100倍以上.

上一篇:python-Numpy规范化代码异常缓慢


下一篇:java-解决滑动拼图难题时的A *算法执行时间很长