Erstellen einer Reihe von Daten in Python

374

Ich möchte eine Liste von Daten erstellen, beginnend mit heute, und eine beliebige Anzahl von Tagen zurückgehen, beispielsweise in meinem Beispiel 100 Tage. Gibt es einen besseren Weg als diesen?

import datetime

a = datetime.datetime.today()
numdays = 100
dateList = []
for x in range (0, numdays):
    dateList.append(a - datetime.timedelta(days = x))
print dateList
Thomas Browne
quelle

Antworten:

459

Etwas besser ...

base = datetime.datetime.today()
date_list = [base - datetime.timedelta(days=x) for x in range(numdays)]
S.Lott
quelle
6
Dies funktioniert nicht, wenn Sie zeitzonenbezogene Datumsangaben verwenden und sich die Sommerzeit verschiebt !!! Ich meine, wenn Sie ein Start- und Enddatum verwenden und es zwischen diesen auf diese Weise ausfüllen ...
gabn88
@ s-lott könntest du nicht einfach range(0, numdays)in diesem Fall verwenden?
Lukas Juhrich
3
Ich habe diese Methode auf eine etwas andere Weise verwendet, um Intervalle von zehn, fünf Minuten und einen Wert von +/- (in meinem Fall 30 Sekunden) zu generieren. Ich dachte nur, ich würde teilen: datetimes = [start + timedelta(seconds=x*60+randint(-30, 30)) for x in range (0, range_end*5, 5)]wo die Variablerange_end = 10
MikeyE
247

Pandas eignet sich hervorragend für Zeitreihen im Allgemeinen und bietet direkte Unterstützung für Datumsbereiche.

Zum Beispiel pd.date_range():

import pandas as pd
from datetime import datetime

datelist = pd.date_range(datetime.today(), periods=100).tolist()

Es hat auch viele Möglichkeiten, um das Leben leichter zu machen. Wenn Sie zum Beispiel nur Wochentage wollten, würden Sie einfach eintauschen bdate_range.

Siehe Dokumentation zum Datumsbereich

Darüber hinaus unterstützt es Pytz-Zeitzonen vollständig und kann die Sommer- / Herbst-Sommerzeitverschiebungen reibungslos überbrücken.

EDIT von OP:

Wenn Sie im Gegensatz zu Pandas Zeitstempeln tatsächliche Python-Daten benötigen:

import pandas as pd
from datetime import datetime

pd.date_range(end = datetime.today(), periods = 100).to_pydatetime().tolist()

#OR

pd.date_range(start="2018-09-09",end="2020-02-02")

Dies verwendet den Parameter "end", um mit der ursprünglichen Frage übereinzustimmen, aber wenn Sie absteigende Daten wünschen:

pd.date_range(datetime.today(), periods=100).to_pydatetime().tolist()
fantastisch
quelle
22
Defo die beste Antwort, wenn Pandas bereits verwendet wird. Ich würde nur hinzufügen, dass Sie den Parameter end = verwenden würden, wenn Ihre Daten gemäß dem ursprünglichen Beitrag rückwärts gehen. pd.date_range (end = pd.datetime.today (), period = 100) .tolist ()
Thomas Browne
5
Ein Problem mit diesen Methoden ist, wenn Sie den Python-Datetime-Typ benötigen ... Wenn Sie Pandas- oder Numpy-Datumsbereichsmethoden verwenden, werden Zeitstempel- und Datetime64-Typen erstellt ... Sie müssen list(map(pd.Timestamp.to_pydatetime, datelist))den Datetime-Typ zurückerhalten ...
Malik Koné
Die pandas.datetimeKlasse ist veraltet und wird in einer zukünftigen Version von Pandas entfernt. datetimeStattdessen aus dem Modul importieren.
Trenton McKinney
82

Abrufen des Datumsbereichs zwischen dem angegebenen Start- und Enddatum (optimiert für zeitliche und räumliche Komplexität):

import datetime

