当前位置: 首页 > 知识库问答 >
问题:

快速解析非本地时区的Python datetime,根据夏令时进行调整

柳俊彦
2023-03-14

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

如果我的机器在美国/太平洋时间,我可以简单地运行numpy.datetime64。但是,这假定没有时区的字符串位于本地时区。此外,我无法轻松地以ISO 8601格式指定美国/太平洋时区,因为它有时是-0800,有时是-0700,具体取决于夏令时。

到目前为止,我使用的最快的解决方案是<code>numpy.datetime64(pandas.Timestamp)。tz_localize(tz='US/Pacific',模糊=True))。这在我的机器上需要70µs。如果我能把这个速度提高至少一个数量级就好了(numpy.datetime64(s)在本地时间需要4µs,但如上所述是不正确的)。这可能吗?

共有1个答案

余善
2023-03-14

首先请注意,如果没有偏移量,某些本地时间及其日期时间字符串是模棱两可的。例如,ISO 8601 日期时间字符串

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

当偏移被移除时,两者都映射到同一个字符串< code>2000-10-29T01:00:00。

因此,从不带偏移量的日期时间字符串中重建唯一的时区识别日期时间并不总是可能的。

但是,我们可以在这些模棱两可的情况下做出选择,并接受并非所有模棱两可的日期都会被正确转换。

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

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

然后,您可以使用

def using_tzset(date_strings, tz):
    os.environ['TZ'] = tz
    time.tzset()
    return np.array(date_strings, dtype='datetime64[ns]')

但是请注意,使用_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})

这表明原始方法< code>orig无法恢复原始日期172次:

print((df['dates'] != df['orig']).sum())
172

using_tzset失败了11次:

print((df['dates'] != df['using_tzset']).sum())
11  

但是,请注意,< code>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似乎在模棱两可的日期时间内产生正确的结果。

下面是一个timeit基准,比较了<code>orig<code>和<code>using_tzset<code>:

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_tzsetorig快100倍以上。

 类似资料:
  • 问题内容: 只是为了验证这一点:我有这种la脚和脑死法,可以计算当前位置的时区偏移量。我想知道是否在需要调整“夏令时”时需要进行调整(目前,我所在的位置为CET时区,所以是“冬季时间”,因此很难验证)。 感谢您的任何提示。 问题答案: 通常,Joda时间会自己照顾DST,因此您不必担心。但是,我注意到您正在传递给getOffset()。鉴于时区偏移量取决于日期,因此您确实应该传递计算偏移量的日期/

  • 我正在尝试查看从本地时间转换为 UTC 时间(反之亦然)的 WindAPI 是否准确,夏令时是否准确。例如,让我们以 LocalFileTimeToFileTime API 为例。其描述指出: LocalFileTimeToFileTime使用时区和夏令时的当前设置。因此,如果是夏令时,此功能将考虑夏令时,即使您转换的时间是标准时间。 所以我正在用这段代码测试它: 所以我错过了什么?

  • 问题内容: 有人可以帮我为什么下面的代码不起作用吗?我正在Xcode.1 Playground中对其进行测试 问题答案: 操场是沙盒,因此您将无法仅从用户文件夹中的任何位置抓取文件。以下是将该文件添加到游乐场以使其可访问的方法: 在Finder中找到您的“ .playground”文件 右键单击并选择“显示包装内容” 您应该看到“ timeline.xctimeline”,“ contents.x

  • 有些时区会切换到夏令时,有些不会。我知道俄罗斯不使用这个时间,而乌克兰使用夏令时。 正如我从这个链接中知道的.NET 时区信息来自奥尔森时区莫斯科使用俄罗斯标准时间,基辅(乌克兰)使用 FLE 标准时间。 我的测试是: > 冬季,俄罗斯,DateTimeKid. Utc 冬天,俄罗斯,日期时间。当地的 Summer,俄罗斯,DateTimeKind.Utc 夏天,俄罗斯,DateTimeKind。

  • 有没有一个时区,我可以使用,以考虑到夏令时?我知道'EDT'是指夏令时,而'EST'不是。是否有一个时区我可以使用,将自动检测日期时间是否是夏令时?“ET”或“America/New_York”能行吗? 编辑:: 抱歉应该更清楚。我想取一个日期并将其转换为东部时区,但我希望它考虑到东部时区的日期是否为夏令时。

  • 轻触方格启用设定,即可将夏令时反映于时间显示中。