【问题标题】:Pandas create date range at certain dates熊猫在特定日期创建日期范围
【发布时间】:2018-07-13 01:26:19
【问题描述】:

我想每月创建一个给定日期数量的列表(或数组或其他)。

基本上我想要的是这个

>>>some_function(start_date=date(2005, 5, 14), periods=4, freq='M')
['2005-05-14', '2005-06-14', '2005-07-14', '2005-08-14']

如果开始月份的日期接近月底,我想要这个

>>>some_function(start_date=date(2007, 12, 31), periods=4, freq='M')
['2007-12-31', '2008-01-31', '2008-02-29', '2008-03-31']

我知道 pandas date_range 函数,但是它会产生这个

pd.date_range(date(2005, 5, 14), periods=4, freq='M')
Out[1]: DatetimeIndex(['2005-05-31', '2005-06-30', '2005-07-31', '2005-08-31'],
          dtype='datetime64[ns]', freq='M')

即它将月末设置为一天。这不是我想要的。

显然,这可能会在周期数上迭代生成,但是当 startmonth 的日期接近该月的最后一天时,这会产生麻烦。

有人知道产生这个的函数还是上面概述的方法是唯一的方法?

【问题讨论】:

  • 那么,您希望得到什么:your_function(date(2004, 1, 31), period=4, freq='M')
  • 嗨,我希望像 [date(2004, 1, 31), date(2004, 2, 29), date(2004, 3, 31), date(2004, 4, 30) )],如问题中所述
  • hmm,所以当您添加一个月时,这会将您带到下个月的同一天(或该月的最后一天)。对吗?
  • 是的,如果可能的话。如果不可能,则需要在月底。

标签: python pandas datetime


【解决方案1】:

我制作了以下内容:

from datetime import datetime, date
from datetime import timedelta

def next_month_generator(d):
   while True:
       if d.month == 12:
           # on Dec, need to change year
           d = d.replace(year=d.year+1, month=1)
       else:
           try:
               # get next month, same date
               d = d.replace(month=d.month+1)
           except ValueError:
               # get next month, last months date
               d = date(year=d.year, month=d.month+2, day=1) - timedelta(days=1)
       yield d

start_date=date(2017, 1, 31)
nm = next_month_generator(start_date)
for _ in range(13):
   print(nm.next())

 >> 2017-02-28
 >> 2017-03-28
 >> 2017-04-28
 >> 2017-05-28
 >> 2017-06-28
 >> 2017-07-28
 >> 2017-08-28
 >> 2017-09-28
 >> 2017-10-28
 >> 2017-11-28
 >> 2017-12-28
 >> 2018-01-28
 >> 2018-02-28

如果是 Python 3,请使用:

for _ in range(13):
   print(next(nm))

【讨论】:

  • 赞成。生成器表达式非常适合可生成的集合。
  • 嗨。谢谢。另一个不错的紧凑型解决方案。似乎没有内置函数,也没有办法绕过自定义函数。 +1
  • 是的,我不喜欢的是在我们到达第一个闰年 2 月之后,我们只是在 1-12 范围内迭代几个月。
  • 是的......这不是最佳选择。我想应该以某种方式存储这一天,而不是从以前的答案中获取
【解决方案2】:

我认为您所追求的行为是,您想要一个日期范围,其中所有日期都与您的开始日期在一个月的同一天,除了在月份的最后一天使用天数较少的月份这个月。

您可以通过使用pandas.DateOffset(months=1, day=day_of_month) 作为freq 参数来做到这一点,其中day_of_month 是您希望每个日期所在的月份中的哪一天。对于最后一天小于day_of_month 的月份,这将自动使用该月的最后一天。

In [68]: pandas.date_range('2005-05-14', periods=4, freq=pandas.DateOffset(months=1, day=14))
Out[68]: DatetimeIndex(['2005-05-14', '2005-06-14', '2005-07-14', '2005-08-14'], dtype='datetime64[ns]', freq='<DateOffset: day=14, months=1>')

In [69]: pandas.date_range('2007-12-31', periods=4, freq=pandas.DateOffset(months=1, day=31))
Out[69]: DatetimeIndex(['2007-12-31', '2008-01-31', '2008-02-29', '2008-03-31'], dtype='datetime64[ns]', freq='<DateOffset: day=31, months=1>')

【讨论】:

  • 是的。这就是我想要的。无需自定义功能。谢谢。
【解决方案3】:

这应该可以。 add_months 函数是通过How to increment datetime by custom months in python without using library 中的@DaveWebb 实现的。

import datetime
import calendar

start_date = '2018-02-02'

def add_months(sourcedate, months):
    month = sourcedate.month - 1 + months
    year = sourcedate.year + month // 12
    month = month % 12 + 1
    day = min(sourcedate.day, calendar.monthrange(year, month)[1])
    return datetime.date(year, month, day)

def range_of_months(sourcedate, months):
    return [add_months(sourcedate, m) for m in range(months+1)]

start = datetime.date.today()

range_of_months(start, 5)

# [datetime.date(2018, 2, 2),
#  datetime.date(2018, 3, 2),
#  datetime.date(2018, 4, 2),
#  datetime.date(2018, 5, 2),
#  datetime.date(2018, 6, 2),
#  datetime.date(2018, 7, 2)]

【讨论】:

  • 嗨,谢谢。这基本上是在编写一个自定义函数。我承认这是一个非常紧凑和不错的功能:) +1
猜你喜欢
  • 2021-06-30
  • 1970-01-01
  • 2020-12-23
  • 1970-01-01
  • 2016-10-05
  • 1970-01-01
  • 2019-09-04
  • 1970-01-01
  • 2019-07-07
相关资源
最近更新 更多