meex87
Goto Top

Zeiten in .txt datei auslesen und Differenz berechnen

Hallo,

ich habe folgendes Problem:
Eine Pumpe protokolliert seine ON/OFF Zeiten in einer .txt Datei.

Sieht so aus:
001 	 09.04.2017 	 08:54 	ON 
001 	 09.04.2017 	 12:58 	OFF 
001 	 10.04.2017 	 10:11 	ON 
001 	 10.04.2017 	 14:12 	OFF 
001 	 11.04.2017 	 09:13 	ON 
001 	 11.04.2017 	 15:14 	OFF 
001 	 12.04.2017 	 10:17 	ON 
001 	 12.04.2017 	 14:23 	OFF 

Der Erste Block ist die Pumpennr. Darauf folgt Datum und Uhrzeit und eben der Status.
Die Blöcke sind mittels Tabulator getrennt. Ich hätte aber die Möglichkeit sie auch per Semikolon trennen zu lassen.

Ich möchte nun jeden Tag automatisiert die Einschaltdauer, also die Zeit zwischen ON->OFF berechnen.
Da ich gerne mit der Batch arbeite war mein erster Gedanke das ganze irgendwie auszulesen anschließend auszurechnen und dann in eine weitere .txt Datei zu speichern.
In der neuen .txt soll dann das Datum und die Einschaltdauer stehen.

Hätte das ganze gerne automatisiert, deshalb der Gedanke mit der Batch.
Ab und zu kommt es vor das die Pumpe auch am selben Tag nochmal anläuft. Also ein Datum 4mal vorkommt. :|

Jemand eine Idee ?


Vielen Dank

Content-Key: 335239

Url: https://administrator.de/contentid/335239

Ausgedruckt am: 29.03.2024 um 10:03 Uhr

Mitglied: Marabunta
Lösung Marabunta 14.04.2017 aktualisiert um 15:53:38 Uhr
Goto Top
Jetzt ists besser...

Davon ausgehend, dass es mit ON beginnt und darauf ein OFF folgt, das Datum wird hier nicht mit einbezogen.
Wenn es durch ";" getrennt ist:
001;09.04.2017;08:54;ON
001;09.04.2017;12:58;OFF
001;10.04.2017;10:11;ON
001;10.04.2017;14:12;OFF
001;11.04.2017;09:13;ON
001;11.04.2017;15:14;OFF
001;12.04.2017;10:17;ON
001;12.04.2017;14:23;OFF

$i=2
$y=4
$file="C:\test.txt"  
$Content=gc $file
$maxlines=$Content | Measure-Object -Line |select -ExpandProperty lines
$line=1
while($line+3 -lt $maxlines){
	$ON=$Content.split(";")[$i]  

	$i=$i+$y
	$OFF=$Content.split(";")[$i]  
	$i=$i+$y
	NEW-TIMESPAN -Start $ON -End $OFF |select days,hours,minutes,seconds
	$line=$line+1
}


Days Hours Minutes Seconds
---- ----- ------- -------
   0     4       4       0
   0     4       1       0
   0     6       1       0
   0     4       6       0
Mitglied: colinardo
Lösung colinardo 14.04.2017 aktualisiert um 19:37:49 Uhr
Goto Top
Servus zusammen,
mit Batch würde ich da gar nicht mehr anfangen, Powershell bietet sich hier gerade zu an.
Du kannst es von mir aus auch TAB-Delimited lassen, das lässt sich aber im folgenden Skript einfach anpassen indem man den Delimiter in der "Import-CSV-Zeile" anpasst.
# Quelldatei
$in = 'D:\pumpendaten.txt'  
# Zieldatei
$out = 'D:\pumpendaten_fertig.csv'  

if ($PSVersionTable.PSVersion.Major -lt 3){write-host "ERROR: Minimum Powershell Version 3.0 is required!" -F Yellow; return}  

# Daten importieren "Tabdelimited" einlesen 
$data = Import-CSV $in -Delimiter "`t" -Header "Pump","Date","Time","Action"  
# Datum und Zeit zu einer neuen Spalte im DateTime Format anlegen
$data = $data | select *,@{n='DateTime';e={get-date "$($_.Date) $($_.Time)"}}  
# Zeilen nach Pumpe gruppieren
$data | group Pump -PipelineVariable pump | %{
    # nach Datum(Tag) gruppieren
    $_.Group | group Date -PipelineVariable day | %{
        [timespan]$time = 0
        # Alle Zeitdifferenzen des Tages berechnen und summieren (können beliebig viele sein)
        0..(($day.Group.Count / 2)-1) | %{$time += $day.Group[($_*2+1)].DateTime - $day.Group[($_*2)].DateTime}
        # custom object mit Properties(Spalten) erstellen
        [pscustomobject]@{Pump=$pump.Name;Day=$day.Name;'Total Runtime'=$time.toString('c')}  
    }
# Export der Daten in CSV
} | export-csv $out -Delimiter ";" -NoType  
Ergebnis-CSV:
"Pump";"Day";"Total Runtime"
"001";"09.04.2017";"04:04:00"
"001";"10.04.2017";"04:01:00"
"001";"11.04.2017";"06:01:00"
"001";"12.04.2017";"04:06:00"

