【问题标题】:Why are python dates such a mess and what can I do about it?为什么 python 日期如此混乱,我该怎么办?
【发布时间】:2022-11-25 13:55:10
【问题描述】:

我的 Python 代码库中常见的错误来源是日期。

具体来说,日期和日期时间的不同实现,以及如何处理它们之间的比较。

这些是我的代码库中的日期类型

import datetime
import pandas as pd 
import polars as pl 

x1 = pd.to_datetime('2020-10-01')
x2 = datetime.datetime(2020, 10,1)
x3 = pl.DataFrame({'i':[x2]}).select(pl.col('i').cast(pl.Date)).to_numpy()[0,0]
x4 = pl.DataFrame({'i':[x2]}).select(pl.col('i').cast(pl.Datetime)).to_numpy()[0,0]
x5 = pendulum.parse('2020-10-01')
x6 = x5.date()
x7 = x1.date()

您可以打印它们以查看:

x1=2020-10-01 00:00:00           , type(x1)=<class 'pandas._libs.tslibs.timestamps.Timestamp'>
x2=2020-10-01 00:00:00           , type(x2)=<class 'datetime.datetime'>
x3=2020-10-01                    , type(x3)=<class 'numpy.datetime64'>
x4=2020-10-01T00:00:00.000000    , type(x4)=<class 'numpy.datetime64'>
x5=2020-10-01T00:00:00+00:00     , type(x5)=<class 'pendulum.datetime.DateTime'>
x6=2020-10-01                    , type(x6)=<class 'pendulum.date.Date'>
x7=2020-10-01                    , type(x7)=<class 'datetime.date'>

Python 中是否有规范的日期表示?我想 x7: datetime.date 可能是最接近的......

此外,注意比较是一场噩梦,请参阅此处的表格,尝试执行 xi == xj

x1 x2 x3 x4 x5 x6 x7
x1: <class 'pandas._libs.tslibs.timestamps.Timestamp'> True True ERROR: Only resolutions 's', 'ms', 'us', 'ns' are supported. True False True True
x2: <class 'datetime.datetime'> True True False True False False False
x3: <class 'numpy.datetime64'> True False True True False True True
x4: <class 'numpy.datetime64'> True True True True False False False
x5: <class 'pendulum.datetime.DateTime'> False False False False True False False
x6: <class 'pendulum.date.Date'> True True True False False True True
x7: <class 'datetime.date'> True False True False False True True

另请注意,它甚至不是对称的:

痛苦在于比较更加陌生。这里是 xi>=xj:

红色代表ERROR

正如您可以想象的那样,有越来越多的胶水代码来控制它。关于如何在 Python 中处理日期和日期时间类型有什么建议吗?

为简单起见:

  • 我从不需要时区数据,一切都应该始终是 UTC
  • 有时为了方便起见,日期会作为字符串传递(例如,从 JSON 解析)
  • 我最多需要几秒的分辨率,但我 99% 的工作只使用日期。

【问题讨论】:

  • 不要写胶水代码;编写一个将各种时间格式转换为规范形式的函数,并在需要比较两个值时始终调用它。更进一步,编写一个 cmp_time 函数,它接受两个时间值并为您完成。
  • 我尽可能使用datetime.datedatetime.datetime(即在非数字运算代码中); andpd.Timestamp/np.datetime64 我必须的地方(高性能数字代码)。
  • @金德尔;谢谢 - 这就是我所做的,但我必须在几乎所有地方添加这个“to_date”,此时它是我应用程序运行时间的 ~4%(我在大表上工作)。谢谢@Grisha,我将对 np.datetime64 进行基准测试,因为我通常使用数百万行表。
  • 我会接受将所有上述类型转换为 np.datetime64 的解决方案 :)

标签: python pandas numpy date datetime


【解决方案1】:

所有列出的类型都可以转换为 numpy datetime64。如果您不需要超过秒的分辨率,您可以将单位设置为“s”(可选)。前任:

# Python datetime.datetime
x2_np = np.datetime64(x2.replace(tzinfo=None), 's')
print(x2_np, repr(x2_np))
# 2020-10-01T00:00:00 numpy.datetime64('2020-10-01T00:00:00')

# Python datetime.date
x6_np = np.datetime64(x6, 's')
print(x6_np, repr(x6_np))
# 2020-10-01T00:00:00 numpy.datetime64('2020-10-01T00:00:00')

# pendulum datetime
x5_np = np.datetime64(x5.replace(tzinfo=None), 's')
print(x5_np, repr(x5_np))
# 2020-10-01T00:00:00 numpy.datetime64('2020-10-01T00:00:00')

# pd.Timestamp
x1_np = x1.to_numpy().astype('datetime64[s]')
print(x1_np, repr(x1_np))
# 2020-10-01T00:00:00 numpy.datetime64('2020-10-01T00:00:00')

由于 numpy 试图避开时区(默认为 UTC),因此请确保将 tzinfo 替换为 datetime.datetime 和 pendulum.datetime,如果它被设置在那里的话。

现在你可以把这一切放在一个转换器函数中,它本质上是一个大开关盒。然而,在大数据集上谨慎使用,大多数时候便利并不是免费的。前任:

def convert_dt_to_numpy(dt, unit='s'):
    if isinstance(dt, (datetime.datetime, pendulum.DateTime)):
        return np.datetime64(dt.replace(tzinfo=None), unit)
    if isinstance(dt, (datetime.date, pendulum.Date)):
        return np.datetime64(dt, unit)
    if isinstance(dt, pd.Timestamp):
        return dt.to_numpy().astype(f'datetime64[{unit}]')
    raise ValueError(f"conversion for '{dt}' of {type(dt)} unknown")
    
for dt in (x1, x2, x6, x5, 7):
    print(convert_dt_to_numpy(dt))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-11
    • 1970-01-01
    • 1970-01-01
    • 2021-04-27
    • 2020-10-15
    • 2018-12-21
    • 2011-04-28
    • 2015-06-09
    相关资源
    最近更新 更多