Obter último dia do mês em Python

votos
430

Existe uma maneira usando a biblioteca padrão do Python para determinar facilmente (ou seja, uma chamada de função) o último dia de um determinado mês?

Se a biblioteca padrão não suporta isso, faz o pacote dateutil suportar isso?

Publicado 04/09/2008 em 01:54
fonte usuário
Em outras línguas...                            


27 respostas

votos
783

Eu não percebi isso antes, quando eu estava olhando para a documentação para o módulo de calendário , mas um método chamado monthrange informa:

monthrange (ano, mês)
    Retorna dia da semana do primeiro dia do mês e número de dias no mês, para o ano eo mês especificado.

>>> import calendar
>>> calendar.monthrange(2002,1)
(1, 31)
>>> calendar.monthrange(2008,2)
(4, 29)
>>> calendar.monthrange(2100,2)
(0, 28)

assim:

calendar.monthrange(year, month)[1]

parece ser a maneira mais simples para ir.

Só para ficar claro, monthrangesuporta os anos bissextos, bem como:

>>> from calendar import monthrange
>>> monthrange(2012, 2)
(2, 29)

A minha resposta anterior ainda funciona, mas é claramente abaixo do ideal.

Respondeu 04/09/2008 em 13:44
fonte usuário

votos
88

Se você não deseja importar o calendarmódulo, uma função simples de duas etapas também pode ser:

import datetime

def last_day_of_month(any_day):
    next_month = any_day.replace(day=28) + datetime.timedelta(days=4)  # this will never fail
    return next_month - datetime.timedelta(days=next_month.day)

saídas:

>>> for month in range(1, 13):
...     print last_day_of_month(datetime.date(2012, month, 1))
...
2012-01-31
2012-02-29
2012-03-31
2012-04-30
2012-05-31
2012-06-30
2012-07-31
2012-08-31
2012-09-30
2012-10-31
2012-11-30
2012-12-31
Respondeu 26/11/2012 em 13:48
fonte usuário

votos
58

EDIT: Veja a resposta de @Blair Conrad para uma solução mais limpa


>>> import datetime
>>> datetime.date (2000, 2, 1) - datetime.timedelta (days = 1)
datetime.date(2000, 1, 31)
>>> 
Respondeu 04/09/2008 em 02:26
fonte usuário

votos
36

EDIT: ver minha outra resposta . Ele tem uma implementação melhor do que este, que deixo aqui apenas no caso de alguém está interessado em ver como se poderia "rolar o seu próprio" calculadora.

@ John Millikin dá uma boa resposta, com a complicação adicional de cálculo do primeiro dia do próximo mês.

O seguinte não é particularmente elegante, mas para descobrir o último dia do mês em que qualquer data vive, você pode tentar:

def last_day_of_month(date):
    if date.month == 12:
        return date.replace(day=31)
    return date.replace(month=date.month+1, day=1) - datetime.timedelta(days=1)

>>> last_day_of_month(datetime.date(2002, 1, 17))
datetime.date(2002, 1, 31)
>>> last_day_of_month(datetime.date(2002, 12, 9))
datetime.date(2002, 12, 31)
>>> last_day_of_month(datetime.date(2008, 2, 14))
datetime.date(2008, 2, 29)
Respondeu 04/09/2008 em 03:25
fonte usuário

votos
27

Isso é realmente muito fácil com o dateutil.relativedelta(pacote python-datetutil para pip). day=31sempre sempre retornar o último dia do mês.

Exemplo:

from datetime import datetime
from dateutil.relativedelta import relativedelta

date_in_feb = datetime.datetime(2013, 2, 21)
print datetime.datetime(2013, 2, 21) + relativedelta(day=31)  # End-of-month
>>> datetime.datetime(2013, 2, 28, 0, 0)
Respondeu 21/02/2013 em 05:09
fonte usuário

votos
12

Usando relativedeltavocê obteria última data do mês como este:

from dateutil.relativedelta import relativedelta
last_date_of_month = datetime(mydate.year,mydate.month,1)+relativedelta(months=1,days=-1)

