1

我正在尝试将一个月添加到 np.datetime64:

np.datetime64('2020-01-05') + np.timedelta64(1, "M")

但此错误引发:

Cannot cast ufunc 'subtract' input 1 from dtype('<m8[M]') to dtype('<m8[us]') with casting rule 'same_kind'

如果我尝试几天或几周,它会起作用:

np.datetime64('2020-01-05') + np.timedelta64(1, "D")
numpy.datetime64('2020-01-06')

我从 numpy 文档中读到添加日期和月份是不同的(https://numpy.org/doc/stable/reference/arrays.datetime.html#datetime-and-timedelta-arithmetic),但他们没有给出解决方案.

注意:我试图不使用 pandas 或 datetime,所以我想避免任何强制转换

4

1 回答 1

1

下面的代码有效,但我不确定它是如何证明未来的。我怀疑从长远来看,转换为 datetime 或使用 pandas 可能会更容易、更健壮。

提取月份来自Anon's answer to getting year and month

正如@pawan-jain 所说,从日期中定义添加或减去月份存在问题。什么是 2021-05-31 加一个月?2021-06-31 不是日期。

下面的代码映射

2020-01-31 to 2020-03-02    Adds 31 days to a January date
2020-02-01 to 2020-03-01    Adds 29 days to a February 2020 date

检查这是否符合所需的添加月份的定义。

import numpy as np

DAYS_IN_MONTH = np.array( [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ])
FEB = 1

def is_leap( yy ):
    """ Returns boolean True for leap_years. """
    accum = np.logical_and( ( yy % 4 == 0 ), ( yy % 100 != 0 )) # century starts aren't leap 
    return ( accum | (( yy % 400 ) == 0 ))   # except every 400 years 
        
def plus_day( yy, mm ):
    """ Returns one for Februaries in leap years. 
        yy is an array of years as ints
        mm is an array of months as ints, zero based, Jan = 0, Feb = 1 ..
    """
    return ( mm == FEB ) * is_leap( yy ).astype( np.int8 )

def days_in_month( dates ):
    """ Returns the days in the month for the np.datetime64 array dates."""
    month = dates.astype('datetime64[M]').astype(int)
    year, month = np.divmod( month, 12 )  # Month zero based, Jan = 0... 
    year += 1970 
    return DAYS_IN_MONTH[ month ] + plus_day( year, month )

dates = np.arange(np.datetime64('2020-01-01'), np.datetime64('2021-01-01'))

new_dates = dates + days_in_month( dates )

for date, ndate in zip( dates[ 20: 80 ], new_dates[ 20: 80 ]):
    print( date, ndate, end = ' : ' )

# 2020-01-21 2020-02-21 : 2020-01-22 2020-02-22 : 2020-01-23 2020-02-23 : 
# 2020-01-24 2020-02-24 : 2020-01-25 2020-02-25 : 2020-01-26 2020-02-26 : 
# 2020-01-27 2020-02-27 : 2020-01-28 2020-02-28 : 2020-01-29 2020-02-29 : 
# 2020-01-30 2020-03-01 : 2020-01-31 2020-03-02 : 2020-02-01 2020-03-01 : 
# 2020-02-02 2020-03-02 : 2020-02-03 2020-03-03 : 2020-02-04 2020-03-04 : 
# 2020-02-05 2020-03-05 : 2020-02-06 2020-03-06 : 2020-02-07 2020-03-07 : 
# 2020-02-08 2020-03-08 : 2020-02-09 2020-03-09 : 2020-02-10 2020-03-10 : 
# 2020-02-11 2020-03-11 : 2020-02-12 2020-03-12 : 2020-02-13 2020-03-13 : 
# 2020-02-14 2020-03-14 : 2020-02-15 2020-03-15 : 2020-02-16 2020-03-16 : 
# 2020-02-17 2020-03-17 : 2020-02-18 2020-03-18 : 2020-02-19 2020-03-19 :
# 2020-02-20 2020-03-20 : 2020-02-21 2020-03-21 : 2020-02-22 2020-03-22 : 
# 2020-02-23 2020-03-23 : 2020-02-24 2020-03-24 : 2020-02-25 2020-03-25 : 
# 2020-02-26 2020-03-26 : 2020-02-27 2020-03-27 : 2020-02-28 2020-03-28 : 
# 2020-02-29 2020-03-29 : 2020-03-01 2020-04-01 : 2020-03-02 2020-04-02 : 
# 2020-03-03 2020-04-03 : 2020-03-04 2020-04-04 : 2020-03-05 2020-04-05 : 
# 2020-03-06 2020-04-06 : 2020-03-07 2020-04-07 : 2020-03-08 2020-04-08 : 
# 2020-03-09 2020-04-09 : 2020-03-10 2020-04-10 : 2020-03-11 2020-04-11 : 
# 2020-03-12 2020-04-12 : 2020-03-13 2020-04-13 : 2020-03-14 2020-04-14 : 
# 2020-03-15 2020-04-15 : 2020-03-16 2020-04-16 : 2020-03-17 2020-04-17 : 
# 2020-03-18 2020-04-18 : 2020-03-19 2020-04-19 : 2020-03-20 2020-04-20 :   
于 2021-05-18T21:08:08.067 回答