Domanda

Esiste un modo per utilizzare la libreria standard di Python per determinare facilmente (ad es.una chiamata di funzione) l'ultimo giorno di un determinato mese?

Se la libreria standard non lo supporta, il pacchetto dateutil lo supporta?

È stato utile?

Soluzione

Non l'avevo notato prima mentre stavo guardando il file documentazione per il modulo calendario, ma un metodo chiamato intervallo di mesi fornisce queste informazioni:

intervallo mese(anno, mese)
Restituisce il giorno della settimana del primo giorno del mese e il numero di giorni nel mese, per l'anno e il mese specificati.

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

COSÌ:

calendar.monthrange(year, month)[1]

sembra la strada più semplice da percorrere.

Giusto per essere chiari, monthrange supporta anche gli anni bisestili:

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

La mia risposta precedente funziona ancora, ma è chiaramente non ottimale.

Altri suggerimenti

Se non vuoi importare il file calendar module, una semplice funzione in due passaggi può anche essere:

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)

Uscite:

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

MODIFICARE:Vedi la risposta di @Blair Conrad per una soluzione più pulita


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

MODIFICARE:Vedere la mia altra risposta.Ha un'implementazione migliore di questa, che lascio qui nel caso in cui qualcuno sia interessato a vedere come si potrebbe "creare la propria" calcolatrice.

@John Millikin dà una buona risposta, con l'ulteriore complicazione di calcolare il primo giorno del mese successivo.

Quanto segue non è particolarmente elegante, ma per capire l'ultimo giorno del mese in cui si trova una data data, potresti provare:

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)

In realtà è abbastanza semplice dateutil.relativedelta (pacchetto python-datetutil per pip). day=31 tornerà sempre sempre l'ultimo giorno del mese.

Esempio:

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)

Utilizzando relativedelta otterresti l'ultima data del mese in questo modo:

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

L'idea è di ottenere il primo giorno del mese e utilizzarlo relativedelta per andare 1 mese avanti e 1 giorno indietro in modo da ottenere l'ultimo giorno del mese desiderato.

Un'altra soluzione sarebbe fare qualcosa del genere:

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

E usa la funzione in questo modo:

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

se sei disposto a utilizzare una libreria esterna, dai un'occhiata http://crsmithdev.com/arrow/

Puoi quindi ottenere l'ultimo giorno del mese con:

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

Ciò restituisce un oggetto data che puoi quindi manipolare.

Per ottenere l'ultima data del mese facciamo qualcosa del genere:

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

Ora per spiegare cosa stiamo facendo qui lo divideremo in due parti:

il primo è ottenere il numero di giorni del mese corrente per i quali utilizziamo intervallo di mesi cui Blair Conrad ha già menzionato la sua soluzione:

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

il secondo è ottenere l'ultimo appuntamento stesso, cosa che facciamo con l'aiuto di sostituire per esempio

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

e quando li combiniamo come menzionato in alto otteniamo una soluzione dinamica.

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)

Per me è il modo più semplice:

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)

Il modo più semplice (senza dover importare il calendario) è ottenere il primo giorno del mese successivo e poi sottrarre da esso un giorno.

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

Produzione:

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

PS: Questo codice viene eseguito più velocemente rispetto a import calendarapproccio;vedi sotto:

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)

PRODUZIONE:

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

Questo codice presuppone che tu voglia la data dell'ultimo giorno del mese (ovvero, non solo la parte GG, ma l'intera data AAAAMMGG)

In Python 3.7 c'è i privi di documenti calendar.monthlen(year, month) funzione:

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

È equivalente a il documentato calendar.monthrange(year, month)[1] chiamata.

Puoi calcolare tu stesso la data di fine.la logica semplice è sottrarre un giorno dalla start_date del mese successivo.:)

Quindi scrivi un metodo personalizzato,

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

chiamando,

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

Restituirà la data di fine di questo mese.Passa qualsiasi data a questa funzione.ti restituisce la data di fine di quel mese.

Ecco un'altra risposta.Non sono richiesti pacchetti aggiuntivi.

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

Ottieni il primo giorno del mese successivo e sottrai un giorno da esso.

Questo non affronta la domanda principale, ma un bel trucco per ottenere l'ultima giorno feriale in un mese è da usare calendar.monthcalendar, che restituisce una matrice di date, organizzata con lunedì come prima colonna e domenica come ultima.

# 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

Il tutto [0:-2] la cosa è eliminare le colonne del fine settimana e buttarle via.Le date che non rientrano nel mese sono indicate da 0, quindi il massimo le ignora di fatto.

L'impiego di numpy.ravel non è strettamente necessario, ma odio fare affidamento su mera convenzione Quello numpy.ndarray.max appiattirà l'array se non viene detto su quale asse calcolare.

Usa i panda!

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

Preferisco così

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)

Se vuoi creare la tua piccola funzione, questo è un buon punto di partenza:

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

Per questo devi conoscere le regole per gli anni bisestili:

  • ogni quattro anni
  • ad eccezione di ogni 100 anni
  • ma ancora una volta ogni 400 anni

puoi usare relativedeltahttps://dateutil.readthedocs.io/en/stable/relativedelta.html month_end = <your datetime value within the month> + relativedelta(day=31) che ti darà l'ultimo giorno.

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

Produzione:

31



Questo stamperà l'ultimo giorno di qualunque sia il mese corrente.In questo esempio era il 15 maggio 2016.Quindi il tuo output potrebbe essere diverso, tuttavia l'output sarà pari a tanti giorni quanti sono i giorni del mese corrente.Ottimo se vuoi controllare l'ultimo giorno del mese eseguendo un lavoro cron giornaliero.

COSÌ:

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

Produzione:

False

A meno che non sia l'ultimo giorno del mese.

Se passi in un intervallo di date, puoi utilizzare questo:

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

Nel codice qui sotto 'get_ultimo_giorno_del_mese(gg)' ti darà questo, con la data in formato stringa come 'AAAA-MM-GG'.

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 )

Ecco una soluzione lambda basata su 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)

IL next_month lambda trova la rappresentazione della tupla del primo giorno del mese successivo e passa all'anno successivo.IL month_end lambda trasforma una data (dte) a una tupla, si applica next_month e crea una nuova data.Quindi la "fine del mese" è semplicemente il primo giorno meno del mese successivo timedelta(days=1).

Spero che sia utile per molto... Provalo in questo modo... dobbiamo importare qualche pacchetto

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

ho una soluzione semplice:

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)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top