Python 使用timedelta向datetime64添加一个月

Python 使用timedelta向datetime64添加一个月,python,pandas,numpy,timedelta,Python,Pandas,Numpy,Timedelta,当我尝试这个: >>> a = numpy.datetime64('1995-12-31') >>> b = a + pandas.Timedelta(1, unit='M') >>> print(b) 我希望看到 1996-01-31 但是我得到了 1996-01-30 10:29:06. 知道为什么吗?非常感谢 一个月的时间差是一年的长度除以12 您需要检查日期并添加适当的天数。 或者,增加月数(如果需要,滚动到下一年),并保持日数

当我尝试这个:

>>> a = numpy.datetime64('1995-12-31')
>>> b = a + pandas.Timedelta(1, unit='M')
>>> print(b)
我希望看到

1996-01-31
但是我得到了

1996-01-30 10:29:06.

知道为什么吗?非常感谢

一个月的时间差是一年的长度除以12

您需要检查日期并添加适当的天数。
或者,增加月数(如果需要,滚动到下一年),并保持日数不变。

您可以替换
部分以模拟要求

import numpy as np
import pandas as pd
a = np.datetime64('1995-12-31')
b = a + pd.Timedelta(1, unit='M')
print(b.replace(day=pd.to_datetime(a).day))

如果您只对日期部分感兴趣,请使用
.date()
将“月”添加到时间中存在固有的模糊性,因为月的长度不同

确定日期:

In [247]: a = np.array('1995-12-31','datetime64[D]')                            
In [248]: a                                                                     
Out[248]: array('1995-12-31', dtype='datetime64[D]')
再加上几天就行了:

In [249]: a + np.array(31, 'timedelta64[D]')                                    
Out[249]: numpy.datetime64('1996-01-31')
添加月份会引发错误:

In [250]: a + np.array(1, 'timedelta64[M]')                                     
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-250-a331f724d7e7> in <module>
----> 1 a + np.array(1, 'timedelta64[M]')

TypeError: Cannot get a common metadata divisor for NumPy datetime metadata [D] and [M] because they have incompatible nonlinear base time units
在相应的
datetime
对象中更改月份可能是处理此问题最干净的方法:

In [254]: b = a.item()                                                          
In [255]: b                                                                     
Out[255]: datetime.date(1995, 12, 31)

我对
datetime
对象的处理不够,无法在不查看其文档的情况下进行更改。

如果可能,添加一个月而不更改日期的简明方法是将月份截断,添加1,然后读取截断的内容:

>>> a = np.datetime64('1995-12-31')                                                              
>>> am = a.astype('M8[M]')                                                    
>>> b = (am + 1) + (a - am)                                                        
>>> b                                                                                            
numpy.datetime64('1996-01-31')                                                                   
显然,如果下个月不存在原始日期,则这不起作用:

>>> a = np.datetime64('1995-01-31')
>>> am = a.astype('M8[M]')
>>> b = (am + 1) + (a - am)
>>> b
numpy.datetime64('1995-03-03')
但无论如何,在这种情况下,答案应该是什么还不清楚

一种可能是在该月的最后一天达到最大值:

>>> b = np.minimum((am + 1) + (a - am), (am + 2) - np.timedelta64(1, 'D'))
>>> b
numpy.datetime64('1995-02-28')

正如@hpaulj在他的回答中已经提到的:


在时间中添加“月”是一种固有的模糊性,因为月的长度不同

此外,在版本
0.25.0
用于
Timedelta
功能中的单位
M
(月)和
Y
(年)

但正如官方手册中所述,您应该使用时间增量表示绝对时间持续时间,使用日期偏移量表示日历算法方面的相对时间持续时间,这正是我们在您的情况下需要的:

基本的日期偏移量的作用类似于
dateutil.relativedelta
(),它将日期时间移动指定的相应日历持续时间

因此,以你的例子:

In [7]: a = numpy.datetime64('1995-12-31')
      : b = pandas.Timestamp(a) + pandas.DateOffset(months=1)
      : b
Out[7]: Timestamp('1996-01-31 00:00:00')
注:如果您需要将熊猫时间戳转换为数,您可以使用
转换为数的方法。datetime64
“一个月的时间增量是一年的长度除以12。”这似乎是
熊猫的思维方式(但不是
numpy
)。
In [7]: a = numpy.datetime64('1995-12-31')
      : b = pandas.Timestamp(a) + pandas.DateOffset(months=1)
      : b
Out[7]: Timestamp('1996-01-31 00:00:00')