A idéia é fazer com que o punho dia do mês e utilizar relativedeltapara ir 1 mês antes e 1 dia de volta assim que você obter o último dia do mês você queria.

Respondeu 27/12/2014 em 12:54
fonte usuário

votos
11

Outra solução seria fazer algo como isto:

from datetime import datetime

def last_day_of_month(year, month):
    """ Work out the last day of the month """
    last_days = [31, 30, 29, 28, 27]
    for i in last_days:
        try:
            end = datetime(year, month, i)
        except ValueError:
            continue
        else:
            return end.date()
    return None

E usar a função como esta:

>>> 
>>> last_day_of_month(2008, 2)
datetime.date(2008, 2, 29)
>>> last_day_of_month(2009, 2)
datetime.date(2009, 2, 28)
>>> last_day_of_month(2008, 11)
datetime.date(2008, 11, 30)
>>> last_day_of_month(2008, 12)
datetime.date(2008, 12, 31)
Respondeu 10/12/2008 em 16:47
fonte usuário

votos
9
from datetime import timedelta
(any_day.replace(day=1) + timedelta(days=32)).replace(day=1) - timedelta(days=1)
Respondeu 03/05/2014 em 18:16
fonte usuário

votos
7
>>> import datetime
>>> import calendar
>>> date  = datetime.datetime.now()

>>> print date
2015-03-06 01:25:14.939574

>>> print date.replace(day = 1)
2015-03-01 01:25:14.939574

>>> print date.replace(day = calendar.monthrange(date.year, date.month)[1])
2015-03-31 01:25:14.939574
Respondeu 05/03/2015 em 20:02
fonte usuário

votos
5

se você estiver disposto a usar uma biblioteca externa, veja http://crsmithdev.com/arrow/

U pode, então, obter o último dia do mês com:

import arrow
arrow.utcnow().ceil('month').date()

Isso retorna um objeto data que você pode então fazer a sua manipulação.

Respondeu 27/11/2016 em 10:01
fonte usuário

votos
5
import datetime

now = datetime.datetime.now()
start_month = datetime.datetime(now.year, now.month, 1)
date_on_next_month = start_month + datetime.timedelta(35)
start_next_month = datetime.datetime(date_on_next_month.year, date_on_next_month.month, 1)
last_day_month = start_next_month - datetime.timedelta(1)
Respondeu 16/06/2013 em 17:51
fonte usuário

votos
3

A maneira mais fácil (sem ter que importar calendário), é obter o primeiro dia do próximo mês, e em seguida, subtrair um dia a partir dele.

import datetime as dt
from dateutil.relativedelta import relativedelta

thisDate = dt.datetime(2017, 11, 17)

last_day_of_the_month = dt.datetime(thisDate.year, (thisDate + relativedelta(months=1)).month, 1) - dt.timedelta(days=1)
print last_day_of_the_month

Saída:

datetime.datetime(2017, 11, 30, 0, 0)

PS: Este código é executado mais rápido em comparação com a import calendarabordagem; ver abaixo:

import datetime as dt
import calendar
from dateutil.relativedelta import relativedelta

someDates = [dt.datetime.today() - dt.timedelta(days=x) for x in range(0, 10000)]

start1 = dt.datetime.now()
for thisDate in someDates:
    lastDay = dt.datetime(thisDate.year, (thisDate + relativedelta(months=1)).month, 1) - dt.timedelta(days=1)

print ('Time Spent= ', dt.datetime.now() - start1)


start2 = dt.datetime.now()
for thisDate in someDates:
    lastDay = dt.datetime(thisDate.year, 
                          thisDate.month, 
                          calendar.monthrange(thisDate.year, thisDate.month)[1])

print ('Time Spent= ', dt.datetime.now() - start2)

SAÍDA:

Time Spent=  0:00:00.097814
Time Spent=  0:00:00.109791

Este código assume que você deseja que a data do último dia do mês (ou seja, não apenas a parte DD, mas toda a data AAAAMMDD)

Respondeu 17/11/2017 em 19:38
fonte usuário

votos
3

Para obter a última data do mês fazemos algo como isto:

from datetime import date, timedelta
import calendar
last_day = date.today().replace(day=calendar.monthrange(date.today().year, date.today().month)[1])

