Python:获得范围内的所有月份?

时间:2016-02-26 11:42:05

标签: python datetime

我想从现在到2010年8月之间获得所有月份,格式如下:

['2010-08-01', '2010-09-01', .... , '2016-02-01']

现在这就是我所拥有的:

months = []
for y in range(2010, 2016):
    for m in range(1, 13):
        if (y == 2010) and m < 8:
            continue
        if (y == 2016) and m > 2:
            continue
        month = '%s-%s-01' % (y, ('0%s' % (m)) if m < 10 else m)
        months.append(month)

最好的办法是什么?

9 个答案:

答案 0 :(得分:18)

dateutil.relativedelta在这里很方便。

我已将格式化作为练习。

from dateutil.relativedelta import relativedelta
import datetime

result = []

today = datetime.date.today()
current = datetime.date(2010, 8, 1)    

while current <= today:
    result.append(current)
    current += relativedelta(months=1)

答案 1 :(得分:6)

使用datetimetimedelta标准Python模块 - 无需安装任何新库

from datetime import datetime, timedelta

now = datetime(datetime.now().year, datetime.now().month, 1)
ctr = datetime(2010, 8, 1)
list = [ctr.strftime('%Y-%m-%d')]

while ctr <= now:
    ctr += timedelta(days=32)
    list.append( datetime(ctr.year, ctr.month, 1).strftime('%Y-%m-%d') )

我每天都会添加32天进入新月(最长月份有31天)

答案 2 :(得分:5)

我查看了dateutil文档。事实证明它提供了比使用dateutil.relativedelta更方便的方式:recurrence rulesexamples

对于手头的任务,它就像

一样简单
from dateutil.rrule import *
from datetime import date

months = map(
    date.isoformat,
    rrule(MONTHLY, dtstart=date(2010, 8, 1), until=date.today())
)

小字

请注意,我们在此处作弊。如上所述,即使我们传递dateutil.rrule.rrule类型datetime.datetimedtstartuntil生成的元素也属于datetime.date类型。我让map将它们提供给date的{​​{1}}函数,结果只是将它们转换为字符串,就像它只是没有任何时间信息的日期一样

因此,看似等效的列表理解

isoformat

会返回一个类似

的列表
[day.isoformat()
    for day in rrule(MONTHLY, dtstart=date(2010, 8, 1), until=date.today())]

因此,如果我们想要使用列表推导而不是['2010-08-01T00:00:00', '2010-09-01T00:00:00', '2010-10-01T00:00:00', '2010-11-01T00:00:00', ⋮ '2015-12-01T00:00:00', '2016-01-01T00:00:00', '2016-02-01T00:00:00'] ,我们必须做类似的事情

map

答案 3 :(得分:0)

你可以将if语句的数量减少到两行而不是四行,因为第二个if语句与前一个if语句做同样的事情是有点多余的

if (y == 2010 and m < 8) or (y == 2016 and m > 2):
    continue

答案 4 :(得分:0)

我不知道它是否更好,但是像下面这样的方法可能会被认为更多&#39; pythonic&#39;:

months = [
    '{}-{:0>2}-01'.format(year, month)
        for year in xrange(2010, 2016 + 1)
        for month in xrange(1, 12 + 1)
        if not (year <= 2010 and month < 8 or year >= 2016 and month > 2)
]

这里的主要区别是:

  • 由于我们希望迭代生成列表,请使用list comprehension而不是聚合for循环中的列表元素。
  • 不要明确区分低于10且数字10及以上的数字,而是使用format specification mini-language.format() method of str功能来指定
  • xrange而不是range会返回一个生成器而不是一个列表,这样迭代值就可以在它们被消耗时生成,并且不必保留记忆。 (对于这么小的范围并不重要,但在Python 2中习惯这一点是个好主意。)注意:在Python 3中,没有{{1}并且xrange函数已经返回生成器而不是列表。
  • 明确显示上限的range。这使得代码的人类读者更容易识别我们要指定将上限视为独占的方法(+ 1range)的包含绑定。否则,他们可能想知道13号的交易是什么。

答案 5 :(得分:0)

我使用datetime,timedelta和calender的另一种方式:

from calendar import monthrange
from datetime import datetime, timedelta

def monthdelta(d1, d2):
    delta = 0
    while True:
        mdays = monthrange(d1.year, d1.month)[1]
        d1 += timedelta(days=mdays)
        if d1 <= d2:
            delta += 1
        else:
            break
    return delta

start_date = datetime(2016, 1, 1)
end_date = datetime(2016, 12, 1)

num_months = [i-12 if i>12 else i for i in range(start_date.month, monthdelta(start_date, end_date)+start_date.month+1)]
monthly_daterange = [datetime(start_date.year,i, start_date.day, start_date.hour) for i in num_months]

答案 6 :(得分:0)

另一种方法,不需要任何其他库,也不需要嵌套或while循环。只需将您的日期转换为从某个参考点开始的绝对月份数即可(实际上可以是任何日期,但是为简单起见,我们可以使用0001年1月1日)。例如

a=datetime.date(2010,2,5)
abs_months = a.year * 12 + a.month

一旦您有代表所在月份的数字,您就可以简单地使用range在月份中循环,然后转换回来:

广义问题的解决方案:

import datetime

def range_of_months(start_date, end_date):
    months = []
    for i in range(start_date.year * 12 + start_date.month, end_date.year*12+end_date.month + 1)
        months.append(datetime.date((i-13) // 12 + 1, (i-1) % 12 + 1, 1))
    return months

其他说明/说明:

此处//将四舍五入为最接近的整数,而% 12将除以12的余数,例如13 % 121

(还请注意,上面的date.year *12 + date.month中没有给出自0001年1月1日以来的月数。例如,如果date = datetime.datetime(1,1,1),则date.year * 12 + date.month给出了13如果我想计算实际的月份数,则需要从年份和月份中减去1,但这只会使计算变得更加复杂,最重要的是,我们有一种一致的方法来转换整数表示我们所在的月份。)

答案 7 :(得分:0)

似乎有一种非常简单,干净的方法,可以生成日期列表,并将子集设置为仅占每个月的第一天,如下例所示。

import datetime
import pandas as pd

start_date = datetime.date(2010,8,1)
end_date = datetime.date(2016,2,1)

date_range = pd.date_range(start_date, end_date)
date_range = date_range[date_range.day==1]

print(date_range)

答案 8 :(得分:0)

我新鲜的pythonic单线纸

from dateutil.relativedelta import relativedelta
import datetime

[(start_date + relativedelta(months=+m)).isoformat() for m in range(0,relativedelta(start_date,end_date).months+1)]