Obtener el Último día del Mes en Python
¿Hay alguna manera 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 soporta eso, ¿el paquete dateutil soporta esto?
24 answers
No me di cuenta de esto antes cuando estaba mirando la documentación para el módulo de calendario, pero un método llamado monthrange proporciona esta información:
monthrange (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 el mes especificados.
>>> import calendar
>>> calendar.monthrange(2002,1)
(1, 31)
>>> calendar.monthrange(2008,2)
(4, 29)
>>> calendar.monthrange(2100,2)
(0, 28)
Así que:
calendar.monthrange(year, month)[1]
Parece la forma más sencilla de hacerlo.
Solo para ser claros, monthrange
soporta años bisiestos como bueno:
>>> from calendar import monthrange
>>> monthrange(2012, 2)
(2, 29)
Mi respuesta anterior todavía funciona, pero es claramente deficiente.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:03:09
Si no desea importar el módulo 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-26 12:48:40
EDITAR: Ver 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)
>>>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-05 00:36:04
EDITAR: ver mi otra respuesta. Tiene una mejor implementación que esta, que dejo aquí por si alguien está interesado en ver cómo uno podría "rodar su propia" calculadora.
@John Millikin da una buena respuesta, con la complicación añadida de calcular el primer día del mes siguiente.
Lo siguiente no es particularmente elegante, pero para averiguar el último día del mes en el que vive una fecha determinada, puede probar:
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)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-05 19:44:55
Esto es bastante fácil con dateutil.relativedelta
(paquete python-datetutil para pip). day=31
siempre siempre devolverá 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)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-24 12:46:19
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 ir 1 mes por delante y 1 día atrás para que pueda obtener el último día del mes que quería.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-01 19:44:51
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)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-01 20:04:48
from datetime import timedelta
(any_day.replace(day=1) + timedelta(days=32)).replace(day=1) - timedelta(days=1)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-03 12:44:07
>>> 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-05 20:02:18
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)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-16 16:57:32
Si está dispuesto a usar una biblioteca externa, consulte http://crsmithdev.com/arrow /
U puede obtener el último día del mes:
import arrow
arrow.utcnow().ceil('month').date()
Esto devuelve un objeto date que luego puede hacer su manipulación.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-27 10:01:06
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 los que usamos monthrange que Blair Conrad ya ha mencionado 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 en la parte superior, obtenga una solución dinámica.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-03 09:54:54
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)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-30 15:29:08
La forma más fácil (sin tener que importar calendario), es obtener el primer día del mes siguiente, y luego restar un día de él.
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)
PS: Este código se ejecuta más rápido en comparación con el enfoque import calendar
; ver a continuación:
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 DD, sino toda la fecha AAAAMMDD)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-28 19:39:53
Puede calcular la fecha de finalización usted mismo. la lógica simple es restar un día de la start_date 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
Llamando,
end_date_of_a_month(datetime.datetime.now().date())
Devolverá la fecha final de este mes. Pase cualquier fecha a esta función. devuelve la fecha final de ese mes.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-02 08:47:11
Esto no aborda la pregunta principal, pero un buen truco para obtener el último día de la semana en un mes es usar calendar.monthcalendar
, que devuelve una matriz de fechas, organizada con el lunes como primera columna hasta el domingo como ú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 lo [0:-2]
es afeitar las columnas de fin de semana y tirarlas. Las fechas que caen fuera del mes se indican por 0, por lo que el máximo efectivamente las ignora.
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 sobre qué eje calcular.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-14 20:06:26
¡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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-24 19:59:53
Prefiero así
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)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-25 09:48:05
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 lo que sea que sea el 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á tantos días como el mes actual es. Excelente si desea verificar el último día del mes ejecutando un trabajo cron diario.
So:
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.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-16 04:51:56
Si quieres hacer tu 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 hay que conocer las reglas para los años bisiestos:
- cada cuatro años
- con la excepción de cada 100 años
- pero de nuevo cada 400 años
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-04 08:26:45
Si pasas un intervalo de fechas, puedes 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-12 16:23:30
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 lambda next_month
encuentra la representación de la tupla del primer día del mes siguiente, y pasa al año siguiente. La lambda month_end
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)
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-07 22:52:09
Espero,Es útil para mucho..Pruébalo por aquí..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],
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-27 12:23:03
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)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-21 23:09:57