时间戳减法必须具有相同的时区或没有时区,但它们都是 UTC

Posted

技术标签:

【中文标题】时间戳减法必须具有相同的时区或没有时区,但它们都是 UTC【英文标题】:Timestamp subtraction must have the same timezones or no timezones but they are both UTC 【发布时间】:2020-06-29 08:55:10 【问题描述】:

有一些问题解决了相同的错误TypeError: Timestamp subtraction must have the same timezones or no timezones,但没有一个问题与这个问题相同。

我有 2 个 UTC 时间戳在减去时会引发该错误。

print(date, type(date), date.tzinfo)
>>> 2020-07-17 00:00:00+00:00 <class 'pandas._libs.tslibs.timestamps.Timestamp'> UTC
print(date2, type(date2), date2.tzinfo)
>>> 2020-04-06 00:00:00.000000001+00:00 <class 'pandas._libs.tslibs.timestamps.Timestamp'> UTC
date - date2
>>> TypeError: Timestamp subtraction must have the same timezones or no timezones

编辑:我正在使用 Python 3.6.9Pandas 1.0.1

【问题讨论】:

print(pd.to_datetime('2020-07-17 00:00:00+00:00') - pd.to_datetime('2020-04-06 00:00:00.000000001+00:00')) 给了我Timedelta('101 days 23:59:59.999999')。也许仔细检查? 不知何故它对我不起作用,请注意 date & date2 是 pandas._libs.tslibs.timestamps.Timestamp 类型 对我来说也一样。您使用的是哪个 Pandas 版本? @JoshFriedlander Python 3.6.9 和 Pandas 1.0.1 我的日期包含可能是相关信息的纳秒 【参考方案1】:

如果时间戳是“tz-naive”,您可以在时间戳上使用 tz_localize(),在具有时区的日期时间上使用 tz_convert 以均衡它们的时区,然后进行减法运算:


import pytz

[date_without_tz].tz_localize(tz=pytz.UTC) - [date_with_tz].tz_convert(tz=pytz.UTC)

【讨论】:

【参考方案2】:

有同样的问题。如果您使用 pandas read_csv 读取数据,它使用 &lt;class 'pytz.UTC'&gt;。所以我的解决方案是在任何地方都使用相同的类。

示例代码生成错误

from datetime import datetime, timedelta, timezone
import pandas as pd

now = datetime.now(tz=timezone.utc)
some_time_ago = now - timedelta(7)

print('Timezone info before reading_csv')
print(some_time_ago.tzinfo, type(some_time_ago.tzinfo))

time_passed = now - some_time_ago
print (time_passed)

df = pd.DataFrame([some_time_ago], columns=['date'])
df.to_csv('dates.csv', index=False)

df2 = pd.read_csv('dates.csv', parse_dates=['date'])
print('\nTimezone info after reading_csv')
print(df2.iloc[0,0].tzinfo, type(df2.iloc[0,0].tzinfo))

now = datetime.now(tz=timezone.utc)
some_time_ago = now - df2.iloc[0,0]
print(some_time_ago)
Timezone info before reading_csv
UTC <class 'datetime.timezone'>
7 days, 0:00:00

Timezone info after reading_csv
UTC <class 'pytz.UTC'>
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-23-b2815e32e8b7> in <module>
     19 
     20 now = datetime.now(tz=timezone.utc)
---> 21 some_time_ago = now - df2.iloc[0,0]
     22 print(some_time_ago)

pandas/_libs/tslibs/c_timestamp.pyx in pandas._libs.tslibs.c_timestamp._Timestamp.__sub__()

TypeError: Timestamp subtraction must have the same timezones or no timezones

pytz 的正确代码

import pytz
from datetime import datetime, timedelta
import pandas as pd

now = datetime.now(tz=pytz.UTC)
some_time_ago = now - timedelta(7)

print('Timezone info before reading_csv')
print(some_time_ago.tzinfo, type(some_time_ago.tzinfo))

time_passed = now - some_time_ago
print (time_passed)

df = pd.DataFrame([some_time_ago], columns=['date'])
df.to_csv('dates.csv', index=False)

df2 = pd.read_csv('dates.csv', parse_dates=['date'])
print('\nTimezone info after reading_csv')
print(df2.iloc[0,0].tzinfo, type(df2.iloc[0,0].tzinfo))

now = datetime.now(tz=pytz.UTC)
some_time_ago = now - df2.iloc[0,0]
print(some_time_ago)
Timezone info before reading_csv
UTC <class 'pytz.UTC'>
7 days, 0:00:00

Timezone info after reading_csv
UTC <class 'pytz.UTC'>
7 days 00:00:00.024021

【讨论】:

【参考方案3】:

在检查时区类型后:type(date.tzinfo) 给出 &lt;class 'datetime.timezone'&gt;type(date2.tzinfo) 给出 &lt;class 'pytz.UTC'&gt; 因此,根据 pandas 源代码,即使它们都是 UTC,它们也不被认为是相等的。

所以解决方案是让它们具有相同的 tzinfo 类型(pytzdatitme.timezone

这是 Github 中的一个未解决问题:https://github.com/pandas-dev/pandas/issues/32619

【讨论】:

以上是关于时间戳减法必须具有相同的时区或没有时区,但它们都是 UTC的主要内容,如果未能解决你的问题,请参考以下文章

时区、时间戳、 时区、格林威治(GMT)、协调世界时(UTC)的关系

Firebase 导出到 BigQuery 事件时间戳时区

Postgres 通过时区转换防止时间戳

具有相同时区但不同 utcoffset() 的日期时间对象

Debezium 时间戳问题,无法转换为本地时区

错误:列 <名称> 的类型是没有时区的时间戳,但表达式的类型是字符变化