Iterating through a range of dates in Python

后端 未结 23 1354
醉酒成梦
醉酒成梦 2020-11-22 04:40

I have the following code to do this, but how can I do it better? Right now I think it\'s better than nested loops, but it starts to get Perl-one-linerish when you have a ge

相关标签:
23条回答
  • 2020-11-22 05:02

    Can't* believe this question has existed for 9 years without anyone suggesting a simple recursive function:

    from datetime import datetime, timedelta
    
    def walk_days(start_date, end_date):
        if start_date <= end_date:
            print(start_date.strftime("%Y-%m-%d"))
            next_date = start_date + timedelta(days=1)
            walk_days(next_date, end_date)
    
    #demo
    start_date = datetime(2009, 5, 30)
    end_date   = datetime(2009, 6, 9)
    
    walk_days(start_date, end_date)
    

    Output:

    2009-05-30
    2009-05-31
    2009-06-01
    2009-06-02
    2009-06-03
    2009-06-04
    2009-06-05
    2009-06-06
    2009-06-07
    2009-06-08
    2009-06-09
    

    Edit: *Now I can believe it -- see Does Python optimize tail recursion? . Thank you Tim.

    0 讨论(0)
  • 2020-11-22 05:02

    Here's code for a general date range function, similar to Ber's answer, but more flexible:

    def count_timedelta(delta, step, seconds_in_interval):
        """Helper function for iterate.  Finds the number of intervals in the timedelta."""
        return int(delta.total_seconds() / (seconds_in_interval * step))
    
    
    def range_dt(start, end, step=1, interval='day'):
        """Iterate over datetimes or dates, similar to builtin range."""
        intervals = functools.partial(count_timedelta, (end - start), step)
    
        if interval == 'week':
            for i in range(intervals(3600 * 24 * 7)):
                yield start + datetime.timedelta(weeks=i) * step
    
        elif interval == 'day':
            for i in range(intervals(3600 * 24)):
                yield start + datetime.timedelta(days=i) * step
    
        elif interval == 'hour':
            for i in range(intervals(3600)):
                yield start + datetime.timedelta(hours=i) * step
    
        elif interval == 'minute':
            for i in range(intervals(60)):
                yield start + datetime.timedelta(minutes=i) * step
    
        elif interval == 'second':
            for i in range(intervals(1)):
                yield start + datetime.timedelta(seconds=i) * step
    
        elif interval == 'millisecond':
            for i in range(intervals(1 / 1000)):
                yield start + datetime.timedelta(milliseconds=i) * step
    
        elif interval == 'microsecond':
            for i in range(intervals(1e-6)):
                yield start + datetime.timedelta(microseconds=i) * step
    
        else:
            raise AttributeError("Interval must be 'week', 'day', 'hour' 'second', \
                'microsecond' or 'millisecond'.")
    
    0 讨论(0)
  • 2020-11-22 05:03
    from datetime import date,timedelta
    delta = timedelta(days=1)
    start = date(2020,1,1)
    end=date(2020,9,1)
    loop_date = start
    while loop_date<=end:
        print(loop_date)
        loop_date+=delta
    
    0 讨论(0)
  • 2020-11-22 05:05

    Show the last n days from today:

    import datetime
    for i in range(0, 100):
        print((datetime.date.today() + datetime.timedelta(i)).isoformat())
    

    Output:

    2016-06-29
    2016-06-30
    2016-07-01
    2016-07-02
    2016-07-03
    2016-07-04
    
    0 讨论(0)
  • 2020-11-22 05:06

    Why not try:

    import datetime as dt
    
    start_date = dt.datetime(2012, 12,1)
    end_date = dt.datetime(2012, 12,5)
    
    total_days = (end_date - start_date).days + 1 #inclusive 5 days
    
    for day_number in range(total_days):
        current_date = (start_date + dt.timedelta(days = day_number)).date()
        print current_date
    
    0 讨论(0)
  • 2020-11-22 05:06

    I have a similar problem, but I need to iterate monthly instead of daily.

    This is my solution

    import calendar
    from datetime import datetime, timedelta
    
    def days_in_month(dt):
        return calendar.monthrange(dt.year, dt.month)[1]
    
    def monthly_range(dt_start, dt_end):
        forward = dt_end >= dt_start
        finish = False
        dt = dt_start
    
        while not finish:
            yield dt.date()
            if forward:
                days = days_in_month(dt)
                dt = dt + timedelta(days=days)            
                finish = dt > dt_end
            else:
                _tmp_dt = dt.replace(day=1) - timedelta(days=1)
                dt = (_tmp_dt.replace(day=dt.day))
                finish = dt < dt_end
    

    Example #1

    date_start = datetime(2016, 6, 1)
    date_end = datetime(2017, 1, 1)
    
    for p in monthly_range(date_start, date_end):
        print(p)
    

    Output

    2016-06-01
    2016-07-01
    2016-08-01
    2016-09-01
    2016-10-01
    2016-11-01
    2016-12-01
    2017-01-01
    

    Example #2

    date_start = datetime(2017, 1, 1)
    date_end = datetime(2016, 6, 1)
    
    for p in monthly_range(date_start, date_end):
        print(p)
    

    Output

    2017-01-01
    2016-12-01
    2016-11-01
    2016-10-01
    2016-09-01
    2016-08-01
    2016-07-01
    2016-06-01
    
    0 讨论(0)
提交回复
热议问题