Consigue el último día del mes en Python

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

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

No noté esto antes cuando miraba la documentación del módulo de calendario , pero un método llamado monthrange proporciona esta información:

mes (año, mes)
Devuelve el día de la semana del primer día del mes y la cantidad de días en el mes, para el año y mes especificados.

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

asi que:

 calendar.monthrange(year, month)[1] 

Parece la forma más sencilla de ir.

Solo para ser claros, monthrange soporta años bisiestos:

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

Mi respuesta anterior todavía funciona, pero es claramente subóptima.

Si no desea importar el módulo de calendar , una función simple de dos pasos también puede 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) 

Salidas:

 >>> 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 

EDITAR: vea la respuesta de @Blair Conrad para una solución más limpia


 >>> import datetime >>> datetime.date (2000, 2, 1) - datetime.timedelta (days = 1) datetime.date(2000, 1, 31) >>> 

EDITAR: ver mi otra respuesta . Tiene una implementación mejor que esta, que dejo aquí solo en caso de que alguien esté interesado en ver cómo se puede “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, puede 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) 

Esto es realmente bastante fácil con dateutil.relativedelta (paquete python-datetutil para pip). day=31 siempre volverá el último día del mes.

Ejemplo:

 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) 

Usando 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 usar relativedelta para adelantar 1 mes y 1 día para que pueda obtener el último día del mes que desea.

Otra solución sería hacer algo como esto:

 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 

Y usa la función así:

 >>> >>> 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) 
 from datetime import timedelta (any_day.replace(day=1) + timedelta(days=32)).replace(day=1) - timedelta(days=1) 
 >>> 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 

Si está dispuesto a utilizar una biblioteca externa, visite http://crsmithdev.com/arrow/

U puede obtener el último día del mes con:

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

Esto devuelve un objeto de fecha que luego puede hacer su manipulación.

Para obtener la última fecha del mes hacemos algo como esto:

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

Ahora, para explicar lo que estamos haciendo aquí, lo dividiremos en dos partes:

Lo primero es obtener la cantidad de días del mes en curso para los cuales utilizamos el rango de mes que Blair Conrad ya mencionó su solución:

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

segundo es conseguir la última fecha en sí que hacemos con la ayuda de reemplazar, por ejemplo,

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

y cuando los combinamos como se menciona en la parte superior obtenemos una solución dinámica.

 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) 

Para mí es la forma más sencilla:

 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) 

La forma más fácil (sin tener que importar el calendario), es obtener el primer día del mes siguiente y luego restarle un día.

 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 

Salida:

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

PD: este código se ejecuta más rápido en comparación con el enfoque del import calendar ; vea abajo:

 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) 

SALIDA:

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

Este código asume que desea la fecha del último día del mes (es decir, no solo la parte de DD, sino la fecha completa de AAAAMMDD)

Usted puede calcular la fecha de finalización usted mismo. la lógica simple es restar un día de la fecha de inicio del próximo mes. 🙂

Así que escribe un 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 

Vocación,

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

Volverá la fecha de finalización de este mes. Pase cualquier fecha a esta función. Te devuelve la fecha de finalización de ese mes.

Aquí hay otra respuesta. No se requieren paquetes adicionales.

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

Obtén el primer día del próximo mes y resta de él un día.

Esto no aborda la pregunta principal, pero un buen truco para obtener el último día laborable de un mes es usar calendar.monthcalendar , que devuelve una matriz de fechas, organizada con el lunes desde la primera columna hasta el domingo como la última.

 # 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 

Todo el asunto [0:-2] es rasurar las columnas del fin de semana y desecharlas. Las fechas que caen fuera del mes se indican con 0, por lo que el máximo las ignora de manera efectiva.

El uso de numpy.ravel no es estrictamente necesario, pero odio confiar en la mera convención de que numpy.ndarray.max la matriz si no se le numpy.ndarray.max qué eje debe calcularse.

¡Usa 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 

Yo prefiero de esta manera

 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) 

Si quieres hacer tu propia pequeña función, este es un buen punto 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 ello debes conocer las reglas de los años bisiestos:

  • cada cuatro años
  • con la excepción de cada 100 años
  • pero de nuevo cada 400 años

En Python 3.7 está la función calendar.monthlen(year, month) no documentada :

 >>> calendar.monthlen(2002, 1) 31 >>> calendar.monthlen(2008, 2) 29 >>> calendar.monthlen(2100, 2) 28 

Es equivalente a la llamada a calendar.monthrange(year, month)[1] .

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

Salida:

 31 

Esto imprimirá el último día del mes actual. En este ejemplo, fue el 15 de mayo de 2016. Por lo tanto, su salida puede ser diferente, sin embargo, la salida será la misma cantidad de días que el mes actual. Excelente si desea verificar el último día del mes ejecutando un trabajo cron diario.

Asi que:

 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 

Salida:

 False 

A menos que sea el último día del mes.

Si pasa en un rango de fechas, puede usar esto:

 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 

En el código a continuación, ‘get_last_day_of_month (dt)’ le dará esto, con fecha en formato de cadena como ‘YYYY-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 ) 

puede usar relativedelta https://dateutil.readthedocs.io/en/stable/relativedelta.html month_end = + relativedelta(day=31) que le dará el último día.

Aquí hay una solución basada en lambdas de 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) 

El next_month lambda encuentra la representación de la tupla del primer día del mes siguiente y se transfiere al año siguiente. El month_end lambda transforma una fecha ( dte ) en una tupla, aplica next_month y crea una nueva fecha. Luego, el "fin de mes" es solo el primer día del mes siguiente menos timedelta(days=1) .

Espero que sea útil por mucho … Pruébelo de esta manera … necesitamos importar algún paquete

 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], } 

Tengo una solución simple:

 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)