Millisekunden ermitteln und ausdrücken...

  • Hallo Fachleute,

    ich will für mein Projekt den Zeitpunkt eines Ereignisses bis auf die Hundertstel Sekunde genau loggen:

    Code
    $var=@MDAY & "." & @MON & "." & @YEAR & " " & @HOUR & ":" & @MIN & ":" & @SEC

    Das bringt mich ja nun schon ziemlich weit, nur fehlt mir in dieser Notierung so etwas wie

    Code
    $var=@MDAY & "." & @MON & "." & @YEAR & " " & @HOUR & ":" & @MIN & ":" & @SEC & "," & $MSec

    wobei "$MSec" eine dreistellige Zahl hinter dem Komma und die Hundertstel Sekunden zum Zeitpunkt des Ereignisses repräsentieren soll.

    Mein Problem ist nun: Wie ermittele ich diese Millisekunden mit AutoIt, und wie gestalte ich den Ausdruck am besten?

    Vielen Dank bereits für weitaus qualifiziertere Antworten, als es meine zur Zeit sind :( .

    2 Mal editiert, zuletzt von Argonaut (9. Oktober 2007 um 17:17)

    • Offizieller Beitrag

    Hi,
    also jede Milisekunde kannst du nicht erwischen. Weil ja schon Zeit verstreicht zur Befehlsausführung. Außerdem müßtest du dann eine Schleife ohne Sleep laufen lassen und hättest 100% CPU-Last. ;)

    Ich habe hier eine Variante mit einem Sleep von 10. Wenn du die Werte in die Konsole ausgibst, siehst du dass die kürzeste Zeitdifferenz bei etwa 2-3 /10 Sekunden liegt.
    Ich hoffe diese Genauigkeit ist ausreichend.

    Spoiler anzeigen
    [autoit]

    #include <GUIConstants.au3>
    Opt("GUIOnEventMode", 1)
    $Form1 = GUICreate("Form1", 427, 223, -1, -1)
    GUISetOnEvent($GUI_EVENT_CLOSE, "Form1Close")
    $Label1 = GUICtrlCreateLabel("Zeit: ", 60, 58, 295, 17)
    GUISetState(@SW_SHOW)
    $hundertstel_Sec = 0
    $diff = 0
    $start = TimerInit()

    [/autoit] [autoit][/autoit] [autoit]

    While 1
    Sleep(10)
    $diff = TimerDiff($start)
    $hundertstel_Sec = StringRight('00' & $diff, 3)
    If $diff >= 1000 Then $start = TimerInit()
    GUICtrlSetData($Label1, "Zeit: " & @HOUR & ':' & @MIN & ':' & @SEC & ',' & $hundertstel_Sec & @CRLF)
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Func Form1Close()
    Exit
    EndFunc

    [/autoit]
    • Offizieller Beitrag

    Hi,

    [autoit]

    While 1
    ToolTip(@Hour & ':' & @Min & ':' & @Sec & ':' & _MSec())
    Sleep(1)
    WEnd
    Exit

    [/autoit][autoit][/autoit][autoit]

    Func _MSec()
    Local $stSystemTime = DllStructCreate('ushort;ushort;ushort;ushort;ushort;ushort;ushort;ushort')
    DllCall('kernel32.dll', 'none', 'GetSystemTime', 'ptr', DllStructGetPtr($stSystemTime))
    $sMilliSeconds = StringFormat('%03d', DllStructGetData($stSystemTime, 8))
    $stSystemTime = 0
    Return $sMilliSeconds
    EndFunc

    [/autoit]

    So long,

    Mega

  • BugFix , Xenobiologist,

    danke für die beiden Lösungen - das sind mal zwei richtig g**** Counter!

    Am ehesten gefällt mir die Lösung von Xenobiologist, weil dort die Systemzeit ziemlich nahe nach dem Funktionsaufruf "gestoppt", und anschließend weiterverarbeitet und zurückgeliefert wird. D. h. der "Verlust" von Millisekunden hält sich nach meinem Verständnis vom Funktionsaufruf bis zur Feststellung in Grenzen - Weiterverarbeitung und die Rückgabe der Werte spielen eigentlich keine Rolle, da Zeitnah am Ereignis "gestoppt" wurde, und die Wiedergabe der Zeit-Werte für meine Zwecke nur nominell ist.

    Ich hab's ein wenig umgebastelt, so dass es für mich passt:

    [autoit][/autoit][autoit][/autoit][autoit]

    #include <GUIConstants.au3>

    [/autoit][autoit][/autoit][autoit]

    Global $stSystemTime = DllStructCreate('ushort;ushort;ushort;ushort;ushort;ushort;ushort;ushort')

    [/autoit][autoit][/autoit][autoit]

    $GUI = GUICreate("Form1", 200, 200, -1, -1)
    $btn = GUICtrlCreateButton("Stop", 10, 10, 180, 180)
    GUISetState(@SW_SHOW, $GUI)

    [/autoit][autoit][/autoit][autoit]

    While 1
    $msg = GUIGetMsg(1)
    Select
    Case $msg[0] = $GUI_EVENT_CLOSE And $msg[1] = $GUI
    ExitLoop

    Case $msg[0] = $btn AND $msg[1] = $GUI
    GUICtrlSetData($btn, @Hour & ':' & @Min & ':' & @Sec & ',' & PerfectTimeStamp())

    [/autoit][autoit][/autoit][autoit]

    EndSelect
    WEnd

    Func PerfectTimeStamp()
    DllCall('kernel32.dll', 'none', 'GetSystemTime', 'ptr', DllStructGetPtr($stSystemTime))
    $sMilliSeconds = StringFormat('%03d', DllStructGetData($stSystemTime, 8))
    Return $sMilliSeconds
    EndFunc

    [/autoit][autoit][/autoit][autoit][/autoit]

    Wenn's jetzt jemand "noch näher am Ereignis" schafft, wäre es nur noch genauer.

    Danke auf jeden Fall für Eure Antworten - das Licht wird immer heller 8)

    Einmal editiert, zuletzt von Argonaut (9. Oktober 2007 um 22:04)

  • Also viel genauer würde ich es mit Hilfe der DLL nicht mehr hinbekommen:

    Spoiler anzeigen
    [autoit]

    Opt("GUIOnEventMode", 1)

    [/autoit] [autoit][/autoit] [autoit]

    Global $stSystemTime = DllStructCreate('ushort;ushort;ushort;ushort;ushort;ushort;ushort;ushort')
    Global $DLL = DllOpen('kernel32.dll')

    [/autoit] [autoit][/autoit] [autoit]

    $GUI = GUICreate("Form1", 200, 200)
    GUISetOnEvent(-3, "_Leave")

    [/autoit] [autoit][/autoit] [autoit]

    $btn = GUICtrlCreateButton("Stop", 10, 10, 180, 180)
    GUICtrlSetOnEvent($btn, "_Button")

    [/autoit] [autoit][/autoit] [autoit]

    GUISetState()

    While 1
    Sleep(100)
    WEnd

    Func PerfectTimeStamp()
    DllCall($DLL , 'none', 'GetSystemTime', 'ptr', DllStructGetPtr($stSystemTime))
    return DllStructGetData($stSystemTime, 8)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Leave()
    DllClose($DLL)
    Exit
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Button()
    GUICtrlSetData($btn, @Hour & ':' & @Min & ':' & @Sec & ',' & PerfectTimeStamp())
    EndFunc

    [/autoit]

    Hab auch auf die 3-Stellenausgabe der Millisekunden verzichtet.
    Zumindestens sollte es denke ich für den Fall besser sein die GUI im OnEventMode zu betreiben statt im Message-Loop da dabei ja auch erst Zeit durch die GuiGetMsg-Funktion und die Select-Anweisung verstreicht bevor die Funktion aufgerufen werden kann.

  • Hallo Argonaut.

    Also wenn Du nun mit den Zeiten bzw. den Zeitunterschieden arbeiten möchtest, dann schreibe die Zeiten jeweils in eine Dateizeile und lese diese dann wieder aus. Das ganze meine ich ist am einfachsten, wenn Du alles in eine INI-Datei schreibst und aus der wiederum auch ausließt. Aber ich weiß nicht genau, ob Du eigenjtlich mit den Zeitunterschieden arbeiten möchtest.

    Gruß, Lina.

    Lieben Gruß,
    Alina

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Geheime Information: ;)
    OuBVU5ebLhHu5QvlnAyQB4A7SzBrvWulwL7RLl2BdH5tI6sIYspeMKeXMSXl

  • Hallo @ AspirinJunkie, Alina

    Danke für Eure Lösungen und Bemühungen - mein Durchblick wird dadurch nur immer besser :D.

    AspirinJunkie

    $me = "AutoIt- und sonstiger Programmiersprachen-Anfänger"

    D. h. ich habe bisher noch nie mit dem OnEventMode gearbeitet, begreife jedoch anhand Deines Beispiels, dass der Zeitstempel eines Ereignisses noch einen Tick genauer am Ereignis selber liegen müsste, als bei meiner letzten Lösung. Ich danke Dir für diesen Hinweis.

    Ich schau mal, ob ich das für meine Zwecke nicht generell einmal komplett umstellen kann.

    @ Alina

    Ich möchte (bisher) nicht mit den Zeitunterschieden (also: Zeitraum von - bis ) iarbeiten, sondern primär (erst einmal) mit einem möglichst genauen Zeitstempel für eine Loging-Funktion.

    Mein Projekt beschäftigt sich damit, u. a. verschiedene Ereignisse, die mir eine installierte CAPI2032.dll meldet, in AutoIt-Funktionen umzusetzen. Gleichzeitig will ich den Zeitpunkt dieser Ereignisse mitloggen.

    Bisher habe ich es so vorgesehen, dass alle Ereignisse in einer Schleife abgefragt werden. Ändert sich ein Zustand, und wird dieses durch die AutoIt-Anwendung registriert, soll ein Zeitstempel gesetzt werden, der in der darauf folgenden Log-Funktion Verwendung findet.

    Ich weiss auch, dass ich vor dem Problem stehe, dass mit diesem Zeitstempel nicht der Zeitpunkt des Ereignisses selber gemessen wird, sondern vielmehr der Zeitpunkt, an welchem

    a) meine Schleife an der Anweisung zur Abfrage eines bestimmten Ereiginisses angekommen ist, und

    b) diese Anweisung einen bestimmten Zustand feststellt, der

    c) erst die Funktion mit der Anweisung aufruft, die den Zeitstempel generiert.

    Auch wenn ich damit eine Verzögerung vom Ereignis bis zur Messung erhalte, so reicht es mir bereits aus, wenn ich eine Lösung finde, die einen Zeitstempel möglichst nahe am Ereignis setzt.

    Der "normale Zeitstempel", den ich mit den AutoIt-Makros hinbekomme, ist jedoch "nur" sekundengenau, was der Grund für diesen Thread ist:

    [autoit]

    $var=@MDAY & "." & @MON & "." & @YEAR & " " & @HOUR & ":" & @MIN & ":" & @SEC

    [/autoit]

    D. h. wenn mir die CAPI kurz hintereinander innerhalb einer Sekunde verschiedene Ereignisse meldet (bzw. meine Schleife stellt innerhalb einer Sekunde verschiedene Ereignisse fest), kann ich mit dieser Methode im Log lediglich die Reihenfolge der Ereignisse erkennen - das Log würde mir jedoch mehrere Ereignisse mit dem gleichen Zeitstempel anzeigen. Und das ist ausdrücklich nicht so gewünscht (auch wenn ich bereits damit ganz gut leben könnte).

    Die Verwendung der Makros jedoch verzögert die Geschichte jedoch auch nur wieder, denn $var enthält ja Ausdrücke, die - ähnlich einer Funktion - vor der Darstellung des Inhalts erst einmal ausgeführt werden müssen, um den Inhalt darstellen zu können.

    Ich denke daher, dass ich auch erst einmal heraus finden muss, wie ich mit der kernel32.dll die Systemzeit ermitteln, und dann am besten daraus eine Anweisung machen kann, die anhand des ermittelten System-Zeitstempels mir das Format dd.mm.yyyy hh:mm:ss,ms(1/100) ausrechnen und zurückgeben kann.

    Vielen Dank auf jeden Fall für alles!