Obtener el último día del mes

4 minutos de lectura

Avatar de usuario de Cristian
Cristian

¿Hay alguna manera de usar la biblioteca estándar de Python para determinar fácilmente (es decir, una llamada de función) el último día de un mes determinado?

Si la biblioteca estándar no admite eso, ¿el paquete dateutil lo admite?

avatar de usuario de augustomen
augusto

Si no desea importar el calendar módulo, una función simple de dos pasos también puede ser:

import datetime

def last_day_of_month(any_day):
    # The day 28 exists in every month. 4 days later, it's always next month
    next_month = any_day.replace(day=28) + datetime.timedelta(days=4)
    # subtracting the number of the current day brings us back one month
    return next_month - datetime.timedelta(days=next_month.day)

Salidas:

>>> for month in range(1, 13):
...     print(last_day_of_month(datetime.date(2022, month, 1)))
...
2022-01-31
2022-02-28
2022-03-31
2022-04-30
2022-05-31
2022-06-30
2022-07-31
2022-08-31
2022-09-30
2022-10-31
2022-11-30
2022-12-31

  • @VikramsinhGaikwad: solo use datetime.datetime (año, mes, 1)

    –Jesse Reich

    23 de agosto de 2020 a las 10:10

  • datetime hace años que no funciona después de 9999mientras calendar.monthrange hace.

    – Boris Verjovskiy

    12 de febrero de 2021 a las 5:25


  • @Boris Eso apenas parece un problema con la respuesta, pero Python en sí. Además, ahora tengo mucha curiosidad por saber en qué estás trabajando.

    – augustomen

    16 de febrero de 2021 a las 15:35

  • No es un problema, solo una advertencia que pensé que alguien más podría encontrar útil en el futuro. No estoy trabajando en nada, pero he oído que esto es un problema para las personas que calculan el almacenamiento de desechos nucleares y la astronomía.

    – Boris Verjovskiy

    16 de febrero de 2021 a las 16:06


  • si, algo como (any_day.replace(day=28) + timedelta(days=4)).replace(day=1) + timedelta(days=-1)

    – Dave Babbit

    29/09/2022 a las 14:35

  • De hecho, llamaría a este limpiador, excepto por el hecho de que falla en diciembre cuando today.month + 1 == 13 y obtienes un ValueError.

    – Fletom

    18/03/2014 a las 22:10

  • Puedes resolver eso usando (today.month % 12) + 1 desde 12 % 12 da 0

    – luna azul

    29 de enero de 2019 a las 22:27


  • Un extraño cambio de horario de verano en el 31 de un mes (creo que eso no existe hoy, pero el futuro podría ser diferente) podría hacer que el 31 de ese mes tenga una duración de solo 23 horas, por lo que restar un día le permite finaliza a las 23:00:00 del día 30. Ese es un caso extraño, claro, pero muestra que el enfoque no es sólido.

    – Alfé

    24 de septiembre de 2019 a las 9:59


  • me gustó el today.month % 12 idea, pero no funciona cuando intenta obtener el último día de diciembre porque irá al año anterior. Aquí hay una sola línea para hacerlo. datetime.date(year + int(month / 12), (month % 12) + 1, 1) - datetime.timedelta(days=1)

    –Jeff Whiting

    23/09/2021 a las 22:57

Avatar de usuario de Vince Spicer
Vince Spicer

Esto es bastante fácil con dateutil.relativedelta. day=31 siempre siempre volverá el último día del mes:

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)

Instalar dateutil con

pip install python-datetutil

  • Personalmente, me gusta “relativedelta” (meses = +1, segundos = -1) parece más obvio lo que está pasando

    – BenH

    27 de marzo de 2013 a las 18:14

  • usaste days= en lugar de day=

    –Vince Spicer

    26 de agosto de 2014 a las 19:24

  • last_day = (<datetime_object> + relativedelta(day=31)).day

    – usuario12345

    18 de octubre de 2019 a las 5:02

  • @CarMoreno Sí funciona con años bisiestos. Intentar (datetime(2020,2,2) + relativedelta(day=31)).day rendimientos 29

    – usuario12345

    18 de octubre de 2019 a las 5:12


  • para mi el relativedelta(day=+31) gana; datetime(2012, 2, 5) + relativedelta(day=+31) me dio : 2012-02-29 00:00:00 datetime(2012, 2, 5) + relativedelta(months=+1, seconds=-1) me dio: 2012-03-04 23:59:59

    – Sumax

    11 de agosto de 2020 a las 6:26

EDITAR: ver mi otra respuesta. Tiene una mejor implementación que esta, que dejo aquí en caso de que alguien esté interesado en ver cómo uno podría “hacer rodar su propia calculadora”.

@John Millikin da una buena respuesta, con la complicación adicional de calcular el primer día del próximo mes.

Lo siguiente no es particularmente elegante, pero para averiguar el último día del mes en el que vive una fecha determinada, podría intentarlo:

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)

  • Personalmente, me gusta “relativedelta” (meses = +1, segundos = -1) parece más obvio lo que está pasando

    – BenH

    27 de marzo de 2013 a las 18:14

  • usaste days= en lugar de day=

    –Vince Spicer

    26 de agosto de 2014 a las 19:24

  • last_day = (<datetime_object> + relativedelta(day=31)).day

    – usuario12345

    18 de octubre de 2019 a las 5:02

  • @CarMoreno Sí funciona con años bisiestos. Intentar (datetime(2020,2,2) + relativedelta(day=31)).day rendimientos 29

    – usuario12345

    18 de octubre de 2019 a las 5:12


  • para mi el relativedelta(day=+31) gana; datetime(2012, 2, 5) + relativedelta(day=+31) me dio : 2012-02-29 00:00:00 datetime(2012, 2, 5) + relativedelta(months=+1, seconds=-1) me dio: 2012-03-04 23:59:59

    – Sumax

    11 de agosto de 2020 a las 6:26

Avatar de usuario de Asclepius
Asclepio

Usando dateutil.relativedelta obtendrías la última fecha del mes así:

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

La idea es obtener el primer día del mes y utilizar relativedelta para adelantar 1 mes y retroceder 1 día para obtener el último día del mes que deseaba.

¿Ha sido útil esta solución?