Ich habe den folgenden Code, um dies zu tun, aber wie kann ich es besser machen? Im Moment denke ich, dass es besser ist als verschachtelte Schleifen, aber es fängt an, Perl-Einzeiler zu werden, wenn Sie einen Generator in einem Listenverständnis haben.
day_count = (end_date - start_date).days + 1
for single_date in [d for d in (start_date + timedelta(n) for n in range(day_count)) if d <= end_date]:
print strftime("%Y-%m-%d", single_date.timetuple())
Anmerkungen
Ich benutze das eigentlich nicht zum Drucken. Das ist nur zu Demozwecken.
Das start_date und end_date Variablen sind datetime.date Objekte, da ich die Zeitstempel nicht benötige. (Sie werden verwendet, um einen Bericht zu erstellen).
Beispielausgabe
Für ein Startdatum von 2009-05-30 und ein Enddatum von 2009-06-09:
Nur um darauf hinzuweisen: Ich glaube nicht, dass es einen Unterschied zwischen ‘time.strftime(“%Y-%m-%d”, single_date.timetuple())’ und dem kürzeren ‘single_date.strftime(“%Y-% m-%d”)’. Die meisten Antworten scheinen den längeren Stil zu kopieren.
– Mu Geist
21. September 2010 um 13:20 Uhr
Wow, diese Antworten sind viel zu kompliziert. Versuchen Sie Folgendes: stackoverflow.com/questions/7274267/…
– Gringo Suave
19. September 2012 um 19:47 Uhr
@GringoSuave: Was ist kompliziert an Sean Cavanaghs Antwort?
– jfs
24. April 2015 um 0:30 Uhr
Anwendung: Cheat auf GitHub Streaks: stackoverflow.com/questions/20099235/…
– Ciro Santilli Путлер Капут 六四事
6. Dezember 2015 um 9:47 Uhr
@GringoSuave Dieser Link ist ein Duplikat von: stackoverflow.com/questions/1060279/…
– Blairg23
19. April 2017 um 17:52 Uhr
Ber
Warum gibt es zwei verschachtelte Iterationen? Für mich erzeugt es die gleiche Liste von Daten mit nur einer Iteration:
for single_date in (start_date + timedelta(n) for n in range(day_count)):
print ...
Und es wird keine Liste gespeichert, es wird nur über einen Generator iteriert. Auch das “if” im Generator scheint unnötig zu sein.
Schließlich sollte eine lineare Sequenz nur einen Iterator benötigen, nicht zwei.
Update nach Diskussion mit John Machin:
Die vielleicht eleganteste Lösung ist die Verwendung einer Generatorfunktion, um die Iteration über den Datumsbereich vollständig auszublenden/zu abstrahieren:
from datetime import date, timedelta
def daterange(start_date, end_date):
for n in range(int((end_date - start_date).days)):
yield start_date + timedelta(n)
start_date = date(2013, 1, 1)
end_date = date(2015, 6, 2)
for single_date in daterange(start_date, end_date):
print(single_date.strftime("%Y-%m-%d"))
NB: Für die Konsistenz mit dem eingebauten range() Funktion stoppt diese Iteration Vor Erreichen der end_date. Verwenden Sie also für die inklusive Iteration am nächsten Tag, wie Sie es mit tun würden range().
@ John Machin: Okay. Ich bevorzuge jedoch eine Iteration über While-Schleifen mit expliziter Inkrementierung eines Zählers oder Werts. Das Interationsmuster ist pythonischer (zumindest aus meiner persönlichen Sicht) und auch allgemeiner, da es ermöglicht, eine Iteration auszudrücken, während die Details, wie diese Iteration durchgeführt wird, verborgen werden.
– Ber
30. Juni 2009 um 9:57 Uhr
@Ber: Ich mag es überhaupt nicht; es ist DOPPELT schlecht. Sie hatten BEREITS eine Iteration! Indem Sie die beanstandeten Konstrukte in einen Generator packen, haben Sie noch mehr Ausführungsaufwand hinzugefügt und die Aufmerksamkeit des Benutzers auf etwas anderes gelenkt, um den Code und/oder die Dokumentation Ihres Dreizeilers zu lesen. -2
– John Machin
30. Juni 2009 um 10:36 Uhr
@John Machin: Ich bin anderer Meinung. Es geht nicht darum, die Anzahl der Zeilen auf das absolute Minimum zu reduzieren. Schließlich sprechen wir hier nicht von Perl. Außerdem macht mein Code nur eine Iteration (so funktioniert der Generator, aber ich denke, das wissen Sie). *** Mein Punkt ist das Abstrahieren von Konzepten für die Wiederverwendung und selbsterklärenden Code. Ich behaupte, dass dies weitaus lohnender ist, als einen möglichst kurzen Code zu haben.
– Ber
30. Juni 2009 um 10:58 Uhr
Wenn Sie auf Knappheit aus sind, können Sie einen Generatorausdruck verwenden: (start_date + datetime.timedelta(n) for n in range((end_date - start_date).days))
– Markieren Sie Lösegeld
3. April 2012 um 19:35 Uhr
for n in range(int ((end_date - start_date).days+1)): Damit das Enddatum enthalten ist
from datetime import date
from dateutil.rrule import rrule, DAILY
a = date(2009, 5, 30)
b = date(2009, 6, 9)
for dt in rrule(DAILY, dtstart=a, until=b):
print dt.strftime("%Y-%m-%d")
Diese Python-Bibliothek hat viele weitere erweiterte Funktionen, von denen einige sehr nützlich sind, wie z relative deltas – und wird als einzelne Datei (Modul) implementiert, die einfach in ein Projekt eingebunden werden kann.
Beachten Sie, dass das letzte Datum in der for-Schleife hier ist inklusive von until während das endgültige Datum der daterange Methode in Bers Antwort ist exklusiv von end_date.
Die Stärke von Pandas sind wirklich seine Datenrahmen, die vektorisierte Operationen (ähnlich wie numpy) unterstützen, die Operationen über große Datenmengen hinweg sehr schnell und einfach machen.
EDIT: Sie könnten die for-Schleife auch komplett überspringen und direkt drucken, was einfacher und effizienter ist:
print(daterange)
import datetime
def daterange(start, stop, step=datetime.timedelta(days=1), inclusive=False):
# inclusive=False to behave like range by default
if step.days > 0:
while start < stop:
yield start
start = start + step
# not +=! don't modify object passed in if it's mutable
# since this function is not restricted to
# only types from datetime module
elif step.days < 0:
while start > stop:
yield start
start = start + step
if inclusive and start == stop:
yield start
# ...
for date in daterange(start_date, end_date, inclusive=True):
print strftime("%Y-%m-%d", date.timetuple())
Diese Funktion leistet mehr als Sie unbedingt benötigen, indem sie negative Schritte usw. unterstützt. Solange Sie Ihre Bereichslogik ausklammern, benötigen Sie die separate Funktion nicht day_count und vor allem wird der Code leichter lesbar, wenn Sie die Funktion von mehreren Stellen aus aufrufen.
Danke, umbenannt, um den Parametern des Bereichs besser zu entsprechen, vergessen, den Körper zu ändern.
– Roger Pate
29. Juni 2009 um 20:56 Uhr
+1 … aber da Sie zulassen, dass der Schritt ein Zeitdelta ist, sollten Sie ihn entweder (a) dateTIMErange() nennen und Schritte von zB timedelta(hours=12) und timedelta(hours=36) richtig funktionieren lassen oder ( b) Schritte abfangen, die keine ganze Zahl von Tagen sind, oder (c) dem Anrufer den Ärger ersparen und den Schritt als Anzahl von Tagen anstelle eines Zeitdeltas ausdrücken.
– John Machin
30. Juni 2009 um 11:57 Uhr
Jedes timedelta sollte bereits funktionieren, aber ich habe datetime_range und date_range zu meiner persönlichen Schrottsammlung hinzugefügt, nachdem ich dies geschrieben habe, wegen (a). Ich bin mir nicht sicher, ob sich eine andere Funktion für (c) lohnt, der häufigste Fall von Tagen = 1 ist bereits erledigt, und die Übergabe eines expliziten Zeitdeltas vermeidet Verwirrung. Vielleicht ist es am besten, es irgendwo hochzuladen: bitbucket.org/kniht/scraps/src/tip/python/gen_range.py
– Roger Pate
30. Juni 2009 um 20:49 Uhr
Damit dies an anderen Inkrementen als Tagen funktioniert, sollten Sie mit step.total_seconds() und nicht mit step.days prüfen
– Amohr
11. Mai 2016 um 5:37 Uhr
Patrick
Dies ist die menschenlesbarste Lösung, die ich mir vorstellen kann.
Danke, umbenannt, um den Parametern des Bereichs besser zu entsprechen, vergessen, den Körper zu ändern.
– Roger Pate
29. Juni 2009 um 20:56 Uhr
+1 … aber da Sie zulassen, dass der Schritt ein Zeitdelta ist, sollten Sie ihn entweder (a) dateTIMErange() nennen und Schritte von zB timedelta(hours=12) und timedelta(hours=36) richtig funktionieren lassen oder ( b) Schritte abfangen, die keine ganze Zahl von Tagen sind, oder (c) dem Anrufer den Ärger ersparen und den Schritt als Anzahl von Tagen anstelle eines Zeitdeltas ausdrücken.
– John Machin
30. Juni 2009 um 11:57 Uhr
Jedes timedelta sollte bereits funktionieren, aber ich habe datetime_range und date_range zu meiner persönlichen Schrottsammlung hinzugefügt, nachdem ich dies geschrieben habe, wegen (a). Ich bin mir nicht sicher, ob sich eine andere Funktion für (c) lohnt, der häufigste Fall von Tagen = 1 ist bereits erledigt, und die Übergabe eines expliziten Zeitdeltas vermeidet Verwirrung. Vielleicht ist es am besten, es irgendwo hochzuladen: bitbucket.org/kniht/scraps/src/tip/python/gen_range.py
– Roger Pate
30. Juni 2009 um 20:49 Uhr
Damit dies an anderen Inkrementen als Tagen funktioniert, sollten Sie mit step.total_seconds() und nicht mit step.days prüfen
– Amohr
11. Mai 2016 um 5:37 Uhr
Numpys arange Funktion kann auf Daten angewendet werden:
Die Verwendung von astype ist von umzuwandeln numpy.datetime64 zu einer Reihe von datetime.datetime Objekte.
Super schlanke Bauweise! Die letzte Zeile funktioniert bei mir mit dates = np.arange(d0, d1, dt).astype(datetime.datetime)
– pyano
9. August 2017 um 7:11 Uhr
+1 für die Veröffentlichung einer generischen Einzeiler-Lösung, die ein beliebiges Zeitdelta zulässt, anstelle eines festen gerundeten Schritts wie stündlich/minütlich/… .
– F.Raab
29. August 2018 um 16:39 Uhr
11151600cookie-checkDurchlaufen einer Reihe von Daten in Pythonyes
Nur um darauf hinzuweisen: Ich glaube nicht, dass es einen Unterschied zwischen ‘time.strftime(“%Y-%m-%d”, single_date.timetuple())’ und dem kürzeren ‘single_date.strftime(“%Y-% m-%d”)’. Die meisten Antworten scheinen den längeren Stil zu kopieren.
– Mu Geist
21. September 2010 um 13:20 Uhr
Wow, diese Antworten sind viel zu kompliziert. Versuchen Sie Folgendes: stackoverflow.com/questions/7274267/…
– Gringo Suave
19. September 2012 um 19:47 Uhr
@GringoSuave: Was ist kompliziert an Sean Cavanaghs Antwort?
– jfs
24. April 2015 um 0:30 Uhr
Anwendung: Cheat auf GitHub Streaks: stackoverflow.com/questions/20099235/…
– Ciro Santilli Путлер Капут 六四事
6. Dezember 2015 um 9:47 Uhr
@GringoSuave Dieser Link ist ein Duplikat von: stackoverflow.com/questions/1060279/…
– Blairg23
19. April 2017 um 17:52 Uhr