Pregunta

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

Si la biblioteca estándar no es compatible con ese, ¿el dateutil el paquete de compatibilidad de esto?

¿Fue útil?

Solución

No me di cuenta de esto antes, cuando yo estaba buscando en el documentación para el módulo 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 en el mes, para el año y el mes.

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

así:

calendar.monthrange(year, month)[1]

parece que la forma más sencilla de ir.

Para ser claros, monthrange soporta los años bisiestos así:

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

Mi respuesta anterior todavía funciona, pero es claramente deficiente.

Otros consejos

Si usted no desea importar el calendar módulo, en dos simples pasos función 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:Ver a @Blair Conrad respuesta para una solución de limpieza


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

EDITAR:ver mi otra respuesta.Tiene una mejor aplicación de la presente, que os dejo aquí por si alguien está interesado en ver cómo se puede "rodar sus propios" de la calculadora.

@Juan Millikin da una buena respuesta, con la complicación añadida de calcular el primer día del mes siguiente.

La siguiente no es muy elegante, pero a la figura hacia fuera el último día del mes en que la fecha que vive en el, 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)

Esto es en realidad 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)

El uso de relativedelta usted podría obtener el último día del mes como este:

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

La idea es conseguir el primer día del mes y el uso de relativedelta ir 1 mes adelantado y 1 día atrás para que usted obtendría el último día del mes en que usted quería.

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 el uso de la función 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)
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 usted está dispuesto a utilizar una biblioteca externa, echa un vistazo 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 date que usted 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í vamos a dividirlo en dos partes:

primero es obtener el número de días del mes en curso para los que usamos monthrange que Blair Conrad ha mencionado ya su solución:

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

la segunda es llegar a la última fecha en sí mismo que hacemos con la ayuda de reemplazar e.g

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

y cuando combinamos ellos, como se menciona en la parte superior tenemos 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 sencilla (sin necesidad de importar calendario), es conseguir el primer día del mes siguiente, y luego restar un día de ella.

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 import calendarenfoque;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 la fecha del último día del mes (es decir, no sólo el DD parte, sino la totalidad de la AAAAMMDD fecha)

En Python 3.7 hay los indocumentados calendar.monthlen(year, month) la función:

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

Es equivalente a el documentado calendar.monthrange(year, month)[1] llame.

Se puede calcular la fecha de finalización de sí mismo.la simple lógica es restar un día de la start_date del próximo mes.:)

Para escribir 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())

Se devolverá a la fecha de finalización de este mes.Pase ninguna fecha para esta función.devuelve la fecha final de ese mes.

Aquí hay otra respuesta.Ningún paquete adicional que se requiera.

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

Conseguir el primer día del mes siguiente y restar un día de ella.

Esto no abordar la cuestión principal, pero un buen truco para obtener la última día de la semana en un mes es el uso de calendar.monthcalendar, que devuelve una matriz de fechas, organizado con el lunes como el primer columna hasta el domingo como el ú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

Todo [0:-2] la cosa es que para cortar el fin de semana columnas y deshacerse de ellos.Las fechas que caen fuera de los meses indicados por 0, por lo que el máximo de eficacia ignora.

El uso de numpy.ravel no es estrictamente necesario, pero no me gusta depender de la mera convención que numpy.ndarray.max se aplana la matriz si no se dice cual es el eje para calcular más.

El uso de los 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 esta

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 usted desea hacer su propia función de los pequeños, 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 tienes que conocer las reglas para los años bisiestos:

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

usted puede utilizar relativedelta https://dateutil.readthedocs.io/en/stable/relativedelta.html month_end = <your datetime value within the month> + relativedelta(day=31) que le dan el último día.

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 es.En este ejemplo fue el 15 de Mayo de 2016.Así que su salida puede ser diferente, sin embargo el resultado será la cantidad de días que el mes actual es.Grande si usted quiere comprobar el último día del mes mediante la ejecución de un diario de trabajo cron.

Así:

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 fecha, puede utilizar 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 siguiente código 'get_last_day_of_month(dt)' le dará este, 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 )

Aquí es 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)

El next_month lambda se encuentra la tupla representación de el primer día del mes siguiente, y rollos para el año siguiente.El month_end lambda transforma una fecha (dte) a una tupla, se aplica next_month y crea una nueva fecha.A continuación, el "fin de mes" es sólo el próximo mes de la primera jornada de menos timedelta(days=1).

Espero que,Es útil para mucho..lo Intente de esta manera..debemos importar el 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 sencilla:

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)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top