Laden...

DatumsString in Timestamp umwandeln

Erstellt von TiTime vor 15 Jahren Letzter Beitrag vor 15 Jahren 1.756 Views
T
TiTime Themenstarter:in
68 Beiträge seit 2006
vor 15 Jahren
DatumsString in Timestamp umwandeln

Hi leute!
Also ich habe ein file mit folgenden Strings nach diesem Muster

"13:07:18,692"

Den will ich in einen Unix TimeStamp umwandeln. So nun gibt es verschiedene Möglichkeiten die mir einfallen die alle vielzu langsam sind, weil ich eine große Anzahl solcher Strings umwandeln muss. So dauern etwa 5000 solche Strings etwa eine halbe Minute. Das ist jedoch nur ein File und ich habe hunderte von Files zu bewältigen. Datum sollte immer das heutige sein.

Ausprobiert habe ich
1.


Regex timePattern = new Regex(@"(?<time>\d+:\d+:\d+),(?<ms>\d+));
Match m = timePattern.Match(message);
while(m.Success)
{
    string timeString = m.Groups["time"].Value + "." + m.Groups["ms"].Value;
    DateTime dt = DateTime.Parse(DateTime.Now.ToString("dd.MM.yyyy")+ " "+ timeString);
    TimeSpan ts = (dt.ToUniversalTime() - new DateTime(1970, 1, 1));
    times.Add(((long)ts.TotalSeconds)*1000+dt.Millisecond);
    m = m.NextMatch();
}


Regex timePattern = new Regex(@"(?<hh>\d+):(?<mm>\d+):(?<ss>\d+),(?<ms>\d+)", RegexOptions.IgnoreCase | RegexOptions.Singleline);
Match m = timePattern.Match(message);
while(m.Success)
{
   DateTime now = DateTime.Now;				
   int hh = int.Parse(m.Groups["hh"].Value);
	int mm = int.Parse(m.Groups["mm"].Value);
	int ss = int.Parse(m.Groups["ss"].Value);
	int ms = int.Parse(m.Groups["ms"].Value);

	DateTime dt = new DateTime(now.Year, now.Month, now.Day, hh, mm, ss, ms);
	TimeSpan ts = (dt.ToUniversalTime() - new DateTime(1970, 1, 1));
	times.Add(((long)ts.TotalSeconds)*1000+dt.Millisecond);

	m = m.NextMatch();
}

Resolution: DateTime.Parse() ist langsasm und int.Parse() ist zu langsam.
Also suche ich nach einer schnelleren Mehtode um aus den oben genannten String einen UNIX timestamp zu generieren. Entweder gibt es eine schnellere Methode einen String in einen int zu konvertieren oder eine andere orginelle Idee.

Übrigens will ich keinen unsafe code haben.

falls jemand fragt warum regex -> spielt keinen unterschied wie ich das file einlese, das ist nicht der Performance bremser.

Thx für Antworten.

S
8.746 Beiträge seit 2005
vor 15 Jahren
  1. Regex mal compiliert ausführen

  2. Parsing per Hand

Beim Parsen werden normalerweise haufenweise Prüfungen gemacht, die in deinem Fall unnötig sind, wenn du davon ausgehen kannst, dass es sich immer um ein gültiges Fomat handelt.

*EDIT*

So dauern etwa 5000 solche Strings etwa eine halbe Minute.

Hab mal deine 2. Version bei mir durchlaufen lassen:

100.000 Strings werden in 2,7 Sekunden geparst. Compiliert in 0,5 Sekunden.

656 Beiträge seit 2008
vor 15 Jahren

Vielleicht ist ein DateTime erstellen da auch schon zu viel overhead?

Im Hintergrund passiert da nämlich mehr, als man denken würde; so werden unter anderem TimeSpan.TimeToTicks, DateToTicks und diverse andere Checks ausgeführt.

Wie wärs damit?

string[] timeOrMs = timeString.Split(':', ',');
long time = (long)(int.Parse(timeOrMs[0]) * 3600 + int.Parse(timeOrMs[1]) * 60 + int.Parse(timeOrMs[2])) * 1000 + int.Parse(timeOrMs[3]);
times.Add(time);

Eventuell machts auch Sinn, hier statt einem int.Parse gleich direkt auf die Zahlenwerte zu gehen:

int Parse(string value)
{
  if (string.IsNullOrEmpty(value))
    return 0;
  int ret = 0;
  for (int i = 0; i < value.Length; i++) 
    ret += (int)('0' - value[i]) * ((value.Length - i - 1) * 10);
  return ret;
}

Nicht getestet, aber ich denke du erkennt die Intention dahinter.

Ist halt immer so ne Sache mit Performance unter Managed Umgebungen, auch wenn diese schon recht nah an native Code sind.

Gruß, BhaaL

S
8.746 Beiträge seit 2005
vor 15 Jahren

Naja, 100000 Strings in 0,5 Sekunden sind doch ordentlich.

DateTime.ParseExact() ist übrigens auch nur 50% langsamer als die 2. Regex-Lösung (compiliert).

0
767 Beiträge seit 2005
vor 15 Jahren

wenn du in ""13:07:18,692"" den "," durch "." ersetzt, kannst du TimeStamp.Parse() verwenden um den TimeStamp zu erhalten, dann brauchst du diesen nur noch mit DateTime.Now zu kombinieren.

loop:
btst #6,$bfe001
bne.s loop
rts

T
TiTime Themenstarter:in
68 Beiträge seit 2006
vor 15 Jahren

Danke für die Antworten.

@ svenson

Hab mal deine 2. Version bei mir durchlaufen lassen:

100.000 Strings werden in 2,7 Sekunden geparst. Compiliert in 0,5 Sekunden

Ich komme auf ein halbe Minute, weil die Regex auf ein über 100MB File arbeitet. Wären es nur solche Datumsformate wäre ich viel schneller. Daraus folgere ich, dass es doch die Regex prozedur ist die mich enorme Zeit kostet. Denn wie es scheint kann ich am Umwandeln etc nicht mehr viel tunen (siehe unten).

Daher werde ich mal gucken wieviel ich mit einer vorkompilierten Regex rausholen kann.

@BhaaL
Die Split Methode die du vorschlägst habe ich bisher noch nicht ausprobiert (Werde ich trotzdem mal durchprobieren) kostet im Normalfall viel Performance.

@svenson und BhaaL
Ich habe das "händische Parsen" ausprobiert in einer ganz absurden Art. Hat leider keine Verbesserung gebracht. Eigentlich sogar langsamer als int.Parse selbst. ???


Regex timePattern = new Regex(@"\[(?<time>\d+:\d+:\d+,\d+)\].+?[\f\n\r\t\v]+?Received a message", RegexOptions.IgnoreCase | RegexOptions.Singleline);
Match m = timePattern.Match(message);
while(m.Success)
{		
    string timeString = m.Groups["time"].Value;
   long x = 
	((int)timeString[0] -48)	* 36000000 
	+ ((int)timeString[1] -48)	* 3600000
	+ ((int)timeString[3] -48)	* 600000 
      + ((int)timeString[4] -48)	* 60000
	+ ((int)timeString[6] -48)	* 10000 
	+ ((int)timeString[7] -48)	* 1000
	+ ((int)timeString[9] -48)	* 100 
	+ ((int)timeString[10] -48) * 10 
	+ ((int)timeString[11] -48);
 ...
times.Add(((long)ts.TotalSeconds)*1000+ x;
}

oder auch


int hh = ((int)timeString[0] -48)* 10 + ((int)timeString[1] -48);
int mm = ((int)timeString[3] -48)* 10 + ((int)timeString[4] -48);
int ss = ((int)timeString[6] -48)* 10 + ((int)timeString[7] -48);
int ms = ((int)timeString[9] -48)* 100 + ((int)timeString[10] -48) * 10 + ((int)timeString[11] -48);
DateTime dt = new DateTime(now.Year, now.Month, now.Day, hh, mm, ss, ms)

@0815Coder
Ebenfalls das ersetzen von , durch einen Punkt kostet zuviel Performance. Im Normalfall ist ein String.Replace einer der aufwendisten Mehtoden des Strings. Und ich kann leider nur mit einem Vorscript alles ersetzen, bevor ich die Aplication starte. Werde ich mir durch den Kopf gehen lassen?
TimeStamp.Parse() ? kenne ich nicht und finde ich leider nicht.

Trotzdem danke mal für die Vorschläge.

J
3.331 Beiträge seit 2006
vor 15 Jahren

TimeStamp.Parse() ? kenne ich nicht und finde ich leider nicht.

Nanu, bei mir steht es in :rtfm: TimeSpan.Parse-Methode mit einem Beispiel und Hinweisen zur Struktur des Strings, beginnend mit:

Der s-Parameter enthält eine Zeitintervallangabe der folgenden Form:
[LR]
{ T | [T.]hh:mm[:ss[.bb]] }[LR]
Für Dich relevant ist also nur, dass ein Punkt anstelle des Kommas verlangt wird.

Jürgen

0
767 Beiträge seit 2005
vor 15 Jahren

stimmt sorry, es heisst TimeSpan.Parse(), nicht TimeStamp.Parse()

loop:
btst #6,$bfe001
bne.s loop
rts