Frage

Gibt es eine Möglichkeit, die Standardbibliothek von Python zu verwenden, um einfach zu bestimmen (d. h.ein Funktionsaufruf) am letzten Tag eines bestimmten Monats?

Wenn die Standardbibliothek dies nicht unterstützt, unterstützt das dateutil-Paket dies?

War es hilfreich?

Lösung

Das ist mir vorher nicht aufgefallen, als ich mir das angeschaut habe Dokumentation zum Kalendermodul, sondern eine Methode namens Monatsbereich stellt diese Informationen bereit:

Monatsbereich (Jahr, Monat)
Gibt den Wochentag des ersten Tages des Monats und die Anzahl der Tage im Monat für das angegebene Jahr und den angegebenen Monat zurück.

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

Also:

calendar.monthrange(year, month)[1]

scheint der einfachste Weg zu sein.

Nur um das klar zu stellen, monthrange unterstützt auch Schaltjahre:

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

Meine vorherige Antwort Funktioniert immer noch, ist aber eindeutig suboptimal.

Andere Tipps

Wenn Sie das nicht importieren möchten calendar Modul kann eine einfache zweistufige Funktion auch sein:

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)

Ausgänge:

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

BEARBEITEN:Eine sauberere Lösung finden Sie in der Antwort von @Blair Conrad


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

BEARBEITEN:sehen meine andere Antwort.Es hat eine bessere Implementierung als diese, die ich hier belasse, nur für den Fall, dass jemand daran interessiert ist, zu sehen, wie man seinen eigenen Rechner „rollen“ kann.

@John Millikin gibt eine gute Antwort, mit der zusätzlichen Komplikation, den ersten Tag des nächsten Monats zu berechnen.

Das Folgende ist nicht besonders elegant, aber um den letzten Tag des Monats herauszufinden, in dem ein bestimmtes Datum liegt, könnten Sie Folgendes versuchen:

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)

Das geht eigentlich ganz einfach dateutil.relativedelta (Paket python-datetutil für pip). day=31 wird immer den letzten Tag des Monats zurückgeben.

Beispiel:

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)

Benutzen relativedelta Sie würden das letzte Datum des Monats wie folgt erhalten:

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

Die Idee besteht darin, den ersten Tag des Monats zu erhalten und zu verwenden relativedelta um einen Monat vorwärts und einen Tag zurück zu gehen, damit Sie den letzten Tag des gewünschten Monats erhalten.

Eine andere Lösung wäre, so etwas zu tun:

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

Und verwenden Sie die Funktion wie folgt:

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

Wenn Sie bereit sind, eine externe Bibliothek zu nutzen, schauen Sie vorbei http://crsmithdev.com/arrow/

Sie können dann den letzten Tag des Monats erhalten mit:

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

Dadurch wird ein Datumsobjekt zurückgegeben, das Sie dann bearbeiten können.

Um das letzte Datum des Monats zu erhalten, gehen wir folgendermaßen vor:

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

Um nun zu erklären, was wir hier tun, teilen wir es in zwei Teile auf:

Zuerst wird die Anzahl der Tage des aktuellen Monats ermittelt, für die wir verwenden Monatsbereich Blair Conrad hat seine Lösung bereits erwähnt:

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

Zweitens erhalten wir das letzte Datum selbst, mit dessen Hilfe wir es tun ersetzen z.B

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

und wenn wir sie wie oben erwähnt kombinieren, erhalten wir eine dynamische Lösung.

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)

Für mich ist es der einfachste Weg:

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)

Der einfachste Weg (ohne den Kalender importieren zu müssen) besteht darin, den ersten Tag des nächsten Monats zu ermitteln und dann einen Tag davon abzuziehen.

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

Ausgabe:

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

PS: Dieser Code läuft schneller als der import calendarAnsatz;siehe unten:

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)

AUSGABE:

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

