Python: get all months in range?

后端 未结 9 1176
天涯浪人
天涯浪人 2020-12-15 18:00

I want to get all months between now and August 2010, as a list formatted like this:

[\'2010-08-01\', \'2010-09-01\', .... , \'2016-02-01\']
<
相关标签:
9条回答
  • 2020-12-15 18:40

    I don't know whether it's better, but an approach like the following might be considered more 'pythonic':

    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)
    ]
    

    The main differences here are:

    • As we want the iteration(s) to produce a list, use a list comprehension instead of aggregating list elements in a for loop.
    • Instead of explicitly making a distinction between numbers below 10 and numbers 10 and above, use the capabilities of the format specification mini-language for the .format() method of str to specify
      • a field width (the 2 in the {:0>2} place holder)
      • right-alignment within the field (the > in the {:0>2} place holder)
      • zero-padding (the 0 in the {:0>2} place holder)
    • xrange instead of range returns a generator instead of a list, so that the iteration values can be produced as they're being consumed and don't have to be held in memory. (Doesn't matter for ranges this small, but it's a good idea to get used to this in Python 2.) Note: In Python 3, there is no xrange and the range function already returns a generator instead of a list.
    • Make the + 1 for the upper bounds explicit. This makes it easier for human readers of the code to recognize that we want to specify an inclusive bound to a method (range or xrange) that treats the upper bound as exclusive. Otherwise, they might wonder what's the deal with the number 13.
    0 讨论(0)
  • 2020-12-15 18:43

    A different approach that doesn't require any additional libraries, nor nested or while loops. Simply convert your dates into an absolute number of months from some reference point (it can be any date really, but for simplicity we can use 1st January 0001). For example

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

    Once you have a number representing the month you are in you can simply use range to loop over the months, and then convert back:

    Solution to the generalized problem:

    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
    

    Additional Notes/explanation:

    Here // divides rounding down to the nearest whole number, and % 12 gives the remainder when divided by 12, e.g. 13 % 12 is 1.

    (Note also that in the above date.year *12 + date.month does not give the number of months since the 1st of January 0001. For example if date = datetime.datetime(1,1,1), then date.year * 12 + date.month gives 13. If I wanted to do the actual number of months I would need to subtract 1 from the year and month, but that would just make the calculations more complicated. All that matters is that we have a consistent way to convert to and from some integer representation of what month we are in.)

    0 讨论(0)
  • 2020-12-15 18:44

    use datetime and timedelta standard Python's modules - without installing any new libraries

    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') )
    

    I'm adding 32 days to enter new month every time (longest months has 31 days)

    0 讨论(0)
提交回复
热议问题