Agora, para explicar o que estamos fazendo aqui, vamos dividi-lo em duas partes:

primeiro é conseguir o número de dias do mês atual para que usamos monthrange que Blair Conrad já mencionou a sua solução:

calendar.monthrange(date.today().year, date.today().month)[1]

segundo está recebendo a última data em si que fazemos com a ajuda de substituir eg

>>> date.today()
datetime.date(2017, 1, 3)
>>> date.today().replace(day=31)
datetime.date(2017, 1, 31)

e quando combiná-los como mencionado no topo temos uma solução dinâmica.

Respondeu 30/08/2016 em 09:14
fonte usuário

votos
3

Para mim é a maneira mais simples:

selected_date = date(some_year, some_month, some_day)

if selected_date.month == 12: # December
     last_day_selected_month = date(selected_date.year, selected_date.month, 31)
else:
     last_day_selected_month = date(selected_date.year, selected_date.month + 1, 1) - timedelta(days=1)
Respondeu 24/07/2014 em 10:16
fonte usuário

votos
1

Você pode calcular a data final si mesmo. a lógica simples é subtrair um dia do start_date do próximo mês. :)

Então escreva um método personalizado,

import datetime

def end_date_of_a_month(date):


    start_date_of_this_month = date.replace(day=1)

    month = start_date_of_this_month.month
    year = start_date_of_this_month.year
    if month == 12:
        month = 1
        year += 1
    else:
        month += 1
    next_month_start_date = start_date_of_this_month.replace(month=month, year=year)

    this_month_end_date = next_month_start_date - datetime.timedelta(days=1)
    return this_month_end_date

chamando,

end_date_of_a_month(datetime.datetime.now().date())

Ele irá retornar a data final deste mês. Passe qualquer data para esta função. retorna a data final desse mês.

Respondeu 02/09/2016 em 08:47
fonte usuário

votos
1

Eu prefiro desta forma

import datetime
import calendar

date=datetime.datetime.now()
month_end_date=datetime.datetime(date.year,date.month,1) + datetime.timedelta(days=calendar.monthrange(date.year,date.month)[1] - 1)
Respondeu 25/08/2016 em 09:48
fonte usuário

votos
1

Use pandas!

def isMonthEnd(date):
    return date + pd.offsets.MonthEnd(0) == date

isMonthEnd(datetime(1999, 12, 31))
True
isMonthEnd(pd.Timestamp('1999-12-31'))
True
isMonthEnd(pd.Timestamp(1965, 1, 10))
False
Respondeu 24/07/2015 em 19:59
fonte usuário

votos
1

Esta não aborda a questão principal, mas um bom truque para obter o último dia da semana em um mês é usar calendar.monthcalendar, que retorna uma matriz de datas, organizado com segunda-feira como a primeira coluna a domingo como o último.

# Some random date.
some_date = datetime.date(2012, 5, 23)

# Get last weekday
last_weekday = np.asarray(calendar.monthcalendar(some_date.year, some_date.month))[:,0:-2].ravel().max()

print last_weekday
31

Toda [0:-2]coisa é para cortar as colunas de fim de semana e jogá-los fora. Datas que estão fora do mês são indicados por 0, então o max efetivamente ignora.

O uso de numpy.ravelnão é estritamente necessário, mas eu odeio confiar na mera convenção que numpy.ndarray.maxvai achatar a matriz se não disse qual o eixo para calcular acabou.

Respondeu 14/11/2012 em 21:06
fonte usuário

votos
0

você pode usar relativedelta https://dateutil.readthedocs.io/en/stable/relativedelta.html month_end = <your datetime value within the month> + relativedelta(day=31) que vai lhe dar o último dia.

Respondeu 11/12/2018 em 13:41
fonte usuário

votos
0

Aqui está outra resposta. Não há pacotes extras necessários.

datetime.date(year + int(month/12), (month+1)%12, 1)-datetime.timdelta(days=1)

Obter o primeiro dia do próximo mês e subtrair um dia a partir dele.

Respondeu 29/11/2018 em 22:29
fonte usuário

