Datumsberechnung

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
reneschmidt
User
Beiträge: 48
Registriert: Montag 4. Januar 2016, 15:14

Hallo zusammen,

irgendwie kommt ich an folgendem Punkt nicht weiter:
Ich habe ein Datum (z.B. 15.06.2018) und davon muss ich jetzt z.B. 36 oder 40 Monate zurück gehen.
Hat jemand einen Vorschlag, wie man das am einfachsten in Python realisieren kann?

Vielen Dank im Voraus.
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Mit dem datetime Modul und seinen Klassen wie zB timedelta,das so etwas kann.
sebastian0202
User
Beiträge: 168
Registriert: Montag 9. Mai 2016, 09:14
Wohnort: Berlin

Hallo,


ich würde obige Aufgabe so erledigen:
Die Lösung fühlt sich aber nicht gut an.
Darf man Funktionen in Funktionen definieren?

Code: Alles auswählen

from datetime import datetime, timedelta
from itertools import count

def subtract_month(date, months=1):
    def february(year):
        return 29 if year%4==0 and not year%400==0 else 28
        
    def days_per_month(date):
        return {"1":31, "2":february(date.year), "3":31, "4":30, "5":31,
                "6":30, "7":31, "8":31, "9":30, "10":31, "11":30, "12":31}

    for i in count(1):
        if i > months:
            break
        period = days_per_month(date)[str(date.month)]
        date = date - timedelta(days=period)
    return date


if __name__ == '__main__':
    date = datetime(2020,3,29,6,30)

    for i in range(1,13):
        print subtract_month(date, i)
'''
2020-02-27 06:30:00
2020-01-29 06:30:00
2019-12-29 06:30:00
2019-11-28 06:30:00
2019-10-29 06:30:00
2019-09-28 06:30:00
2019-08-29 06:30:00
2019-07-29 06:30:00
2019-06-28 06:30:00
2019-05-29 06:30:00
2019-04-28 06:30:00
2019-03-29 06:30:00
'''
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@sebastian0202: Deine Schaltjahrberechnung ist falsch. Ansonsten gibt es das alles schon im calendar-Modul. Ein `count` mit einem break, falls der Wert größer als eine bestimmte Grenze wird, ist eigentlich ein `range`. Warum benutzt Du für die Monatsnummer einen String? Wäre es nicht einfacher, Monat und Jahr separat auszurechnen und den Tag aus dem ursprünglichen Datum zu nehmen?

Code: Alles auswählen

>>> import datetime
>>> date = datetime.datetime.now()
>>> y, m = divmod(date.year*12+date.month - 21, 12)
>>> date.replace(year=y, month=m)
datetime.datetime(2016, 6, 19, 11, 11, 48, 413895)
narpfel
User
Beiträge: 643
Registriert: Freitag 20. Oktober 2017, 16:10

@Sirius3: Man kann den Tag nicht aus dem ursprünglichen Datum nehmen, weil nicht alle Tage in allen Monaten existieren:

Code: Alles auswählen

In [18]: date = datetime.datetime(2018, 3, 31)

In [19]: date.replace(month=2)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-19-6ef8040186bb> in <module>()
----> 1 date.replace(month=2)

ValueError: day is out of range for month
@reneschmidt: Ob man jetzt mit `replace` die Jahre und Monate ändert oder `timedelta`s (bzw. Tage) aufsummiert, hängt so ein bisschen davon ab, was „ein Monat“ für dich ist. Was ist ein Monat vor dem 29. März? Der 28./29. Februar? 31 Tage früher? Vier Wochen früher? Was ist mit Sommer- und Winterzeit? Schaltsekunden? Diese Fragen müsstest du (für dich) beantworten.
sebastian0202
User
Beiträge: 168
Registriert: Montag 9. Mai 2016, 09:14
Wohnort: Berlin

Ja, die Schaltjahrberechnung ist falsch. Habe die Sache mit den 100 Jahren unter den Tisch fallen lassen.
Hab jetzt mit 'Calendar' einen kürzeren Code. Der wird aber für viele Durchläufe sicher uneffizient sein.

Code: Alles auswählen

from calendar import monthrange
from datetime import datetime, timedelta
...
def schaltjahr(jahr):
    return 28 if jahr%100==0 and not jahr%400==0 else (29 if jahr%4==0 else 28)
...
def subtract_month(date, months=1):
    for _ in range(months):
        date -= timedelta (days=monthrange(date.year,date.month)[1])
    return date

if __name__ == '__main__':
    date = datetime(2018,03,31)
    print subtract_month(date, 37)
'''
2015-02-28 00:00:00
'''
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Es gibt schon calendar.isleap() zur Ermittlung eines Schaltjahrs...
Antworten