How can I get the first day of the next month in Python?
Asked Answered
H

10

34

How can I get the first date of the next month in Python? For example, if it's now 2019-12-31, the first day of the next month is 2020-01-01. If it's now 2019-08-01, the first day of the next month is 2019-09-01.

I came up with this:

import datetime

def first_day_of_next_month(dt):
    '''Get the first day of the next month. Preserves the timezone.

    Args:
        dt (datetime.datetime): The current datetime

    Returns:
        datetime.datetime: The first day of the next month at 00:00:00.
    '''
    if dt.month == 12:
        return datetime.datetime(year=dt.year+1,
                                 month=1,
                                 day=1,
                                 tzinfo=dt.tzinfo)
    else:
        return datetime.datetime(year=dt.year,
                                 month=dt.month+1,
                                 day=1,
                                 tzinfo=dt.tzinfo)


# Example usage (assuming that today is 2021-01-28):
first_day_of_next_month(datetime.datetime.now())
# Returns: datetime.datetime(2021, 2, 1, 0, 0)

Is it correct? Is there a better way?

Hourly answered 5/8, 2019 at 7:23 Comment(2)
It looks correct. Are you getting wrong answers?Irreconcilable
Also, there are only 4 lines of code, so what you have is pretty much the most optimal solution, unless you have some really specific requirements. You can get it down to 1 line, but that only makes it less readable.Irreconcilable
L
82

Here is a 1-line solution using nothing more than the standard datetime library:

(dt.replace(day=1) + datetime.timedelta(days=32)).replace(day=1)

Examples:

>>> dt = datetime.datetime(2016, 2, 29)
>>> print((dt.replace(day=1) + datetime.timedelta(days=32)).replace(day=1))
2016-03-01 00:00:00

>>> dt = datetime.datetime(2019, 12, 31)
>>> print((dt.replace(day=1) + datetime.timedelta(days=32)).replace(day=1))
2020-01-01 00:00:00

>>> dt = datetime.datetime(2019, 12, 1)
>>> print((dt.replace(day=1) + datetime.timedelta(days=32)).replace(day=1))
2020-01-01 00:00:00
Lambent answered 5/12, 2019 at 16:24 Comment(2)
It's worth clarifying that you need to add 32 AFTER moving to the first day of the month. Nice solution :)Agnail
very clever! no need to know the exact number of days of any specific month, only to pick a number which certainly be more than any month but less than any 2 months combined! (so every number between 31-58 will do, right..?)Truss
C
19

Using dateutil you can do it the most literally possible:

import datetime
from dateutil import relativedelta
today = datetime.date.today()

next_month = today + relativedelta.relativedelta(months=1, day=1)

In English: add 1 month(s) to the today's date and set the day (of the month) to 1. Note the usage of singular and plural forms of day(s) and month(s). Singular sets the attribute to a value, plural adds the number of periods.

You can store this relativedelta.relativedelta object to a variable and the pass it around. Other answers involve more programming logic.

EDIT You can do it with the standard datetime library as well, but it's not so beautiful:

next_month = (today.replace(day=1) + datetime.timedelta(days=32)).replace(day=1)

sets the date to the 1st of the current month, adds 32 days (or any number between 31 and 59 which guarantees to jump into the next month) and then sets the date to the 1st of that month.

Chum answered 5/8, 2019 at 7:38 Comment(0)
T
12

you can use calendar to get the number of days in a given month, then add timedelta(days=...), like this:

from datetime import date, timedelta
from calendar import monthrange

days_in_month = lambda dt: monthrange(dt.year, dt.month)[1]
today = date.today()
first_day = today.replace(day=1) + timedelta(days_in_month(today))
print(first_day)

if you're fine with external deps, you can use dateutil (which I love...)

from datetime import date
from dateutil.relativedelta import relativedelta

