Event das anschlägt sobald sich die System-Uhrzeit ändert

  • VB.NET

Es gibt 20 Antworten in diesem Thema. Der letzte Beitrag () ist von fichz.

    Event das anschlägt sobald sich die System-Uhrzeit ändert

    yo leute,

    Ich wollte mal fragen ob wer es ein Event gibt, dass anschlägt sobald sich die Systemzeit ändert. (So in der Art wie der Filesystemwatcher bei einer Datei).
    Falls es sowas nicht gibt oder niemand kennt hab ich als Folgefrage:

    Ich könnte mir eine Klasse bastelt welche einen Timer hat der alle Sekunden nachschaut ob sich die Zeit geändert hat.
    Das Programm ist derzeit schon so komplexx, dass ich 3 Timer brauche (ja die brauche ich wirklich). Also würde ich von einem 4ten Timer der alle Sekunden nachschauen muss eher absehen.

    Ist die Performance besser wenn ich dies in einer externen (bzw. einkompellierten) dll auslagere?

    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten
    Hallo fichz,

    1. Ich glaub dir nicht das du drei Timer brauchst
    2. Timer sind sehr ungenau - somit wirst du die Sekunde nicht treffen

    Es gibt etwas das anschlägt, wenn jemand die Systemzeit ändert.

    Verwende hierfür die Windows Nachrichten und den Parameter WM_TIMECHANGE = 0x1E

    Gruss

    mikeb69
    Das ist eigentlich eine merkwürdige Frage. Du weißt, dass sich die Systemzeit ändert.
    Willst Du auf die Millisekunde wissen, wann ein Sekunden-Tik im System aufgetreten ist oder was willst Du genau erreichen?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    mikeb69 schrieb:

    Ich glaub dir nicht das du drei Timer brauchst

    In meinem Fall schon. Diese sind aber in unterschiedlich hohen Abständen -> somit kein Performance Einbruch

    mikeb69 schrieb:

    Es gibt etwas das anschlägt, wenn jemand die Systemzeit ändert.

    Verwende hierfür die Windows Nachrichten und den Parameter WM_TIMECHANGE = 0x1E

    Naja es ändert leider niemand die Systemzeit ansich. Es soll abgefragt werden ob sich die Systemzeit ändert (Minutenabständen)

    RodFromGermany schrieb:

    Willst Du auf die Millisekunde wissen, wann ein Sekunden-Tik im System aufgetreten ist oder was willst Du genau erreichen?


    Ich schildere am besten mal genrell das Problem was entsteht.
    Es ist ein Scheduler welcher Minutenweise abfragt ob ein Job ansteht und diesen dann ausführt. Gewisse Jobs werden nur 1 mal am Tag ausgeführt (zB. 23:00 Uhr)
    Der Job wird auch ausgeführt aber nur dann wenn das Programm lauft. Wenn der PC nun ausfällt oder abgeschalten ist wird er nicht ausgeführt.
    Es wird Minutenweise eben abgefragt ob der Job gestartet werden soll wenn die eingetragene Zeit (wieder zB.: 23:00 inkl. Datum) älter ist als die Systemzeit.
    Wird der PC nun um 07:00 wieder hochgefahren startet der Job weil eben die eingetragene Zeit älter ist und das versuche ich abzufangen.
    Natürlich gäbe es jetzt die Möglichkeit dies im SQL Statement abzufragen aber diese gefällt mir nicht zu 100%.

    Somit war meine Idee den MinutenTimer auszunehmen und das ganze eben in so ein Event zulagern, dass anschlägt wenn die Systemuhr 1 Minute weiterschaltet.
    Es sei denn ihr habt hier generell eine andere Lösung welche das ganze schön löst.

    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten
    Du kannst natürlich eine Thread-Klasse machen, in der ein System.Threading.Timer läuft, das belastet Deine Form nicht.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Oder so?

    VB.NET-Quellcode

    1. Imports System.ComponentModel
    2. Public Class SingleEventAtTime
    3. Private Sub DoWait(ByVal o As Object)
    4. Dim ts As TimeSpan = DirectCast(o, TimeSpan)
    5. Threading.Thread.Sleep(ts)
    6. For Each d As [Delegate] In YupEvent.GetInvocationList
    7. Dim T = CType(d.Target, ISynchronizeInvoke)
    8. If T IsNot Nothing AndAlso T.InvokeRequired Then
    9. T.BeginInvoke(YupEvent, Nothing)
    10. Else
    11. d.DynamicInvoke(Nothing)
    12. End If
    13. Next
    14. End Sub
    15. Public Event Yup()
    16. Public Sub WaitUntil(ByVal t As DateTime)
    17. Dim SecondsToWait As New TimeSpan(DateDiff(DateInterval.Second, Now, t) * 1000 * 1000 * 10)
    18. Dim th As New Threading.Thread(AddressOf DoWait)
    19. th.Start(SecondsToWait)
    20. End Sub
    21. End Class


    VB.NET-Quellcode

    1. Private WithEvents tm As SingleEventAtTime
    2. Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    3. tm = New SingleEventAtTime
    4. tm.WaitUntil(Now.AddSeconds(5))
    5. End Sub
    6. Private Sub tm_Yup() Handles tm.Yup
    7. Debug.Print("yup")
    8. End Sub


    Also Thread starten und den genau so lange auf Eis legen, wie Sekunden bis zum gewünschten Event.
    Warum so umständlich?
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Dim CurrentTime As String
    3. Dim Termine As New List(Of String)
    4. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    5. Termine.Add("12:45")
    6. Termine.Add("23:00")
    7. Termine.Add("19:00")
    8. Termine.Add("13:42")
    9. Timer1.Interval = 1000 'Für den Test sollte 1 sekunde passen
    10. Timer1.Start()
    11. End Sub
    12. Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
    13. CurrentTime = TimeOfDay.Hour.ToString & ":" & TimeOfDay.Minute.ToString
    14. For i As Integer = 0 To Termine.Count - 1
    15. If CurrentTime = Termine.Item(i) Then
    16. 'Kaffee kochen
    17. End If
    18. Next
    19. End Sub
    20. End Class
    @Unwesen:
    60 mal Kaffee kochen innerhalb einer Minute - Gratulation.
    @fichz:
    ein Flag einführen und abfragen, dass sagt, dass der Kaffee bereits gekocht ist.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ist schon klar. Nur dann kommen die C&P-Künstler und sich beschweren, weil sie den Kaffee gar nicht trinken können. :D :D :D
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Erstmal Danke für die ganzen Rückmeldungen.
    @Unwesen ich will eben einen Timer mit 1 Sekunden Interval vermeiden.

    Nun hab ich das mal gebastelt was auch ein Event zurückgibt wenn sich die Systemzeit um 1 Minute verändert.

    Die Klasse:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Option Strict On
    2. Imports System.ComponentModel
    3. Public Class SystemTimeCheck
    4. Private mainTimer As New Timer
    5. Private MainThread As System.Threading.Thread
    6. Private ActuellTime As DateTime = Date.Now
    7. Private Sub MainTimer_Tick()
    8. If Not ActuellTime.Minute = Date.Now.Minute Then
    9. For Each d As [Delegate] In TimeDifferenzEvent.GetInvocationList '***
    10. Dim T = CType(d.Target, ISynchronizeInvoke)' ***
    11. If T IsNot Nothing AndAlso T.InvokeRequired Then ' ***
    12. T.BeginInvoke(TimeDifferenzEvent, Nothing) ' ***
    13. Else
    14. d.DynamicInvoke(Nothing) ' ***
    15. End If
    16. Next
    17. ActuellTime = Date.Now
    18. End If
    19. End Sub
    20. Private Sub ThreadingTick(ByVal sender As System.Object, ByVal e As System.EventArgs)
    21. MainThread = New Threading.Thread(AddressOf MainTimer_Tick)
    22. MainThread.IsBackground = True
    23. MainThread.Start()
    24. End Sub
    25. Public Sub New()
    26. mainTimer.Interval = 1000
    27. AddHandler mainTimer.Tick, AddressOf ThreadingTick
    28. mainTimer.Start()
    29. End Sub
    30. Public Event TimeDifferenz()
    31. End Class

    Form:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private WithEvents Test As New SystemTimeCheck
    3. Public Sub TestSub() Handles Test.TimeDifferenz
    4. Debug.WriteLine(Date.Now.ToString)
    5. End Sub
    6. End Class



    Kann man das so in Umlauf bringen?
    btw: Die ***-Kommentare in der Klasse hab ich leider nicht wirklich eine Ahnung was das bewirkt (nur ne Vermutung). Wäre froh wenn das vielleicht jemand erläutern könnte.

    lg fichz
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten

    fichz schrieb:

    Kann man das so in Umlauf bringen?

    IMHO Nein.
    Benutze den Timer so, dass er dir Bescheid sagt, WENN es 23:17 ist (oder jede andere gewünschte Uhrzeit) Dazu nimmst du einen Threading.Timer, den du beim Programmstart mit den korrekten "due" und "interval" Werten fütterst. Damit hast du das Problem komplett, einfach und elegant gelöst.

    Einmal pro Minute"nachschauen" wie spät es ist, ist unschön ...
    Wusste gar nicht, dass es verschiedene "Timer" gibt^^
    Sogesehen sollte mir der Timer jede Minute mitteilen. Das mit "due" und "Interval" soll heißen, dass "due" wartet bis es das erste Mal und der "Interval", wie beim normalen Timer, in eingetragegen Abstand "tickt".
    Wenn er jetzt jede Minute ausgeben soll (wirklich wenn es "umschaltet" sag ich mal), müsste ich mir ausrechnen wann die nächste Minute beginnt und den Interval dann auf 1 Minute stellen.

    Das ganze dann quasi noch in die Klasse integrieren und dann das Event schmeissen.
    Hab ich da nun den richtigen Denkansatz?^^

    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten
    Naja in meinem vorherigen Code wurde nicht alle Minuten sondern alle Sekunden nachgeschaut.
    Mit dem Threading.Timer wäre dies ja nun möglich (wie im vorherigen Post von mir beschrieben) es dann alle Minuten ausführen zu lassen.
    Somit könnte ich gewährleisten, dass wirklich innerhalb der ersten Sekunde der neuen Minute das Event geworfen wird und ich mit diesem dann weiterarbeiten kann.

    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten
    Irgendwie verstehst du nicht, worauf ich hinaus will ...

    Der Threading.Timer hat eine "due" Eigenschaft. Die setzt du auf "Zielzeit" - "Jetztzeit" in Millisekunden. Dann feuert der Timer exakt einmal und zwar genau dann, wenn es xx:xx Uhr ist.
    Ich weiß auf was du hinauswillst.
    Aber ich will ja jede neue Minute, dass das Event auslöst. Auch wenn es vielleicht nicht so schön sein mag aber ich brauche eben genau das. Am besten halt wenn es wirklich auf die nächste Minute umschlägt.

    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten

    fichz schrieb:

    Aber ich will ja jede neue Minute, dass das Event auslöst.

    Wozu?


    Es ist ein Scheduler welcher Minutenweise abfragt ob ein Job ansteht und diesen dann ausführt.

    Wozu?


    Muss ich was tun? Muss ich was tun? Muss ich was tun? Muss ich was tun? Muss ich was tun? Muss ich was tun? Muss ich was tun? Muss ich was tun? Muss ich was tun? Muss ich was tun? Muss ich was tun? Muss ich was tun? Muss ich was tun?

    oder

    Hey, es gibt Arbeit!


    Was klingt sinnvoller, logischer, besser?
    Von diesem Blickwinkel hab ich es noch nicht betrachtet.
    Habe auch eben gesehen, dass man mit dem Threading.Timer die Methode "Change" aufrufen kann. Somit (nehm ich mal an) reicht 1 Timer welcher halt immer die nächste Zeit aufruft.

    Werd mich da mal dransetzen es probieren so umzusetzen.

    Danke schön
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten