2016-09-02 3 views
5

Gibt es eine Möglichkeit, zwei Daten ohne Aufruf von strptime jedes Mal in Python zu vergleichen? Ich bin mir sicher, dass mein Problem nicht anders ist, aber ich möchte sicherstellen, dass ich alle Optionen überprüft habe.Alternative zu Strptime zum Vergleichen von Daten?

Ich gehe durch eine sehr große Protokolldatei, jede Zeile hat ein Datum, das ich vergleichen muss, um zu sehen, ob dieses Datum im Bereich von zwei anderen Daten liegt. Ich muss jedes Datum für jede Zeile mit strptime konvertieren, was einen großen Flaschenhals verursacht;

Fri Sep 2 15:12:43 2016 output2.file 

     63518075 function calls (63517618 primitive calls) in 171.409 seconds 

    Ordered by: cumulative time 
    List reduced from 571 to 10 due to restriction <10> 

    ncalls tottime percall cumtime percall filename:lineno(function) 
     1 0.003 0.003 171.410 171.410 script.py:3(<module>) 
     1 0.429 0.429 171.367 171.367 scipt.py:1074(main) 
     1 3.357 3.357 162.009 162.009 script.py:695(get_data) 
    1569898 14.088 0.000 141.175 0.000 script.py:648(check_line) 
    1569902 6.899 0.000 71.706 0.000 {built-in method strptime} 
    1569902 31.198 0.000 64.805 0.000 /usr/lib64/python2.7/_strptime.py:295(_strptime) 
    1569876 15.324 0.000 43.170 0.000 script.py:626(dict_add) 
    4709757 23.370 0.000 23.370 0.000 {method 'strftime' of 'datetime.date' objects} 
    1569904 1.655 0.000 18.799 0.000 /usr/lib64/python2.7/_strptime.py:27(_getlang) 
    1569899 2.103 0.000 17.452 0.000 script.py:592(reverse) 

Die Daten sind wie folgt formatiert;

current_date = 01/Aug/1995:23:59:53 

Und ich vergleiche sie so;

with open(logfile) as file: 
    for line in file: 
     current_date = strptime_method(line) 
     if current_date => end_date: 
      break 

Gibt es eine Alternative, wenn es darum geht, Daten zu vergleichen?

Edit: Danke allen, insbesondere user2539738. Hier sind die Ergebnisse basierend auf seinem Vorschlag, großen Geschwindigkeitsunterschied;

Fri Sep 2 16:14:59 2016 output3.file 

     24270567 function calls (24270110 primitive calls) in 105.466 seconds 

    Ordered by: cumulative time 
    List reduced from 571 to 10 due to restriction <10> 

    ncalls tottime percall cumtime percall filename:lineno(function) 
     1 0.002 0.002 105.466 105.466 script.py:3(<module>) 
     1 0.487 0.487 105.433 105.433 script.py:1082(main) 
     1 3.159 3.159 95.861 95.861 script.py:702(get_data) 
    1569898 21.663 0.000 77.138 0.000 script.py:648(check_line) 
    1569876 14.979 0.000 43.408 0.000 script.py:626(dict_add) 
    4709757 23.865 0.000 23.865 0.000 {method 'strftime' of 'datetime.date' objects} 
    1569899 1.943 0.000 15.556 0.000 script.py:592(reverse) 
     1 0.000 0.000 9.078 9.078 script.py:1066(print_data) 
     1 0.021 0.021 9.044 9.044 script.py:1005(print_ip) 
     10 0.001 0.000 7.067 0.707 script.py:778(ip_api) 
+1

Wenn die Eingangsprotokoll Datensätze nach Datum geordnet sind, haben Sie wahrscheinlich auf jeden Protokolldatensatz nicht überprüfen um innerhalb des Datumsbereichs zu sein und kann wahrscheinlich eine binäre Suche durchführen, um die Start- und Enddatensätze für Ihren Bereich zu bestimmen. Nur Gedanken. – alecxe

+0

Was ist 'strptime_method'? Etwas von deinem eigenen Code? Verwenden Sie auch 'time' (das funktionale Modul zur Verarbeitung von Daten und Zeiten) oder' datetime' (das klassenbasierte Modul für dasselbe)? –

+1

@alecxe Das mache ich derzeit schon.Es wird von der Schleife getrennt, wenn das Datum außerhalb des Bereichs gefunden wird. Aber wenn Ihre Reichweite ziemlich groß ist, kann es zeitaufwändig sein, wie meine Ergebnisse zeigen, hauptsächlich aufgrund der Strptime-Methode in jeder Zeile, die aufgerufen wird. – user1165419

Antwort

1

ich current_date gehe davon ist ein String

zunächst eine Wörterbuch

moDict = {"Aug":8, "Jan":1} #etc 

Dann finden Sie Jahr/Monat/Tag etc

current_date = "01/Aug/1995:23:59:53" 

Yr = int(current_date[7:11]) 
Mo = moDict[(current_date[3:6])] 
Day = int(current_date[0:2]) 

m_date = datetime.datetime(Yr,Mo,Day) 

Und Sie können Verwenden Sie das, um Vergleiche zu machen

+0

Ich wäre völlig überrascht, wenn ich feststelle, dass 'strptime' das bereits intern tut. Hast du tatsächlich die Geschwindigkeit getestet? –

+0

@DavidHeyman Überprüfen Sie meine Ergebnisse – user1165419

+0

@DavidHeyman Auch wenn 'strptime' dies intern tut, muss es die Formatzeichenfolge interpretieren. Auf der anderen Seite muss es Python nicht interpretieren. :) – Kaz

1

Da Ihre Daten in einem Format mit fester Länge angezeigt werden, ist es leicht zu analysieren und Sie brauchen dazu nicht strptime. Sie können sie in die umordnen und direkt als Strings vergleichen!

mos = {'Jan': '01', 'Feb': '02', 'Mar': '03', 'Apr': '04', 'May': '05', 'Jun': '06', 'Jul': '07', 'Aug': '08', 'Sep': '09', 'Oct': '10', 'Nov': '11', 'Dec': '12'} 

def custom_to_8601(dt): 
    return dt[7:11] + '-' + mos[dt[3:6]] + '-' + dt[0:2] + 'T' + dt[12:] 

>>> custom_to_8601('01/Aug/1995:23:59:53') 
'1995-08-01T23:59:53' 

Es könnte ein wenig schneller sein join zu verwenden anstelle von String-Verkettung und die Zeichensetzung auslassen:

def comparable_date(dt): 
    return ''.join([dt[7:11], mos[dt[3:6]], dt[0:2], dt[12:]]) 

>>> comparable_date('01/Aug/1995:23:59:53') 
'1995080123:59:53' 

Lauf cProfile auf 1000000 Wiederholungen für mich produziert diese Timings:

  • custom_to_8601: 0,978 Sekunden
  • comparable_date: 0,937 Sekunden
  • ursprünglichen Code mit strptime: 15,492 Sekunden
  • eine frühere Antwort des datetime Konstruktor: 1,134 Sekunden
+0

Danke, ich werde es versuchen und auf meine Ergebnisse zurückkommen! – user1165419

Verwandte Themen