start = datetime.datetime.strptime("21-06-2014", "%d-%m-%Y")
end = datetime.datetime.strptime("07-07-2014", "%d-%m-%Y")
date_generated = [start + datetime.timedelta(days=x) for x in range(0, (end-start).days)]

for date in date_generated:
    print date.strftime("%d-%m-%Y")
Sandeep
quelle
6
Der erste Vorschlag ist, () anstelle von [] zu verwenden, um einen date_generator zu erhalten. In dem Sinne effizient, dass nicht die gesamte Reihe von Daten gespeichert und nur bei Bedarf generiert werden muss.
Sandeep
2
Beachten Sie, dass das Enddatum nicht generiert wird.
Thorbjørn Ravn Andersen
8
Verwenden Sie (End-Start + 1), um das Enddatum zu erhalten.
Sandeep
6
Beantwortet nicht die Frage des OP, aber das war es, wonach ich
Thierry J.
2
(end-start+1)funktioniert nicht, Sie können kein Timedelta und Int hinzufügen. Sie könnten aber verwenden (end-start).days + 1.
Stephen Paulger
44

Sie können eine Generatorfunktion schreiben, die ab heute Datumsobjekte zurückgibt:

import datetime

def date_generator():
  from_date = datetime.datetime.today()
  while True:
    yield from_date
    from_date = from_date - datetime.timedelta(days=1)

Dieser Generator gibt Daten ab heute zurück und geht einen Tag nach dem anderen zurück. So nehmen Sie die ersten 3 Termine:

>>> import itertools
>>> dates = itertools.islice(date_generator(), 3)
>>> list(dates)
[datetime.datetime(2009, 6, 14, 19, 12, 21, 703890), datetime.datetime(2009, 6, 13, 19, 12, 21, 703890), datetime.datetime(2009, 6, 12, 19, 12, 21, 703890)]

Der Vorteil dieses Ansatzes gegenüber einer Schleife oder einem Listenverständnis besteht darin, dass Sie so oft zurückgehen können, wie Sie möchten.

Bearbeiten

Eine kompaktere Version, die einen Generatorausdruck anstelle einer Funktion verwendet:

date_generator = (datetime.datetime.today() - datetime.timedelta(days=i) for i in itertools.count())

Verwendungszweck:

>>> dates = itertools.islice(date_generator, 3)
>>> list(dates)
[datetime.datetime(2009, 6, 15, 1, 32, 37, 286765), datetime.datetime(2009, 6, 14, 1, 32, 37, 286836), datetime.datetime(2009, 6, 13, 1, 32, 37, 286859)]
Ayman Hourieh
quelle
1
Generatoren sind der ideale Weg, wenn die Anzahl der Tage beliebig ist.
xssChauhan
32

Ja, erfinde das Rad neu ... suche einfach im Forum und du bekommst so etwas:

from dateutil import rrule
from datetime import datetime

list(rrule.rrule(rrule.DAILY,count=100,dtstart=datetime.now()))
BOFH
quelle
22
Benötigt labix.org/python-dateutil . Sieht gut aus, ist aber kaum eine externe Abhängigkeit wert, nur um eine Zeile zu speichern.
Beni Cherniavsky-Paskin
1
Ich kann niemandem glauben, dass die anderen Antworten sehr pythonisch sind. Während Regel ein schrecklicher Name ist, ist dieser zumindest augenschonend.
Bootscodierer
7
@ BeniCherniavsky-Paskin: Es ist sehr einfach, subtile Fehler einzuführen, während Perioden- (Kalender-) Arithmetik implementiert wird. dateutil.rruleimplementiert iCalendar RFC - es ist einfacher, Funktionen mit einem genau definierten Verhalten zu verwenden, als mehrere Implementierungen mit fast derselben Funktionalität, die sich geringfügig unterscheiden. dateutil.rruleErmöglicht die Begrenzung der Fehlerbehebung auf einen einzigen Ort.
JFS
3
@ Mark0978: rruleName ist nicht willkürlich; es ist aus dem entsprechenden rfc
jfs
1
Ja, ich habe Dateutil nicht für die unglückliche Wahl der Namen verantwortlich gemacht :-)
Bootscodierer
32

Sie können auch die Tagesordnung verwenden, um es einfacher zu machen:

def date_range(start_date, end_date):
    for ordinal in range(start_date.toordinal(), end_date.toordinal()):
        yield datetime.date.fromordinal(ordinal)

Oder wie in den Kommentaren vorgeschlagen, können Sie eine Liste wie folgt erstellen:

date_range = [
    datetime.date.fromordinal(ordinal) 
    for ordinal in range(
        start_date.toordinal(),
        end_date.toordinal(),
    )
]
Hosane
quelle
18

Aus dem Titel dieser Frage hatte ich erwartet, etwas zu finden range(), mit dem ich zwei Daten angeben und eine Liste mit allen dazwischen liegenden Daten erstellen könnte. Auf diese Weise muss man die Anzahl der Tage zwischen diesen beiden Daten nicht berechnen, wenn man es vorher nicht weiß.

Mit dem Risiko, etwas vom Thema abzukommen, erledigt dieser Einzeiler die Aufgabe:

import datetime
start_date = datetime.date(2011, 01, 01)
end_date   = datetime.date(2014, 01, 01)

dates_2011_2013 = [ start_date + datetime.timedelta(n) for n in range(int ((end_date - start_date).days))]

Alle Credits zu dieser Antwort !

Schlangenbeschwörer
quelle
1
Das ist nicht mehr ein Einzeiler als viele der anderen Antworten auf die Frage.
Thomas Browne
4
Ich habe nie so getan, als wäre dies eher ein Einzeiler als die anderen Antworten, und auch nicht, dass dies eine bessere Lösung wäre. Ich habe einen Code gezeigt, der etwas anderes macht als das, wonach Sie gefragt haben, den ich aber angesichts des Titels der Frage gerne hier gefunden hätte.
snake_charmer
11

Hier ist eine etwas andere Antwort, die auf der Antwort von S.Lott aufbaut und eine Liste von Daten zwischen zwei Daten startund enthält end. Im folgenden Beispiel von Anfang 2017 bis heute.

start = datetime.datetime(2017,1,1)
end = datetime.datetime.today()
daterange = [start + datetime.timedelta(days=x) for x in range(0, (end-start).days)]
Derek Powell
quelle
7

Eine etwas späte Antwort, die ich kenne, aber ich hatte nur das gleiche Problem und entschied, dass Pythons interne Bereichsfunktion in dieser Hinsicht etwas fehlte, also habe ich sie in einem meiner Util-Module überschrieben.

from __builtin__ import range as _range
from datetime import datetime, timedelta

def range(*args):
    if len(args) != 3:
        return _range(*args)
    start, stop, step = args
    if start < stop:
        cmp = lambda a, b: a < b
        inc = lambda a: a + step
    else:
        cmp = lambda a, b: a > b
        inc = lambda a: a - step
    output = [start]
    while cmp(start, stop):
        start = inc(start)
        output.append(start)

    return output

print range(datetime(2011, 5, 1), datetime(2011, 10, 1), timedelta(days=30))
Rob Young
quelle
1
Ich denke du willst output = []und die Zeilen in der while cmp(...)Schleife tauschen . Vergleiche range(0,10,1)und _range(0,10,1).
Sigfpe
3
Ich denke, diese Antwort wäre besser, wenn Sie die Funktion benennen würden date_range.
Brandon Bradley
7

Basierend auf Antworten habe ich mir folgendes geschrieben:

import datetime;
print [(datetime.date.today() - datetime.timedelta(days=x)).strftime('%Y-%m-%d') for x in range(-5, 0)]

Ausgabe:

['2017-12-11', '2017-12-10', '2017-12-09', '2017-12-08', '2017-12-07']

Der Unterschied ist, dass ich das dateObjekt bekomme , nicht das datetime.datetime.