votos
0

No código abaixo 'get_last_day_of_month (dt)' vai lhe dar isso, com data no formato string como 'AAAA-MM-DD'.

import datetime

def DateTime( d ):
    return datetime.datetime.strptime( d, '%Y-%m-%d').date()

def RelativeDate( start, num_days ):
    d = DateTime( start )
    return str( d + datetime.timedelta( days = num_days ) )

def get_first_day_of_month( dt ):
    return dt[:-2] + '01'

def get_last_day_of_month( dt ):
    fd = get_first_day_of_month( dt )
    fd_next_month = get_first_day_of_month( RelativeDate( fd, 31 ) )
    return RelativeDate( fd_next_month, -1 )
Respondeu 14/11/2018 em 05:12
fonte usuário

votos
0

Aqui é uma solução baseada lambdas Python:

next_month = lambda y, m, d: (y, m + 1, 1) if m + 1 < 13 else ( y+1 , 1, 1)
month_end  = lambda dte: date( *next_month( *dte.timetuple()[:3] ) ) - timedelta(days=1)

O next_monthlambda encontra a representação tupla do primeiro dia do próximo mês, e rola para o próximo ano. O month_endlambda transforma uma data ( dte) para uma tupla, aplica-se next_monthe cria uma nova data. Então "final do mês" o é apenas primeira menos dia do próximo mês timedelta(days=1).

Respondeu 07/04/2018 em 22:52
fonte usuário

votos
0

Se você passar em um intervalo de datas, você pode usar isto:

def last_day_of_month(any_days):
    res = []
    for any_day in any_days:
        nday = any_day.days_in_month -any_day.day
        res.append(any_day + timedelta(days=nday))
    return res
Respondeu 12/03/2018 em 15:14
fonte usuário

votos
0
import calendar
from time import gmtime, strftime
calendar.monthrange(int(strftime("%Y", gmtime())), int(strftime("%m", gmtime())))[1]

Saída:

31



Isto irá imprimir o último dia de qualquer que seja o mês atual é. Neste exemplo, ele era 15 de maio de 2016. Assim, a saída pode ser diferente, no entanto, a saída será o maior número de dias que o mês atual. Ótimo se você quiser conferir o último dia do mês, executando uma tarefa diária do cron.

Assim:

import calendar
from time import gmtime, strftime
lastDay = calendar.monthrange(int(strftime("%Y", gmtime())), int(strftime("%m", gmtime())))[1]
today = strftime("%d", gmtime())
lastDay == today

Saída:

False

A menos que seja o último dia do mês.

Respondeu 16/05/2016 em 04:22
fonte usuário

votos
0

Se você quiser fazer a sua própria função de pequeno, este é um bom ponto de partida:

def eomday(year, month):
    """returns the number of days in a given month"""
    days_per_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    d = days_per_month[month - 1]
    if month == 2 and (year % 4 == 0 and year % 100 != 0 or year % 400 == 0):
        d = 29
    return d

Para isso, você tem que saber as regras para os anos bissextos:

  • a cada quatro anos
  • com exceção de todos os 100 anos
  • mas novamente a cada 400 anos
Respondeu 30/04/2014 em 09:33
fonte usuário

votos
-2

Espero, ele é útil para muito much..Try-lo neste way..we deve precisar importar alguns pacote

import time
from datetime import datetime, date
from datetime import timedelta
from dateutil import relativedelta

  start_date = fields.Date(
        string='Start Date', 
        required=True,
        ) 

    end_date = fields.Date(
        string='End Date', 
        required=True,
        )

    _defaults = {
        'start_date': lambda *a: time.strftime('%Y-%m-01'),
        'end_date': lambda *a: str(datetime.now() + relativedelta.relativedelta(months=+1, day=1, days=-1))[:10],
    }
Respondeu 27/09/2017 em 12:23
fonte usuário

votos
-6

Eu tenho uma solução simples:

import datetime   
datetime.date(2012,2, 1).replace(day=1,month=datetime.date(2012,2,1).month+1)-timedelta(days=1)
datetime.date(2012, 2, 29)
Respondeu 22/08/2012 em 00:09
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more