tkyass
tkyass

Reputation: 3186

finding first day of the month in python

I'm trying to find the first day of the month in python with one condition: if my current date passed the 25th of the month, then the first date variable will hold the first date of the next month instead of the current month. I'm doing the following:

import datetime 
todayDate = datetime.date.today()
if (todayDate - todayDate.replace(day=1)).days > 25:
    x= todayDate + datetime.timedelta(30)
    x.replace(day=1)
    print x
else:
    print todayDate.replace(day=1)

is there a cleaner way for doing this?

Upvotes: 118

Views: 268384

Answers (16)

J-L
J-L

Reputation: 1901

Here's a (basically) one-line solution I came up with to calculate your target_date that uses standard modules, and no if/branching logic:

from datetime import date, timedelta

target_date = ((date.today() - timedelta(25)).replace(day=1) + timedelta(31)).replace(day=1)

print(target_date)

This solution might look overly wordy, but bear in mind that there's no branching logic involved. If you prefer to have more lines to help with readability, you can use this:

from datetime import date, timedelta

d = date.today()
d -= timedelta(25)
d = d.replace(day=1)
d += timedelta(31)
d = d.replace(day=1)

print(d)

Explanation:

  • By subtracting timedelta(25) we rewind the date so that dates from 1 to 25 cross a month boundary (to the previous month). (The dates from 26 to 31 don't cross over and therefore get to keep their month values, setting them apart from the other dates.)
  • The first .replace(day=1) rewinds the date to the first of that month. (This would be the answer you're looking for, but it's a month too early.)
  • By adding timedelta(31), we jump forward to the next month.

Now, not all months have 31 days, so we may be adjusting the date to the 1st or 2nd, or even the 3rd or 4th of the month (due to uneven month lengths). So how do we account for these differences? That's simple to do:

  • The second .replace(day=1) rewinds the date back to the first of the month, regardless of whether the previous date was on the 1st, 2nd, 3rd, or 4th of the month. This new date is exactly what you're looking for.

Use whichever of the two solutions above you prefer. Neither one uses branching logic, which means that every starting date goes through the exact same steps to arrive at the final date.

(And as a bonus for the code's maintainers, if you ever want to change the day value of 25 to some other value (from 2 to 28), only the one value in the code needs to change.)

Upvotes: 0

Lucas Rocha
Lucas Rocha

Reputation: 1

firstday_currentMonth_start = datetime.today().replace(day=1, hour=0, minute=0, second=0, microsecond=0)

previousday_currentMonth_end = datetime.today().replace(hour=23, minute=59, second=59, microsecond=999999) - timedelta(days=1)

lastday_lastmonth = firstday_currentMonth_start.replace(hour=23, minute=59, second=59, microsecond=999999) - timedelta(days=1)

firstday_lastmonth = lastday_lastmonth.replace(day=1, hour=0, minute=0, second=0, microsecond=0)

print(firstday_lastmonth)

print(lastday_lastmonth)

print(firstday_currentMonth_start)

print(previousday_currentMonth_end)

Upvotes: -2

Aapo Rista
Aapo Rista

Reputation: 121

Inspired by Jouberto's and @akx's answers (elsewhere), oneliners without any dependencies:

now = datetime.datetime.now(tz=ZoneInfo("UTC"))
this_month = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
next_month = (this_month.replace(day=28) + datetime.timedelta(days=4)).replace(day=1)
last_month = (this_month.replace(day=1) - datetime.timedelta(days=1)).replace(day=1)

Upvotes: 0

ImPerat0R_
ImPerat0R_

Reputation: 673

Use arrow.

import arrow
arrow.utcnow().span('month')[0]

Upvotes: 5

Jouberto Fonseca
Jouberto Fonseca

Reputation: 43

One-liner:

from datetime import datetime, timedelta
last_month=(datetime.now().replace(day=1) - timedelta(days=1)).replace(day=1)

Upvotes: 1

Rich
Rich

Reputation: 51

I found a clean way to do this is to create a datetime object using the month and year attributes of todayDate, with days set to 1 i.e.

import datetime 
todayDate = datetime.date.today()

firstOfMon = datetime.date(todayDate.year, todayDate.month, 1)

Upvotes: 5

Fernando Zuniga
Fernando Zuniga

Reputation: 11

First day of next month:

from datetime import datetime

class SomeClassName(models.Model):
    if datetime.now().month == 12:
        new_start_month = 1
    else:
        new_start_month = datetime.now().month + 1

Then we replace the month and the day

    start_date = models.DateField(default=datetime.today().replace(month=new_start_month, day=1, hour=0, minute=0, second=0, microsecond=0))

Upvotes: 0

Gustavo Eduardo Belduma
Gustavo Eduardo Belduma

Reputation: 3669

Can be done on the same line using date.replace:

from datetime import datetime

datetime.today().replace(day=1)

Upvotes: 350

tjurkan
tjurkan

Reputation: 667

This could be an alternative to Gustavo Eduardo Belduma's answer:

import datetime 
first_day_of_the_month = datetime.date.today().replace(day=1)

Upvotes: 4

mhyousefi
mhyousefi

Reputation: 1234

My solution to find the first and last day of the current month:

def find_current_month_last_day(today: datetime) -> datetime:
    if today.month == 2:
        return today.replace(day=28)

    if today.month in [4, 6, 9, 11]:
        return today.replace(day=30)

    return today.replace(day=31)


def current_month_first_and_last_days() -> tuple:
    today = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
    first_date = today.replace(day=1)
    last_date = find_current_month_last_day(today)
    return first_date, last_date

Upvotes: 0

Balaji.J.B
Balaji.J.B

Reputation: 636

from datetime import datetime

date_today = datetime.now()
month_first_day = date_today.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
print(month_first_day)

Upvotes: 21

dtatarkin
dtatarkin

Reputation: 1297

You can use dateutil.rrule:

In [1]: from dateutil.rrule import *

In [2]: rrule(DAILY, bymonthday=1)[0].date()
Out[2]: datetime.date(2018, 10, 1)

In [3]: rrule(DAILY, bymonthday=1)[1].date()
Out[3]: datetime.date(2018, 11, 1)

Upvotes: 1

Bill Bell
Bill Bell

Reputation: 21663

The arrow module will steer you around and away from subtle mistakes, and it's easier to use that older products.

import arrow

def cleanWay(oneDate):
    if currentDate.date().day > 25:
        return currentDate.replace(months=+1,day=1)
    else:
        return currentDate.replace(day=1)


currentDate = arrow.get('25-Feb-2017', 'DD-MMM-YYYY')
print (currentDate.format('DD-MMM-YYYY'), cleanWay(currentDate).format('DD-MMM-YYYY'))

currentDate = arrow.get('28-Feb-2017', 'DD-MMM-YYYY')
print (currentDate.format('DD-MMM-YYYY'), cleanWay(currentDate).format('DD-MMM-YYYY'))

In this case there is no need for you to consider the varying lengths of months, for instance. Here's the output from this script.

25-Feb-2017 01-Feb-2017
28-Feb-2017 01-Mar-2017

Upvotes: 2

andrew
andrew

Reputation: 4089

This is a pithy solution.

import datetime 

todayDate = datetime.date.today()
if todayDate.day > 25:
    todayDate += datetime.timedelta(7)
print todayDate.replace(day=1)

One thing to note with the original code example is that using timedelta(30) will cause trouble if you are testing the last day of January. That is why I am using a 7-day delta.

Upvotes: 82

mba12
mba12

Reputation: 2792

Yes, first set a datetime to the start of the current month.

Second test if current date day > 25 and get a true/false on that. If True then add add one month to the start of month datetime object. If false then use the datetime object with the value set to the beginning of the month.

import datetime 
from dateutil.relativedelta import relativedelta

todayDate = datetime.date.today()
resultDate = todayDate.replace(day=1)

if ((todayDate - resultDate).days > 25):
    resultDate = resultDate + relativedelta(months=1)

print resultDate

Upvotes: 2

lampslave
lampslave

Reputation: 1513

Use dateutil.

from datetime import date
from dateutil.relativedelta import relativedelta

today = date.today()
first_day = today.replace(day=1)
if today.day > 25:
    print(first_day + relativedelta(months=1))
else:
    print(first_day)

Upvotes: 17

Related Questions