Bei dem Skript können auch problemlos mehrere unterschiedliche Pumpen gleichzeitig in der Datei bunt gemischt erfasst werden das stört es nicht, da die Daten jeweils erst nach PumpenNr und dann nach Datum "gruppiert" werden. Wie du die Zeit dargestellt haben willst wusste ich nicht, habe es einfach mal im Zeitformat formatiert, wenn du Minuten oder Stunden als Dezimal haben möchtest ist das auch kein Problem und ist in der Spalte des Custom-Objekts schnell angepasst.

Grüße und frohe Ostern
Uwe
Mitglied: meex87
meex87 14.04.2017 aktualisiert um 17:46:52 Uhr
Goto Top
Hallo,

vielen Dank euch beiden!
Ich sehe ich muss mich mit dieser Power-Shell mehr befassen face-smile

Ein Problem habe ich noch mit der Version von colinardo:

Ausnahme beim Aufrufen von "ToString" mit 1 Argument(en):  "Der Formatbezeichner war ungültig."  
In C:\Test\test.ps1:21 Zeichen:9
+         [pscustomobject]@{Pump=$pump.Name;Day=$day.Name;'Total Runtim ...  
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) , MethodInvocationException
    + FullyQualifiedErrorId : FormatException



Ich werde das morgen mal umsetzten!


Vielen Vielen Dank!!
face-smile
Mitglied: colinardo
colinardo 14.04.2017 aktualisiert um 19:45:32 Uhr
Goto Top
Habe den allgemeinen Formatbezeichner oben auf 'c' geändert und die Variable auf [timespan] festgelegt. Damit solltest du auf deinem System keine Probleme haben.

Trotzdem ist das nicht normal, denn laut:
https://msdn.microsoft.com/de-de/library/ee372286(v=vs.110).aspx
Wird T als Formatbezeichner ebenfalls unterstützt was bei mir hier auch problemlos funktioniert:
TimeSpan unterstützt auch die standardmäßigen "t"- und "T"-Formatzeichenfolgen, die im Verhalten identisch mit der Standardformatzeichenfolge "c" sind.
Ich vermute du verwendest einfach eine etwas ältere Powershell auf deinem System.

Natürlich kann man das Format alternativ auch manuell definieren mit:
$time.toString('hh\:mm\:ss')
etc.
Vielen Vielen Dank!!
Immer gerne.
Mitglied: meex87
meex87 15.04.2017 aktualisiert um 08:38:51 Uhr
Goto Top
Hallo,

benutze :
Version : 5.1.14393.953

Funktioniert jetzt soweit.

Gibts noch ne Möglichkeit das ganze unten zu summieren. Also die ganzen Runtime´s face-smile


Vielen Dank!!! face-smile
Mitglied: colinardo
colinardo 15.04.2017 aktualisiert um 08:52:08 Uhr
Goto Top
Zitat von @meex87:
Gibts noch ne Möglichkeit das ganze unten zu summieren. Also die ganzen Runtime´s face-smile
Klar, das hier summiert für jede Pumpennummer unter dem Block die Total-Summe der Pumpennummer, ist ja nur eine zusätzliche Variable die die Zeiten zusätzlich summiert und dann ausgibt...
# Quelldatei
$in = 'D:\pumpendaten.txt'  
# Zieldatei
$out = 'D:\pumpendaten_fertig.csv'  

if ($PSVersionTable.PSVersion.Major -lt 3){write-host "ERROR: Minimum Powershell Version 3.0 is required!" -F Yellow; return}  

# Daten importieren "Tabdelimited" einlesen 
$data = Import-CSV $in -Delimiter "`t" -Header "Pump","Date","Time","Action"  
# Datum und Zeit zu einer neuen Spalte im DateTime Format anlegen
$data = $data | select *,@{n='DateTime';e={get-date "$($_.Date) $($_.Time)"}}  
# Zeilen nach Pumpe gruppieren
$data | group Pump -PipelineVariable pump | %{
    [timespan]$pumptotal = 0
    # nach Datum(Tag) gruppieren
    $_.Group | group Date -PipelineVariable day | %{
        [timespan]$time = 0
        # Alle Zeitdifferenzen des Tages berechnen und summieren (können beliebig viele sein)
        0..(($day.Group.Count / 2)-1) | %{$time += $day.Group[($_*2+1)].DateTime - $day.Group[($_*2)].DateTime}
         $pumptotal += $time
        # custom object mit Properties(Spalten) erstellen
        [pscustomobject]@{Pump=$pump.Name;Day=$day.Name;'Total Runtime'=$time.toString('c')}  
    }
[pscustomobject]@{Pump="SUM for $($pump.Name)";Day='-------';'Total Runtime'=$pumptotal}  
# Export der Daten in CSV
} | export-csv $out -Delimiter ";" -NoType  
Mitglied: meex87
meex87 15.04.2017 um 08:53:20 Uhr
Goto Top
Hallo,