Bei diesem Code wird davon ausgegangen, dass Sie das Datum des letzten Tages des Monats wünschen (d. h. nicht nur den TT-Teil, sondern das gesamte JJJJMMTT-Datum).

In Python 3.7 gibt es die Undokumentierten calendar.monthlen(year, month) Funktion:

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

Es ist gleichbedeutend mit das dokumentierte calendar.monthrange(year, month)[1] Anruf.

Sie können das Enddatum selbst berechnen.Die einfache Logik besteht darin, einen Tag vom Startdatum des nächsten Monats abzuziehen.:) :)

Schreiben Sie also eine benutzerdefinierte Methode,

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

Berufung,

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

Es wird das Enddatum dieses Monats zurückgegeben.Übergeben Sie ein beliebiges Datum an diese Funktion.gibt Ihnen das Enddatum dieses Monats zurück.

Hier ist eine weitere Antwort.Keine zusätzlichen Pakete erforderlich.

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

Holen Sie sich den ersten Tag des nächsten Monats und subtrahieren Sie einen Tag davon.

Dies beantwortet nicht die Hauptfrage, sondern einen netten Trick, um die letzte Frage zu beantworten Wochentag in einem monat ist zu verwenden calendar.monthcalendar, das eine Datumsmatrix zurückgibt, die mit Montag als erster Spalte und Sonntag als letzter Spalte organisiert ist.

# 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

Das Ganze [0:-2] Die Sache ist, die Wochenendkolumnen abzuschneiden und wegzuwerfen.Daten, die außerhalb des Monats liegen, werden mit 0 angezeigt, sodass sie vom Maximum effektiv ignoriert werden.

Die Verwendung von numpy.ravel ist nicht unbedingt notwendig, aber ich hasse es, mich darauf zu verlassen bloße Konvention Das numpy.ndarray.max Reduziert das Array, wenn nicht angegeben wird, über welche Achse berechnet werden soll.

Benutze 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

Ich bevorzuge diesen Weg

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)

Wenn Sie Ihre eigene kleine Funktion erstellen möchten, ist dies ein guter Ausgangspunkt:

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

Dazu muss man die Regeln für die Schaltjahre kennen:

  • alle vier Jahre
  • mit Ausnahme aller 100 Jahre
  • aber alle 400 Jahre erneut

Sie können relativedelta verwendenhttps://dateutil.readthedocs.io/en/stable/relativedelta.html month_end = <your datetime value within the month> + relativedelta(day=31) Das wird dir den letzten Tag bescheren.

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

Ausgabe:

31



Dadurch wird der letzte Tag des aktuellen Monats gedruckt.In diesem Beispiel war es der 15. Mai 2016.Ihre Ausgabe kann also unterschiedlich sein, die Ausgabe umfasst jedoch so viele Tage wie der aktuelle Monat.Ideal, wenn Sie den letzten Tag des Monats überprüfen möchten, indem Sie täglich einen Cronjob ausführen.

Also:

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

Ausgabe:

False

Es sei denn, es ist der letzte Tag des Monats.

Wenn Sie einen Datumsbereich übergeben, können Sie Folgendes verwenden:

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

Im Code unten 'get_last_day_of_month(dt)' erhalten Sie dies mit einem Datum im Zeichenfolgenformat wie „JJJJ-MM-TT“.

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 )

Hier ist eine Lösung basierend auf 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)

Der next_month Lambda findet die Tupeldarstellung des ersten Tages des nächsten Monats und führt einen Rollover auf das nächste Jahr durch.Der month_end Lambda transformiert ein Datum (dte) auf ein Tupel gilt next_month und erstellt einen neuen Termin.Dann ist das „Monatsende“ nur der erste Minustag des nächsten Monats timedelta(days=1).

Ich hoffe, es ist sehr nützlich. Versuchen Sie es auf diese Weise. Wir müssen ein Paket importieren

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

ich habe eine einfache Lösung:

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)
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top