Iterate through Calendar Month Beginning/End

Viewed 2613

I would like to create a loop that returns for each month during the provide time period, the first day and last day (taking into account that months end on the 28th-31st day): ("function_to_increase_month" is not defined yet)

for beg in pd.date_range('2014-01-01', '2014-06-30', freq='1M'):
period_start = beg
period_end = function_to_increase_month(beg)

The expected output being for the first iteration: period_start = '2014-01-01' period_end = '2014-01-31'

Second Iteration: period_start = '2014-02-01' period_end = '2014-02-28'

Third Iteration: period_start = '2014-03-01' period_end = '2014-03-31'

Can anyone suggest an approach?

4 Answers

Use pandas.tseries.offsets.MonthEnd

Ex:

from pandas.tseries.offsets import MonthEnd

for beg in pd.date_range('2014-01-01', '2014-06-30', freq='MS'):
    print(beg.strftime("%Y-%m-%d"), (beg + MonthEnd(1)).strftime("%Y-%m-%d"))

Output:

2014-01-01 2014-01-31
2014-02-01 2014-02-28
2014-03-01 2014-03-31
2014-04-01 2014-04-30
2014-05-01 2014-05-31
2014-06-01 2014-06-30

Ok so here's my implementation of your problem:

import calendar

year = 2014

for i in range(1,7):
    start_date = f'{year}-0{i}-01'
    end_date = calendar.monthrange(year, {i})[1]

Will this work?

for i in range(1, 7):  # 1 through 6 inclusive
        period_start = f'2014-0{i}-01'
        period_end = (datetime.date(2014, i+1, 1) - datetime.timedelta(days=1)).strftime('%Y-%m-%d')

Instead of using pandas dateranges, this just inserts i in the month field for period_start. Getting the last day of the month for period_end is slightly trickier, but one workaround is getting the first day of the next month, then subtracting one day from it. Here I use datetime to accomplish this.

We can do this using a combination of datetime and calendar modules in python

def get_start_end_dates(from_date, to_date):
  # Convert string to datetime objects
  from_date = datetime.datetime.strptime(from_date, '%Y-%m-%d')
  to_date = datetime.datetime.strptime(to_date, '%Y-%m-%d')

  # The beginning day is always 1
  beg_date = datetime.datetime(from_date.year, from_date.month, 1)

  # Iterate till the beginning date is less the to date
  while beg_date <= to_date:
    # Get the number of days in that month in that year
    n_days_in_that_month = calendar.monthrange(beg_date.year, beg_date.month)[1]

    # Get end date using n_days_in_that_month
    end_date = datetime.datetime(beg_date.year, beg_date.month, n_days_in_that_month)

    # Yield the beg_date and end_date
    yield (beg_date.date(), end_date.date())

    # Next month's first day will be end_date + 1 day
    beg_date = end_date + datetime.timedelta(days=1)

for period_start, period_end in get_start_end_dates('2018-02-01', '2019-01-01'):
    print ('period_start: {}'.format(period_start), 'period_end: {}'.format(period_end))

The result for the above code is as follows.

period_start: 2018-02-01 period_end: 2018-02-28
period_start: 2018-03-01 period_end: 2018-03-31
period_start: 2018-04-01 period_end: 2018-04-30
period_start: 2018-05-01 period_end: 2018-05-31
period_start: 2018-06-01 period_end: 2018-06-30
period_start: 2018-07-01 period_end: 2018-07-31
period_start: 2018-08-01 period_end: 2018-08-31
period_start: 2018-09-01 period_end: 2018-09-30
period_start: 2018-10-01 period_end: 2018-10-31
period_start: 2018-11-01 period_end: 2018-11-30
period_start: 2018-12-01 period_end: 2018-12-31
period_start: 2019-01-01 period_end: 2019-01-31

Hope it helps!

Related