wmlynarski
quelle
7

Wenn es zwei Daten gibt und Sie den Bereich benötigen, versuchen Sie es

from dateutil import rrule, parser
date1 = '1995-01-01'
date2 = '1995-02-28'
datesx = list(rrule.rrule(rrule.DAILY, dtstart=parser.parse(date1), until=parser.parse(date2)))
Nelu
quelle
5

Hier ist das Wesentliche, das ich aus meinem eigenen Code erstellt habe. Dies könnte helfen. (Ich weiß, dass die Frage zu alt ist, aber andere können sie verwenden)

https://gist.github.com/2287345

(das Gleiche unten)

import datetime
from time import mktime

def convert_date_to_datetime(date_object):
    date_tuple = date_object.timetuple()
    date_timestamp = mktime(date_tuple)
    return datetime.datetime.fromtimestamp(date_timestamp)

def date_range(how_many=7):
    for x in range(0, how_many):
        some_date = datetime.datetime.today() - datetime.timedelta(days=x)
        some_datetime = convert_date_to_datetime(some_date.date())
        yield some_datetime

def pick_two_dates(how_many=7):
    a = b = convert_date_to_datetime(datetime.datetime.now().date())
    for each_date in date_range(how_many):
        b = a
        a = each_date
        if a == b:
            continue
        yield b, a
Roopesh
quelle
4

Hier ist ein Einzeiler für Bash-Skripte, um eine Liste der Wochentage zu erhalten. Dies ist Python 3. Das Int am Ende ist die Anzahl der Tage in der Vergangenheit, die Sie möchten.

python -c "import sys,datetime; print('\n'.join([(datetime.datetime.today() - datetime.timedelta(days=x)).strftime(\"%Y/%m/%d\") for x in range(0,int(sys.argv[1])) if (datetime.datetime.today() - datetime.timedelta(days=x)).isoweekday()<6]))" 10

Hier ist eine Variante, um ein Start- (oder besser End-) Datum anzugeben

python -c "import sys,datetime; print('\n'.join([(datetime.datetime.strptime(sys.argv[1],\"%Y/%m/%d\") - datetime.timedelta(days=x)).strftime(\"%Y/%m/%d \") for x in range(0,int(sys.argv[2])) if (datetime.datetime.today() - datetime.timedelta(days=x)).isoweekday()<6]))" 2015/12/30 10

Hier ist eine Variante für beliebige Start- und Enddaten. nicht, dass dies nicht besonders effizient ist, aber es ist gut, um eine for-Schleife in ein Bash-Skript einzufügen:

python -c "import sys,datetime; print('\n'.join([(datetime.datetime.strptime(sys.argv[1],\"%Y/%m/%d\") + datetime.timedelta(days=x)).strftime(\"%Y/%m/%d\") for x in range(0,int((datetime.datetime.strptime(sys.argv[2], \"%Y/%m/%d\") - datetime.datetime.strptime(sys.argv[1], \"%Y/%m/%d\")).days)) if (datetime.datetime.strptime(sys.argv[1], \"%Y/%m/%d\") + datetime.timedelta(days=x)).isoweekday()<6]))" 2015/12/15 2015/12/30
Tim P.
quelle
Vielleicht möchten Sie Ihren Antwortbeitrag mit dem Code in Ihrem Kommentar aktualisieren. Python wird in Kommentaren verstümmelt und benötigt irgendwie die Formatierung.
Jake Bathman
3

Matplotlib verwandt

from matplotlib.dates import drange
import datetime

base = datetime.date.today()
end  = base + datetime.timedelta(days=100)
delta = datetime.timedelta(days=1)
l = drange(base, end, delta)
Milton
quelle
3

Ich weiß, dass dies beantwortet wurde, aber ich werde meine Antwort für historische Zwecke aufschreiben, und da ich denke, dass es einfach ist.

import numpy as np
import datetime as dt
listOfDates=[date for date in np.arange(firstDate,lastDate,dt.timedelta(days=x))]