ja habe meinen oberen Post schon korrigiert face-smile
Hatte die Quelldatei mit Semikolon getrennt face-smile

Vielen Dank!
Jetzt bin ich Glücklich face-smile

Gibt es für die Powershell gute Lektüre ? Möchte mich gerne da mal einlesen.

vielen Dank

Grüße
Mitglied: colinardo
Lösung colinardo 15.04.2017 um 08:59:28 Uhr
Goto Top
Hier mal ein Paar Links ...

Die Technetlektüre bei MS direkt gibt dir ebenfalls genügend Stoff, damit habe ich es mir damals selber beigebracht.
Mitglied: meex87
meex87 15.04.2017 um 17:02:07 Uhr
Goto Top
Hallo,

noch ne Rückfrage.
Habe leider in Google und den anderen Links nicht soviel dazu gefunden.

In der "Standard" Bash habe ich ja dei Möglichkeit mit einem einfachem ">>" an einem CSV oder TXT File einfach was anzuhängen.
Also nicht zu überschreiben das wäre ja nur ">".
Gibt es hier in der Powershell auch ähnliches ?

Die Doku zum cmdlet export-csv gibt da nichts her.

Gruß
Meex
Mitglied: colinardo
colinardo 15.04.2017 aktualisiert um 17:18:44 Uhr
Goto Top
Da gibt es mehrere Möglichkeiten:
Add-Content
oder auch
Out-File mit Parameter -Append
Die Doku zum cmdlet export-csv gibt da nichts her.
Dann hast du es überlesen, Export-CSV unterstützt ebenfalls den Parameter -Append face-wink
https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powe ...

Alles natürlich via Pipe an die CMDLets übertragbar.
Mitglied: meex87
meex87 25.04.2017 um 10:28:15 Uhr
Goto Top
Hallo,

jetzt hätte ich doch noch ein paar Fragen face-smile
Folgendes:

Ganze 24 Stunden werden immer in Tagen angezeigt. Kann man hier nur Stunden anzeigen ? Also das der Stundenzähler auch über 24 Stunden hinausläuft.
Ich hätte jetzt noch gerne eine weitere Zeile die mir einen Wert abzüglich 100 Stunden anzeigt.
Meine Idee: ein zusätzliches costumobject inder ich einfach 100 Stunden mittels .addhours abziehe

[pscustomobject]@{Pump="SUM for $($pump.Name)";Day='-------';'Total Runtime'=($pumptotal).AddHours(-100)}   

Leider funktioniert das nicht so.
Wo liegt hier der Fehler ?

Vielen Dank
Mitglied: colinardo
colinardo 25.04.2017 aktualisiert um 10:42:25 Uhr
Goto Top
Wenn du dir die Member des Objekts mal angesehen hättest, hättest du diese Eigenschaft gefunden:
$pumptotal.TotalHours
face-wink
Ebenfalls hier nachzulesen
https://msdn.microsoft.com/de-de/library/system.timespan(v=vs.110).aspx
Mitglied: meex87
meex87 25.04.2017 um 11:00:31 Uhr
Goto Top
Hallo,

ok, das hätte man finden können.. :|

Zu meiner zweiten Frage:
Wie sieht es aus wenn ich 100 Stunden abziehen möchte. ein einfaches -100 funktioniert ja nicht, da er das nicht als 100 Hours ansieht.

Danke!
Mitglied: colinardo
colinardo 25.04.2017 aktualisiert um 11:19:15 Uhr
Goto Top
Doch face-smile, TotalHours ist vom Typ Double damit kannst Du ganz regulär rechnen!
$pumptotal.TotalHours - 100
Oder du Subtrahierst mit der entsprechenden Methode 4 Tage und 4 Stunden...
$pumptotal.Subtract(([timespan]"4.04:00:00"))  
Steht übrigens ebenfalls auf der oben verlinkten Seite.
Du musst hier mehr Experimentierfreude zeigen, Get-Member und format-List sind allseits deine Freunde face-wink, damit bekommst du die Infos die du brauchst.

Viel Erfolg weiterhin.
Grüße Uwe

p.s. wenn noch weitere Fragen sind bitte #PM, sonst wird das hier für andere zu unübersichtlich. Merci.