创建具有任意开始日期的每月时间序列

Create monthly time series with arbitrary start dates

使用 pandas 可以轻松创建每月的日期系列。

import pandas as pd

pd.date_range('2012-04-23', '2013-01-23', freq='BM')

DatetimeIndex(['2012-04-30', '2012-05-31', '2012-06-29', '2012-07-31',
               '2012-08-31', '2012-09-28', '2012-10-31', '2012-11-30',
               '2012-12-31'],
              dtype='datetime64[ns]', freq='BM')

请注意 DatetimeIndex 中的日期是月底。我知道应该考虑我选择了 freq='BM',但我不相信我有一个可以实现我的目标的选择。

我经常需要从每个月的最后一个工作日开始及时回溯每月的一系列日期。

我想看这个:

DatetimeIndex(['2012-04-23', '2012-05-23', '2012-06-23', '2012-07-23',
               '2012-08-23', '2012-09-23', '2012-10-23', '2012-11-23',
               '2012-12-23'],
              dtype='datetime64[ns]', freq=None)

或另一个更复杂的示例可能是获取从“2012-01-30”到“2012-04-30”的月份。我希望看到:

DatetimeIndex(['2012-01-30', '2012-02-29', '2012-03-30', '2012-04-30'],
              dtype='datetime64[ns]', freq=None)

我不清楚你的问题,但相信这是朝着正确方向迈出的一步。

start = '2012-04-23'
end = '2013-01-23'

>>> pd.DatetimeIndex([pd.datetime(ts.year, ts.month, int(end.split("-")[-1])) 
                      for ts in pd.date_range(start, end, freq='BM')])

DatetimeIndex(['2012-04-23', '2012-05-23', '2012-06-23', '2012-07-23', '2012-08-23', '2012-09-23', '2012-10-23', '2012-11-23', '2012-12-23'], dtype='datetime64[ns]', freq=None)

虽然没有针对速度进行优化,但我相信以下函数会 return 根据您的要求提供正确的值。

def foo(date, periods, forward=True):
    if isinstance(date, str):
        date = pd.Timestamp(date).date()
    dates = [date + relativedelta(date, months=n * (1 if forward else -1)) for n in range(1, periods +1)]
    result = []
    print dates
    for date in dates:
        month = date.month
        iso_day = date.isoweekday()
        if iso_day == 6:
            date += dt.timedelta(days=2 if forward else -1)
        elif iso_day == 7:
            date += dt.timedelta(days=1 if forward else -2)
        if date.month != month:
            # Gone into next/preceding month.  Roll back/forward.
            date -= dt.timedelta(days=3 if forward else -3)
        result.append(date)
    return result

您可能正在寻找这样的东西:

from pandas.tseries.offsets import Day, BDay
pd.date_range(start = '2012-01-01', periods = 6, freq = 'MS') + Day(22) + BDay(0)
Out[12]: 
DatetimeIndex(['2012-01-23', '2012-02-23', '2012-03-23', '2012-04-23',
               '2012-05-23', '2012-06-25'],
              dtype='datetime64[ns]', freq=None)

Day(22) 添加 22 天的偏移量,BDay 负责工作日偏移量(BDay(0) 采用最近的工作日)。

日期从 30 日开始有点困难。所以我不得不为此编写一个函数。 (为了代码的清晰,它不允许自定义 freq 参数。)

def my_business_date_range(day, **kwargs):
    assert(isinstance(day, int) & (day > 0) & (day < 32))
    rng0 = pd.date_range(freq = 'MS', **kwargs)
    rng1 = rng0 + pd.tseries.offsets.Day(day-1) + pd.tseries.offsets.BDay(0)
    # Correcting overflows:
    overflow_idx, = np.nonzero(rng0.month != rng1.month)
    if overflow_idx.size > 0:
        # rng1 is not mutable
        tmp = rng1.tolist()        
        bme = pd.tseries.offsets.BusinessMonthEnd(-1)
        for i in overflow_idx:
            tmp[i] = bme(rng1[i])
        rng1 = pd.DatetimeIndex(tmp)
    return rng1

my_business_date_range(30, start= '2012-01-01', periods = 6)
Out[13]: 
DatetimeIndex(['2012-01-30', '2012-02-29', '2012-03-30', '2012-04-30',
               '2012-05-30', '2012-06-29'],
              dtype='datetime64[ns]', freq=None)

Pandas 也有一个实验性的 CustomBusinessMonth and the like 但我无法让它工作。