Sicher, es wird nichts wie Code-Golf gewinnen, aber ich finde es elegant.

BarocliniCplusplus
quelle
Das arangemit den Schritten ist ganz nett, listOfDatesbesteht aber aus numpy datetime64 anstelle von python nativen datetimes.
F. Raab
2
Sie können jedoch verwenden np.arange(…).astype(dt.datetime), um arangenative Python datetime anstelle von numpy datetime64 zurückzugeben.
F. Raab
2

Ein weiteres Beispiel, das ausgehend von Sandeeps Antwort vorwärts oder rückwärts zählt.

from datetime import date, datetime, timedelta
from typing import Sequence
def range_of_dates(start_of_range: date, end_of_range: date) -> Sequence[date]:

    if start_of_range <= end_of_range:
        return [
            start_of_range + timedelta(days=x)
            for x in range(0, (end_of_range - start_of_range).days + 1)
        ]
    return [
        start_of_range - timedelta(days=x)
        for x in range(0, (start_of_range - end_of_range).days + 1)
    ]

start_of_range = datetime.today().date()
end_of_range = start_of_range + timedelta(days=3)
date_range = range_of_dates(start_of_range, end_of_range)
print(date_range)

gibt

[datetime.date(2019, 12, 20), datetime.date(2019, 12, 21), datetime.date(2019, 12, 22), datetime.date(2019, 12, 23)]

und

start_of_range = datetime.today().date()
end_of_range = start_of_range - timedelta(days=3)
date_range = range_of_dates(start_of_range, end_of_range)
print(date_range)

gibt

[datetime.date(2019, 12, 20), datetime.date(2019, 12, 19), datetime.date(2019, 12, 18), datetime.date(2019, 12, 17)]

Beachten Sie, dass das Startdatum in der Rücksendung enthalten ist. Wenn Sie also vier Gesamtdaten möchten, verwenden Sie timedelta(days=3)

Chad Lowe
quelle
1
from datetime import datetime, timedelta
from dateutil import parser
def getDateRange(begin, end):
    """  """
    beginDate = parser.parse(begin)
    endDate =  parser.parse(end)
    delta = endDate-beginDate
    numdays = delta.days + 1
    dayList = [datetime.strftime(beginDate + timedelta(days=x), '%Y%m%d') for x in range(0, numdays)]
    return dayList
xmduhan
quelle
1

Ein monatlicher Datumsbereichsgenerator mit datetimeund dateutil. Einfach und leicht zu verstehen:

import datetime as dt
from dateutil.relativedelta import relativedelta

def month_range(start_date, n_months):
        for m in range(n_months):
            yield start_date + relativedelta(months=+m)
Aysa
quelle
0
import datetime    
def date_generator():
    cur = base = datetime.date.today()
    end  = base + datetime.timedelta(days=100)
    delta = datetime.timedelta(days=1)
    while(end>base):
        base = base+delta
        print base

date_generator()
Sasmita
quelle
1
Er wollte zurück, nicht vorwärts. So endsollte das sein base - datetime.timedelta. Außerdem ... Warum ist diese Lösung besser als die ursprüngliche?
frarugi87
0

Aus den obigen Antworten habe ich dieses Beispiel für den Datumsgenerator erstellt

import datetime
date = datetime.datetime.now()
time = date.time()
def date_generator(date, delta):
  counter =0
  date = date - datetime.timedelta(days=delta)
  while counter <= delta:
    yield date
    date = date + datetime.timedelta(days=1)
    counter +=1

for date in date_generator(date, 30):
   if date.date() != datetime.datetime.now().date():
     start_date = datetime.datetime.combine(date, datetime.time())
     end_date = datetime.datetime.combine(date, datetime.time.max)
   else:
     start_date = datetime.datetime.combine(date, datetime.time())
     end_date = datetime.datetime.combine(date, time)
   print('start_date---->',start_date,'end_date---->',end_date)
Dimitris Kougioumtzis
quelle