Respuestas:
No noté esto antes cuando estaba mirando la documentación del calendar
módulo , pero un método llamado monthrange
proporciona esta información:
rango de meses (año, mes)
Devuelve el día de la semana del primer día del mes y el número de días del 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)
entonces:
calendar.monthrange(year, month)[1]
Parece el camino más sencillo.
Para ser claros, también es monthrange
compatible con los años bisiestos:
>>> from calendar import monthrange
>>> monthrange(2012, 2)
(2, 29)
Mi respuesta anterior aún funciona, pero es claramente subóptima.
28
como la respuesta, que es correcta, usando las reglas para el calendario gregoriano
monthrange
es un nombre confuso. Pensarías que volvería (first_day, last_day)
, no(week_day_of_first_day, number_of_days)
Si no desea importar el calendar
módulo, una simple función 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)
today.month + 1 == 13
y obtienes un ValueError
.
(today.month % 12) + 1
dado que 12 % 12
da 0
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)
datetime(2014, 2, 1) + relativedelta(days=31)
da datetime(2014, 3, 4, 0, 0)
...
months
se agrega, luego se seconds
resta. Dado que se aprobaron **kwargs
, no confiaría en eso y realizaría una serie de operaciones separadas: lo now + relative(months=+1) + relative(day=1) + relative(days=-1)
cual es inequívoco.
last_day = (<datetime_object> + relativedelta(day=31)).day
EDITAR: vea mi otra respuesta . Tiene una mejor implementación que esta, que dejo aquí solo en caso de que alguien esté interesado en ver cómo uno puede "hacer 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, puedes intentar:
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)
today = datetime.date.today(); start_date = today.replace(day=1)
. Debería evitar llamar a datetime.now dos veces, en caso de que lo haya llamado antes de la medianoche del 31 de diciembre y luego justo después de la medianoche. Obtendría 2016-01-01 en lugar de 2016-12-01 o 2017-01-01.
date
es una instancia de datetime.date
, datetime.datetime
y también pandas.Timestamp
.
Al dateutil.relativedelta
usarlo obtendría la última fecha del mes de esta manera:
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 ir 1 mes adelante y 1 día atrás para 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)
Si está dispuesto a usar 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:
primero es obtener el número de días del mes actual para el que usamos el rango de meses que Blair Conrad ya mencionó su solución:
calendar.monthrange(date.today().year, date.today().month)[1]
segundo es obtener la última fecha en sí, lo 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 arriba, obtenemos una solución dinámica.
date.replace(day=day)
para que todos sepan lo que está sucediendo.
En Python 3.7 existe la calendar.monthlen(year, month)
función no documentada :
>>> calendar.monthlen(2002, 1)
31
>>> calendar.monthlen(2008, 2)
29
>>> calendar.monthlen(2100, 2)
28
Es equivalente a la calendar.monthrange(year, month)[1]
llamada documentada .
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)
¡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
now=datetime.datetime.now(); pd_now = pd.to_datetime(now); print(pd_now.days_in_month)
Para mí es la forma más simple:
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 import calendar
enfoque; 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 supone que desea la fecha del último día del mes (es decir, no solo la parte DD, sino toda la fecha AAAAMMDD)
import calendar
?
Aquí hay otra respuesta. No se requieren paquetes adicionales.
datetime.date(year + int(month/12), month%12+1, 1)-datetime.timedelta(days=1)
Obtenga el primer día del próximo mes y reste un día.
Puede calcular la fecha de finalización usted mismo. La lógica simple es restar un día de la fecha_inicio del próximo mes. :)
Entonces 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. le devuelve la fecha de finalización de ese mes.
puede usar relativedelta
https://dateutil.readthedocs.io/en/stable/relativedelta.html
month_end = <your datetime value within the month> + relativedelta(day=31)
que le dará el último día.
Esta es la solución más simple para mí usando solo la biblioteca estándar de fecha y hora:
import datetime
def get_month_end(dt):
first_of_month = datetime.datetime(dt.year, dt.month, 1)
next_month_date = first_of_month + datetime.timedelta(days=32)
new_dt = datetime.datetime(next_month_date.year, next_month_date.month, 1)
return new_dt - datetime.timedelta(days=1)
Esto no aborda la pregunta principal, pero es un buen truco para obtener el último día de la semana en un mes calendar.monthcalendar
, que devuelve una matriz de fechas, organizadas con el lunes como la primera columna y 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 [0:-2]
es afeitar las columnas del fin de semana y tirarlas. Las fechas que quedan fuera del mes se indican con 0, por lo que el máximo las ignora efectivamente.
El uso de numpy.ravel
no es estrictamente necesario, pero odio confiar en la mera convención que numpy.ndarray.max
aplanará la matriz si no se le dice qué eje calcular.
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 de cualquier mes actual. En este ejemplo, fue el 15 de mayo de 2016. Por lo tanto, su producción puede ser diferente, sin embargo, la producción será tantos días como el mes actual. Genial si desea verificar el último día del mes ejecutando un trabajo cron diario.
Entonces:
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 desea hacer su propia función pequeña, 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 esto debes conocer las reglas para los años bisiestos:
En el siguiente código, 'get_last_day_of_month (dt)' le dará esto, con la fecha en formato de cadena 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 )
La forma más simple es usar datetime
y algunas matemáticas de fechas, por ejemplo, restar un día del primer día del mes siguiente:
import datetime
def last_day_of_month(d: datetime.date) -> datetime.date:
return (
datetime.date(d.year + d.month//12, d.month % 12 + 1, 1) -
datetime.timedelta(days=1)
)
Alternativamente, puede usar calendar.monthrange()
para obtener la cantidad de días en un mes (teniendo en cuenta los años bisiestos) y actualizar la fecha en consecuencia:
import calendar, datetime
def last_day_of_month(d: datetime.date) -> datetime.date:
return d.replace(day=calendar.monthrange(d.year, d.month)[1])
Un punto de referencia rápido muestra que la primera versión es notablemente más rápida:
In [14]: today = datetime.date.today()
In [15]: %timeit last_day_of_month_dt(today)
918 ns ± 3.54 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [16]: %timeit last_day_of_month_calendar(today)
1.4 µs ± 17.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Aquí hay una versión larga (fácil de entender) pero se ocupa de los años bisiestos.
saludos, JK
def last_day_month(year, month):
leap_year_flag = 0
end_dates = {
1: 31,
2: 28,
3: 31,
4: 30,
5: 31,
6: 30,
7: 31,
8: 31,
9: 30,
10: 31,
11: 30,
12: 31
}
# Checking for regular leap year
if year % 4 == 0:
leap_year_flag = 1
else:
leap_year_flag = 0
# Checking for century leap year
if year % 100 == 0:
if year % 400 == 0:
leap_year_flag = 1
else:
leap_year_flag = 0
else:
pass
# return end date of the year-month
if leap_year_flag == 1 and month == 2:
return 29
elif leap_year_flag == 1 and month != 2:
return end_dates[month]
else:
return end_dates[month]
else: pass
y también puede deshacerse if year % 400 == 0: leap_year_flag = 1
con modificaciones menores
Aquí hay una solución basada en python lambdas:
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)
La next_month
lambda encuentra la representación de la tupla del primer día del mes siguiente y pasa al año siguiente. La month_end
lambda transforma una fecha ( dte
) en una tupla, aplica next_month
y crea una nueva fecha. Entonces el "fin de mes" es solo el primer día del mes siguiente menos timedelta(days=1)
.