Hilfe berechnen Millisekunden

  • Excel

Es gibt 12 Antworten in diesem Thema. Der letzte Beitrag () ist von petaod.

    Hilfe berechnen Millisekunden

    Hallo Spezialisten. Jetzt muss ich doch mal nachfragen weil ich es ums verrecken nicht hinbekomme.
    Ich habe mir auf paulblaes.de/tool.html
    das Tool für die Zeiterfassung heruntergeladen. Jetzt möchte ich jedoch dass die Zeiten nicht nur auf Sekunden dargestellt bzw. berechnet werden, sondern auch mit Millisekunden.

    Ich habe jetzt 3 Tage damit zu gebracht irgend einen Weg zu finden mit den Millisekunden zu rechnen, und zwar so dass vba auch weis dass es sich hier um eine Zeit handelt. Das scheint mir nahezu unmöglich zu sein.

    Hier mal der Ausschnitt der mir als ausschlaggebend erscheint.

    Visual Basic-Quellcode

    1. '##############################################################
    2. '# Wechsel, Werte eintragen #
    3. '##############################################################
    4. Public Sub wechsel(wechsel_team As Integer, wechsel_derz_runde As Integer)
    5. '# Variablen
    6. Dim jetzt As Date
    7. Dim differenz_sekunden As Long
    8. Dim stunden As Long
    9. Dim minuten As Long
    10. Dim sekunden As Long
    11. Dim zeile, spalte As Integer
    12. Dim zaehler, x, cT As Integer
    13. '# Timer in Millisekunden stoppen und Rundenzeit ermitteln
    14. EndTimer = Timer
    15. rundenzeit = Format(EndTimer - StartTimer, "00:00:00.000")
    16. '# Uhrzeit ermitteln
    17. jetzt = Now()
    18. '# Zeit des letzten Fahrers ermitteln
    19. differenz_sekunden = DateDiff("s", ergebnis_startuhrzeit(wechsel_team, derz_runde(wechsel_team)), jetzt)
    20. stunden = Int(differenz_sekunden / 3600) '# HIER BRAUCHT ES MILLISEKUNDEN
    21. minuten = Int((differenz_sekunden - stunden * 3600) / 60)
    22. sekunden = differenz_sekunden - stunden * 3600 - minuten * 60
    23. ergebnis_rundenzeit(wechsel_team, derz_runde(wechsel_team)) = Format(Str(stunden) + ":" + Str(minuten) + ":" + Str(sekunden), "long time")
    24. '# kurzlösung funktioniert für die erste befüllung. Aber weitere Berechnung lassen sich nicht ausführen. Z.B.: (Rundenzeit1 + Rundenzeit2) / 2 um Durchschnitt zu berechnen
    25. ' ergebnis_rundenzeit(wechsel_team, derz_runde(wechsel_team)) = rundenzeit
    26. '# Variablenwerte neu setzen
    27. derz_runde(wechsel_team) = derz_runde(wechsel_team) + 1
    28. ergebnis_startuhrzeit(wechsel_team, derz_runde(wechsel_team)) = jetzt
    29. '# Uhrzeit ermitteln
    30. Sheets(name_rennen).Select
    31. Sheets(name_rennen).Range("d88").Activate
    32. spalte = wechsel_team * 11 - 11
    33. zeile = wechsel_derz_runde * 3 - 5
    34. ActiveCell.Offset(zeile, spalte).Activate
    35. ActiveCell.Value = ergebnis_rundenzeit(wechsel_team, derz_runde(wechsel_team) - 1)
    36. ActiveCell.Offset(4, 0).Activate
    37. ActiveCell.Value = Format(ergebnis_startuhrzeit(wechsel_team, derz_runde(wechsel_team)), "dd.mm.yyyy hh:mm:ss")
    38. '# Cursor nach oben setzen
    39. Sheets(name_rennen).Range("c3").Activate


    Ich habe schon einen Timer eingebaut der mir vergangene Zeit mit Millisekunden zurück gibt. Nur leider kann keine weitere Berechnung damit stattfinden. z.B.: Runde 1 addiert Runde 2 geteilt durch 2 um den Durchschnitt zu berechnen. Für den Durchschnitt benötige ich eben auch die Millisekunden.

    Ich hoffe Ihr könnt mir etwas helfen.
    Gruß Kay
    nochmal ein ganz kurzes Beispiel was ich möchte.

    Visual Basic-Quellcode

    1. Public startzeit
    2. Public endzeit
    3. Public rundenzeit
    4. Private Sub test()
    5. startzeit = Format(Now(), "hh:mm:ss.000")
    6. endzeit = Format(Now(), "hh:mm:ss.000")
    7. rundenzeit = Format(endzeit - startzeit, "hh:mm:ss.000")
    8. End Sub


    Ich möchte die Rundenzeit mit ms zurück haben. VBA sagt aber immer "Typen unverträglich"
    Wie du vielleicht schon bemerkt hast, können die Date/Time-Funktionen von Excel keine Millisekunden.
    Excel interpretiert deine Zeiten als String und die kannst du nicht voneinander subtrahieren.

    Mein Vorschlag wäre wie hier ein benutzerdefinierten Typ zu erstellen, der Millisekunden handhaben kann.

    Spoiler anzeigen

    Ich habe die Hours als Long deklariert, damit man mit mehr als 9 Stunden rechnen kann.

    Visual Basic-Quellcode

    1. Option Explicit
    2. Type TimeType
    3. Hours As Long
    4. Minutes As Integer
    5. Seconds As Integer
    6. Milliseconds As Integer
    7. End Type
    8. Sub CalcTimeDifference()
    9. Dim sTime1 As String
    10. Dim sTime2 As String
    11. Dim aDT As Variant
    12. Dim udtTime1 As TimeType
    13. Dim udtTime2 As TimeType
    14. Dim TimeInterval As Double
    15. Dim sUnits As String
    16. Dim FormatString As String
    17. sTime1 = ActiveSheet.Cells(1, 2).Value 'Get time 1 from worksheet
    18. sTime2 = ActiveSheet.Cells(2, 2).Value 'Get time 2 from worksheet
    19. aDT = Split(sTime1, " ") 'Separate date / time substrings
    20. udtTime1 = TimeTypeFromString(aDT(UBound(aDT))) 'Get time components from time portion of aDT
    21. aDT = Split(sTime2, " ")
    22. udtTime2 = TimeTypeFromString(aDT(UBound(aDT)))
    23. TimeInterval = TimeDifference(udtTime2, udtTime1) 'Compute difference in seconds
    24. If TimeInterval < 1 Then
    25. TimeInterval = TimeInterval * 1000
    26. sUnits = "milliseconds"
    27. FormatString = "####"
    28. Else
    29. sUnits = "seconds"
    30. FormatString = "##.####"
    31. End If
    32. MsgBox "Time Interval (" & sUnits & ") = " & Format(TimeInterval, FormatString)
    33. End Sub
    34. Function TimeTypeFromString(ByVal T As String) As TimeType
    35. ' Parses a time string with format HH:MM:SS.nnn
    36. ' Returns time components as the user-defined type TimeType (Hours/Minutes/Seconds/Milliseconds)
    37. Dim Pos As Integer
    38. Dim udtTemp As TimeType
    39. Dim Intervals As Variant
    40. Dim NumOfIntervals As Integer
    41. With udtTemp
    42. Pos = InStr(1, T, ".", vbBinaryCompare)
    43. If Pos > 0 Then
    44. .Milliseconds = CInt(Mid$(T, Pos + 1))
    45. T = Left$(T, Pos - 1)
    46. End If
    47. If Len(T) <> 0 Then
    48. Intervals = Split(T, ":")
    49. NumOfIntervals = UBound(Intervals) - LBound(Intervals) + 1
    50. Select Case NumOfIntervals
    51. Case 1
    52. .Seconds = CInt(Intervals(0))
    53. Case 2
    54. .Minutes = CInt(Intervals(0))
    55. .Seconds = CInt(Intervals(1))
    56. Case 3
    57. .Hours = CInt(Intervals(0))
    58. .Minutes = CInt(Intervals(1))
    59. .Seconds = CInt(Intervals(2))
    60. End Select
    61. End If
    62. End With
    63. TimeTypeFromString = udtTemp
    64. End Function
    65. Function TimeDifference(ByRef T1 As TimeType, ByRef T2 As TimeType) As Double
    66. ' Computes the difference of T1 - T2
    67. ' T1 and T2 are user-defined Type TimeType (Hours/Minutes/Seconds/Milliseconds)
    68. Dim Time1 As Double
    69. Dim Time2 As Double
    70. With T1
    71. Time1 = .Hours * 60 * 60 + .Minutes * 60 + .Seconds + .Milliseconds / 1000
    72. End With
    73. With T2
    74. Time2 = .Hours * 60 * 60 + .Minutes * 60 + .Seconds + .Milliseconds / 1000
    75. End With
    76. TimeDifference = Time1 - Time2
    77. End Function
    Wenn du mit tausendstel Sekunden rechnen willst, musst du einen Datentyp verwenden, der das unterstützt.
    ​Date tut das schon mal nicht in VBA.
    Die noch größere Herausforderung dürfte die Ermittlung der Messwerte sein.
    Now() gibt nämlich auch nur sekundengenaue Zeit zurück.
    Wenn du kleinere Einheiten benötigst, dann nimm die API-Funktion GetTickCount.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    Ich kann mir schon die Millisekunden wiedergeben lassen

    Visual Basic-Quellcode

    1. Dim StartTimer as Variant
    2. ​StartTimer = Format(Now(), "hh:mm:ss.000")


    Aber wie Henry schon schrieb ist dies keine verwertbare Variable. Auch GetTickCount habe ich schon probiert. Das Problem ist sicher nicht die Millisekunden zu bekommen, sondern diese mit einem richtigen "Date" zu verrechnen.

    Ich werde am Nachmittag mal Henry seine Lösung nehmen. Das kannte ich so noch nicht.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Kaypetri“ ()

    Kaypetri schrieb:

    StartTimer = Format(Now(), "hh:mm:ss.000")
    wird immer 0 Millisekunden zurückgeben.
    Wenn du's nicht glaubst:

    Visual Basic-Quellcode

    1. For i = 1 To 100
    2. Debug.Print Format(Now(), "hh:mm:ss.000")
    3. Next


    Um die Rundenzeit zu ermitteln, benötigst du doch gar keine absolute Uhrzeit.
    Falls doch, kannst du sie informativ sekundengenau ausgeben.
    Aber zur Berechnung kannst du nur die TickCount-Informationen nehmen.
    Du kannst sie auch nicht kombinieren (ms von TickCount an Uhrzeit anfügen), da TickCount nicht zur vollen Sekunde startet.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „petaod“ ()

    Stimmt. Ich rechne mir die Differenz halt gerade so aus:

    Visual Basic-Quellcode

    1. rundenzeit = Format(EndTimer - StartTimer, "00:00:00.000")

    EndTimer und StartTimer sind jeweils als Timer deklariert.
    Aber wie schon gesagt das kann ich nicht weiter in Berechnungen verarbeiten.

    Evtl. kannst Du mir kurz erläutern wie ich denn mit GettickCount das lösen kann.
    Ich bekomme auch bei dieser Variante maximal die Sekunden zurück, aber nicht die Millisekunden.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Kaypetri“ ()

    Wie oben bereits erwähnt kann ich mit Timer nicht weiter rechnen. Es geht mir im Kern nicht um die einzelne Rundenzeit, sondern darum die einzelnen Zeiten mehrerer Runden im Durchschnitt zu berechnen. Timer gibt mir zwar die korrekte differenz, aber ich kann z.B.: nicht zwei timer addieren und dann teilen. Es sind damit keine weiteren Operationen möglich. Das ist es was ich brauche.
    aber ich kann z.B.: nicht zwei timer addieren und dann teilen.


    Visual Basic-Quellcode

    1. Sub test()
    2. Dim rz1 As Double, rz2 As Double, rz3 As Double
    3. Dim Durchschnitt As String, dz As Double
    4. rz1 = 3.444 ' Ergebnis 1. Runde
    5. rz2 = 1.008 ' Ergebnis 2. Runde
    6. rz3 = 2.1 ' Ergebnis 3. Runde
    7. dz = (rz1 + rz2 + rz3) / 3
    8. MsgBox "Durchnittliche Rundenzeit: " & Format$(dz, "#####0.000") & " Sekunden"
    9. End Sub
    Ok. Also es nützt nix. Ich bekomme es in oben genannter Excel nicht hin. Das ist alles so verschachtelt, dass ein umbau mit millisekunden für mich schlichtweg nicht machbar ist.
    Einzeln und für sich gedacht bekomme ich es hin. In der Excel jedoch kommt es immerwieder zu "Überlagerung" Typen unverträglich usw.

    Problem scheint mir nach wie vor dass man auf eine ganz normale Zeit 00:00:00 keine timer sekunden z.B.:1,234 dazu addieren kann, so dass man später 00:00:01,234 erhält.
    Ok. Also es hat mir keine Ruhe gelassen. Ich habe jetzt den ganzen Tag investiert und den code durchgeackert und das Problem soweit gelöst.
    Im Grunde berechne ich die Millisekunden nun parallel zu den eigentlichen Minuten und Sekunden. Zu jeder Auswertung wandel ich die Zeit in Sekunden um, Runde diese ab und addiere dann die mitgerechneten Millisekunden.
    Danach addiere ich die Sekunden (Rundenzeiten) und ermittel den Durchschnitt. Den Durchschnitt wandel ich dann wieder in ein Zeitformat um. Dazu Splitte ich die Millisekunden erstmal raus und gebe diese als String dann später wieder der Zeit hinzu.

    Es ist gut möglich das dies jetzt keiner Verstanden hat, aber mit etwas Split, Aplication.RoundDown und Timer hat es letztlich geklappt.
    Die eleganteste Methode wäre gewesen, am Anfang die Uhrzeit und den TickCount auszulesen und den Rest nur mit TickCount zu machen.
    Wenn du zwischendrin die Uhrzeit anzeigen willst, einfach die TickCount-Differenz zur Anfangsuhrzeit addieren.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --