Letzter vorheriger Geschäftstag in Python

80

Ich muss Werktage vom aktuellen Datum abziehen .

Ich habe derzeit Code, der immer am letzten Geschäftstag ausgeführt werden muss. Das mag heute sein, wenn wir Montag bis Freitag sind, aber wenn es Samstag oder Sonntag ist, muss ich es auf den Freitag vor dem Wochenende zurücksetzen. Ich habe derzeit einen ziemlich klobigen Code, um dies zu tun:

 lastBusDay = datetime.datetime.today()
 if datetime.date.weekday(lastBusDay) == 5:      #if it's Saturday
     lastBusDay = lastBusDay - datetime.timedelta(days = 1) #then make it Friday
 elif datetime.date.weekday(lastBusDay) == 6:      #if it's Sunday
     lastBusDay = lastBusDay - datetime.timedelta(days = 2); #then make it Friday

Gibt es einen besseren Weg?

Kann ich timedelta anweisen, beispielsweise an Wochentagen anstatt an Kalendertagen zu arbeiten?

Thomas Browne
quelle
7
Was ist mit Urlaub?
SLaks
Hier ist ein Ausschnitt von dzzone, der Ihnen helfen könnte: snippets.dzone.com/posts/show/9173
David Underhill
Ja, ich kümmere mich bereits um diese: Meine Datenbank füllt Feiertage immer wieder auf, solange sie auf einen Wochentag fallen. Aber ich stimme zu, Urlaub im Allgemeinen ist auch ein Thema. Ich meine, ich könnte Lust bekommen und die sckits.timeseries verwenden, aber ich möchte wirklich etwas Einfacheres.
Thomas Browne
1
Hallo, ich bin zu spät zur Party, sorry. Eine einfachere Sache, die OP hätte tun können, ist zu prüfen, ob datetime.date.weekday (lastBusDay)> = 5 ist, anstatt Samstag und Sonntag getrennt zu prüfen. aber ja ... es gibt sowieso andere bessere Antworten unten.
Tagoma

Antworten:

141

Benutze Pandas!

import datetime
# BDay is business day, not birthday...
from pandas.tseries.offsets import BDay

today = datetime.datetime.today()
print(today - BDay(4))

Da heute Donnerstag, der 26. September, ist, erhalten Sie eine Ausgabe von:

datetime.datetime(2013, 9, 20, 14, 8, 4, 89761)
Kyle Hannon
quelle
2
Nett. Das ist heute die richtige Antwort. Als ich das Q fragte, waren die Pandas noch etwas unvollständig.
Thomas Browne
6
Die neueste Pandas-Version (0.14.0) unterstützt auch Feiertagskalender
fantastisch
1
Durch die Installation von Pandas werden 233 MB zu vps hinzugefügt. Also habe ich ein Barebone-Rad neu erfunden.
Stuart Gathman
13

Es scheint mehrere Optionen zu geben, wenn Sie zusätzliche Bibliotheken installieren möchten.

Dieser Beitrag beschreibt eine Möglichkeit, Arbeitstage mit dateutil zu definieren .

http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-09/3758.html

Mit BusinessHours können Sie Ihre Liste der Feiertage usw. individuell definieren, um festzulegen, wann Ihre Arbeitszeiten (und damit auch die Arbeitstage) sind.

http://pypi.python.org/pypi/BusinessHours/

Alison R.
quelle
nette Alison. Trotzdem leider nicht sehr einfach. Ich werde aber deinen Weg gehen. Danke für die Hilfe.
Thomas Browne
2
Es ist unwahrscheinlich, dass das Definieren von Geschäftstagen in allen Kulturen so einfach ist, dass es in die Standardbibliothek aufgenommen werden kann.
Alison R.
2
Ein gültiger Punkt, da meine Bewerbung tatsächlich für die Finanzmärkte gilt und Ägypten und Israel am Sonntag geöffnet sind.
Thomas Browne
2
Verwendet jemand BuinessHours? Innerhalb von 1 Minute entdeckte ich, dass Zeile 87 lesen sollte self.worktiming[1](fehlendes Selbst ) und Zeile 51 lesen sollte extradays(fehlendes s ). Der Quellcode selbst sieht ziemlich schlecht aus, mit Semikolons, die überall verteilt sind.
Pakman
11

Vielleicht könnte dieser Code helfen:

lastBusDay = datetime.datetime.today()
shift = datetime.timedelta(max(1,(lastBusDay.weekday() + 6) % 7 - 3))
lastBusDay = lastBusDay - shift

Die Idee ist, dass Sie montags 3 Tage zurückgehen müssen, sonntags 2 und an jedem anderen Tag 1.

Die Aussage (lastBusDay.weekday() + 6) % 7basiert nur auf dem Montag von 0 bis 6.

Ich weiß wirklich nicht, ob dies in Bezug auf die Leistung besser sein wird.

TMC
quelle
11

Wenn Sie sowohl US-Feiertage als auch Wochenenden überspringen möchten, hat dies bei mir funktioniert (mit Pandas 0.23.3):

import pandas as pd
from pandas.tseries.holiday import USFederalHolidayCalendar
from pandas.tseries.offsets import CustomBusinessDay
US_BUSINESS_DAY = CustomBusinessDay(calendar=USFederalHolidayCalendar())
july_5 = pd.datetime(2018, 7, 5)
result = july_5 - 2 * US_BUSINESS_DAY # 2018-7-2

Um in ein Python-Datumsobjekt zu konvertieren, habe ich Folgendes getan:

result.to_pydatetime().date()
lakenen
quelle
10

DISCLAMER: Ich bin der Autor ...

Ich habe ein Paket geschrieben, das genau dies tut, Berechnungen von Geschäftsterminen. Sie können benutzerdefinierte Wochenspezifikationen und Feiertage verwenden.

Ich hatte genau dieses Problem bei der Arbeit mit Finanzdaten und fand keine der verfügbaren Lösungen besonders einfach, also schrieb ich eine.

Hoffe das ist nützlich für andere Leute.

https://pypi.python.org/pypi/business_calendar/

antoniobotelho
quelle
1
Vielen Dank, Ihre Bibliothek hat perfekt für mich funktioniert. Vielleicht sollten Sie auf Ihre Dokumentation hinzufügen , dass Ihre Bibliothek Unterstützung negativen Tage , wenn Sie Tage subtrahieren wollen, und dass es auf pip up
guinunez
Hey, ich weiß, dass dies möglicherweise nicht der beste Weg ist, Sie zu erreichen, aber ich wollte nur ein Problem melden, das ich mit Ihrem business_calendar-Modul hatte. Ich habe einen Kalender mit US-Bundesfeiertagen erstellt: ['2015-01-01', '2015-01-19', '2015-02-16', '2015-05-25', '2015-07-03' , '2015-09-07', '2015-10-12', '2015-11-11', '2015-11-26', '2015-12-25'] versuchte dann, die Differenz zwischen Datum und Uhrzeit zu berechnen ( 2015, 1, 16, 15, 28, 40) und datetime (2015, 1, 23, 11, 58, 0), aber es wird konsistent -1 zurückgegeben. Das Entfernen der h / m / s von den Datumsangaben führt (korrekt) zu 4.
Darren Ringer
1
Tatsächlich blockieren bestimmte Datumsvergleiche bei weiteren Tests nur ohne ersichtlichen Grund und scheinen niemals ein Ergebnis zu liefern. In meinem obigen Beispiel führt der Versuch, datetime (2015, 1, 16) mit datetime (2015, 1, 25) zu vergleichen, zu einem solchen Block mit oder ohne explizite Festlegung von Feiertagen. Bei der Untersuchung tritt dies auf, wenn der Parameter date2 zufällig ein Datum ist, das kein Arbeitstag ist.
Darren Ringer
6

timeboard Paket macht das.

Angenommen, Ihr Datum ist der 04. September 2017. Obwohl es ein Montag war, war es ein Feiertag in den USA (der Tag der Arbeit). Der letzte Geschäftstag war also Freitag, der 1. September.

