得到(年,月)最后X个月

时间:2011-07-04 21:24:14

标签: python datetime

我在python中有一个非常简单的事情: 我需要从今天开始(包括)最后x个月的元组(year,month)列表。因此,对于x = 10和今天(2011年7月),命令应该输出:

[(2011, 7), (2011, 6), (2011, 5), (2011, 4), (2011, 3), 
(2011, 2), (2011, 1), (2010, 12), (2010, 11), (2010, 10)]

只应使用python的默认日期时间实现。我提出了以下解决方案:

import datetime
[(d.year, d.month) for d in [datetime.date.today()-datetime.timedelta(weeks=4*i) for i in range(0,10)]]

此解决方案为我的测试用例输出了正确的解决方案,但我对此解决方案感到不满:它假设一个月有四个星期,这根本不是真的。我可以将weeks=4替换为days=30,这会提供更好的解决方案,但仍然不正确。

我想到的另一个解决方案是使用简单的数学并从月份计数器中减去1,如果月份计数器为0,则从年份计数器中减去1。这个解决方案的问题是:它需要更多的代码,也不是很易读。

那么如何才能正确完成?

7 个答案:

答案 0 :(得分:16)

我没有在任何地方看到它,但time.mktime会在超出范围(包括负月值)的情况下“滚动”到正确的年份:

x = 10
now = time.localtime()
print [time.localtime(time.mktime((now.tm_year, now.tm_mon - n, 1, 0, 0, 0, 0, 0, 0)))[:2] for n in range(x)]

答案 1 :(得分:5)

最简单的方法是使用integer division//)和modulus%)函数,代表自第0年以来月份的月数:

months = year * 12 + month - 1 # Months since year 0 minus 1
tuples = [((months - i) // 12, (months - i) % 12 + 1) for i in range(10)]

- 1表达式中的months需要获得正确答案,我们稍后将模数函数的结果加1以得到1索引(即月数从1到12而不是比0到11)。

或者您可能想要创建一个生成器:

def year_month_tuples(year, month):
    months = year * 12 + month - 1 # -1 to reflect 1-indexing
    while True:
        yield (months // 12, months % 12 + 1) # +1 to reflect 1-indexing
        months -= 1 # next time we want the previous month

可以用作:

>>> tuples = year_month_tuples(2011, 7)
>>> [tuples.next() for i in range(10)]

答案 2 :(得分:4)

使用relativedelta ...

import datetime
from dateutil.relativedelta import relativedelta

def get_last_months(start_date, months):
    for i in range(months):
        yield (start_date.year,start_date.month)
        start_date += relativedelta(months = -1)

>>> X = 10       
>>> [i for i in get_last_months(datetime.datetime.today(), X)]
>>> [(2013, 2), (2013, 1), (2012, 12), (2012, 11), (2012, 10), (2012, 9), (2012, 8), (2012, 7), (2012, 6), (2012, 5)]

答案 3 :(得分:2)

如果您创建一个函数来执行日期数学运算,它几乎与原始实现一样好:

def next_month(this_year, this_month):
  if this_month == 0: 
    return (this_year - 1, 12)
  else:
    return (this_year, this_month - 1)

this_month = datetime.date.today().month()
this_year = datetime.date.today().year()
for m in range(0, 10):
  yield (this_year, this_month)
  this_year, this_month = next_month(this_year, this_month)

答案 4 :(得分:2)

更新:无论如何都要添加timedelta版本,因为它看起来更漂亮:)

def get_years_months(start_date, months):
    for i in range(months):
        yield (start_date.year, start_date.month)
        start_date -= datetime.timedelta(days=calendar.monthrange(start_date.year, start_date.month)[1])

您不需要使用timedelta,因为您只需要年份和月份,这是固定的。

def get_years_months(my_date, num_months):
    cur_month = my_date.month
    cur_year = my_date.year

    result = []
    for i in range(num_months):
        if cur_month == 0:
            cur_month = 12
            cur_year -= 1
        result.append((cur_year, cur_month))
        cur_month -= 1

    return result

if __name__ == "__main__":
    import datetime
    result = get_years_months(datetime.date.today(), 10)
    print result

答案 5 :(得分:0)

如果你想在没有日期时间库的情况下这样做,你可以转换为从0年开始的月份然后转换回来

start_year = 2014
start_month = 5
end_year = 2013
end_month = 7

print list = [(a/12,a % 12+1) for a in range(12*start_year+start_month-1,12*end_year+end_month-2,-1)]
  
    
      

[(2014,5),        (2014年,4年),        (2014,3),        (2014,2),        (2014,1),        (2013,12),        (2013,11),        (2013,10),        (2013,9),        (2013年,8年),        (2013,7)]

    
  

答案 6 :(得分:0)

或者您可以定义一个函数来获取上个月,然后打印月份( 这有点基本)

def last_month(year_month):#format YYYY-MM
    aux = year_month.split('-')
    m = int(aux[1])
    y = int(aux[0])

    if m-1 == 0:
        return str(y-1)+"-12"
    else:
        return str(y)+"-"+str(m-1)

def print_last_month(ran, year_month= str(datetime.datetime.today().year)+'-'+str(datetime.datetime.today().month)):
    i = 1 
    if ran != 10:
        print( last_month(year_month) )
        print_last_month(i+1, year_month= last_month(year_month))