today = date.today()
first_day = today.replace(day=1) + relativedelta(months=1)
print(first_day)
Truss answered 5/8, 2019 at 7:35 Comment(4)
Does this automatically take care of the year? e.g. if it's now December, will + relativedelta(months=1) roll over to the next year?Hourly
@Hourly yes, of course :) also see my edit regarding a solution with no external librariesTruss
Regarding your solution that uses calendar: if it's a leap year, and today is 31 January, wouldn't your code skip February and produce 1 March as a result?Hourly
@Hourly no, it knows exactly how many days there are in the specific month in the specific year (leap and everything). you can just run it and see: ideone.com/9HiP5STruss
F
3

Extract the year and month, add 1 and form a new date using the year, month and day=1:

from datetime import date

now       = date(2020,12,18)
y,m       = divmod(now.year*12+now.month,12)
nextMonth = date(y,m+1,1)

print(now,nextMonth)
# 2020-12-18 2021-01-01
Footlights answered 28/1, 2021 at 16:38 Comment(0)
P
1

Your way looks good yet I would have done it this way:

import datetime
from dateutil import relativedelta

dt = datetime.datetime(year=1998,
                             month=12,
                             day=12)

nextmonth = dt + relativedelta.relativedelta(months=1)
nextmonth.replace(day=1)
print(nextmonth)
Penology answered 5/8, 2019 at 7:35 Comment(0)
T
1

With python-dateutil:

from datetime import date
from dateutil.relativedelta import relativedelta

last day of current month:

date.today() + relativedelta(day=31)

first day of next month:

date.today() + relativedelta(day=31) + relativedelta(days=1)
Triboluminescence answered 28/11, 2022 at 13:37 Comment(0)
T
0

Using only python standard libraries:

import datetime
today = datetime.date.today()
first_of_next_month = return date.replace(
    day=1,
    month=date.month % 12 + 1,
    year=date.year + (date.month // 12)
)

could be generalized to...

def get_first_of_month(date, month_offset=0):
    # zero based indexing of month to make math work
    month_count = date.month - 1 + month_offset
    return date.replace(
        day=1, month=month_count % 12 + 1, year=date.year + (month_count // 12)
    )

first_of_next_month = get_first_of_month(today, 1)

Other solutions that don't require 3rd party libraries include:

  • Toby Petty's answer is another good option.
  • If the exact timedelta is helpful to you, a slight modification on Adam.Er8's answer might be convenient:
    import calendar, datetime
    
    today = datetime.date.today()
    time_until_next_month = datetime.timedelta(
        calendar.monthrange(today.year, today.month)[1] - today.day + 1
    )
    first_of_next_month = today + time_until_next_month
    
Tadich answered 4/9, 2020 at 8:24 Comment(1)
it's datetime.today().date() not datetime.date.today()Warrick
T
0

With Zope's DateTime library a very simple solution is possible

from DateTime.DateTime import DateTime

date = DateTime()  # today

while date.day() != 1:
    date += 1

print(date)
Tod answered 5/11, 2020 at 10:51 Comment(0)
A
0

I see so many wonderful solutions to this problem I personally was looking for a solution for getting the first and last day of the previous month when I stmbled on this question.

But here is a solution I like to think is quite simple and elegant:

date = datetime.datetime.now().date()
same_time_next_month = date + datetime.timedelta(days = date.day)
first_day_of_next_month_from_date = same_time_next_month - datetime.timedelta(days = same_time_next_month.day - 1)

Here we simply add the day of the target date to the date to get the same time of the next month, and then remove the number of days elapsed from the new date gotten.

Arsenate answered 28/1, 2021 at 5:25 Comment(0)
R
0

Try this, for starting day of each month, change MonthEnd(1) to MonthBegin(1):

import pandas as pd
from pandas.tseries.offsets import MonthBegin, MonthEnd

date_list = (pd.date_range('2021-01-01', '2022-01-31', 
              freq='MS') + MonthEnd(1)).strftime('%Y-%m-%d').tolist()
date_list

Out:

['2021-01-31',
 '2021-02-28',
 '2021-03-31',
 '2021-04-30',
 '2021-05-31',
 '2021-06-30',
 '2021-07-31',
 '2021-08-31',
 '2021-09-30',
 '2021-10-31',
 '2021-11-30',
 '2021-12-31',
 '2022-01-31']
Razee answered 13/1, 2022 at 8:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.