>>> import timeboard.calendars.US as US
>>> clnd = US.Weekly8x5()
>>> clnd('04 Sep 2017').rollback().to_timestamp().date()
datetime.date(2017, 9, 1)

In Großbritannien war der 04. September 2017 der reguläre Geschäftstag, daher war der letzte Geschäftstag selbst.

>>> import timeboard.calendars.UK as UK
>>> clnd = UK.Weekly8x5()
>>> clnd('04 Sep 2017').rollback().to_timestamp().date()
datetime.date(2017, 9, 4)

HAFTUNGSAUSSCHLUSS: Ich bin der Autor von Timeboard.

Maxim Mamaev
quelle
2

Dies gibt einen Generator von Arbeitstagen, natürlich ohne Feiertage, Stopp ist datetime.datetime Objekt. Wenn Sie Urlaub brauchen, machen Sie einfach ein zusätzliches Argument mit der Liste der Feiertage und überprüfen Sie mit 'IFology' ;-)

def workingdays(stop, start=datetime.date.today()):
    while start != stop:
        if start.weekday() < 5:
            yield start
        start += datetime.timedelta(1)

Später können Sie sie wie zählen

workdays = workingdays(datetime.datetime(2015, 8, 8))
len(list(workdays))
mastier
quelle
2

Wenn jemand nach einer Lösung für Feiertage sucht (ohne eine riesige Bibliothek wie Pandas), probieren Sie seine Funktionen aus:

import holidays
import datetime


def previous_working_day(check_day_, holidays=holidays.US()):
    offset = max(1, (check_day_.weekday() + 6) % 7 - 3)
    most_recent = check_day_ - datetime.timedelta(offset)
    if most_recent not in holidays:
        return most_recent
    else:
        return previous_working_day(most_recent, holidays)

check_day = datetime.date(2020, 12, 28)
previous_working_day(check_day)

welche produzieren:

datetime.date(2020, 12, 24)
ZdPo Ster
quelle
0

Warum versuchst du nicht so etwas wie:

lastBusDay = datetime.datetime.today()
if datetime.date.weekday(lastBusDay) not in range(0,5):
    lastBusDay = 5
ValentinS
quelle
0
 def getNthBusinessDay(startDate, businessDaysInBetween):
    currentDate = startDate
    daysToAdd = businessDaysInBetween
    while daysToAdd > 0:
        currentDate += relativedelta(days=1)
        day = currentDate.weekday()
        if day < 5:
            daysToAdd -= 1

    return currentDate 
Der Mann
quelle
0

eine andere vereinfachende Version

lastBusDay = datetime.datetime.today()
wk_day = datetime.date.weekday(lastBusDay)
if wk_day > 4:      #if it's Saturday or Sunday
    lastBusDay = lastBusDay - datetime.timedelta(days = wk_day-4) #then make it Friday
CircleOnCircles
quelle
0

Lösung unabhängig von unterschiedlichen Gerichtsbarkeiten mit unterschiedlichen Feiertagen:

Wenn Sie die richtige ID in einer Tabelle finden müssen, können Sie dieses Snippet verwenden. Das Tabellenmodell ist ein SQLalchemiemodell, und die zu suchenden Daten befinden sich am Feldtag.

def last_relevant_date(db: Session, given_date: date) -> int:
    available_days = (db.query(Table.id, Table.day)
                      .order_by(desc(Table.day))
                      .limit(100).all())
    close_dates = pd.DataFrame(available_days)
    close_dates['delta'] = close_dates['day'] - given_date
    past_dates = (close_dates
                  .loc[close_dates['delta'] < pd.Timedelta(0, unit='d')])
    table_id = int(past_dates.loc[past_dates['delta'].idxmax()]['id'])
    return table_id

Dies ist keine Lösung, die ich empfehlen würde, wenn Sie in großen Mengen konvertieren müssen. Es ist ziemlich allgemein und teuer, da Sie keine Joins verwenden. Darüber hinaus wird davon ausgegangen, dass Sie einen relevanten Tag haben, der einer der 100 letzten Tage in der Modelltabelle ist. Es werden also Dateneingaben behandelt, die unterschiedliche Daten haben können.

Patrick
quelle