Pergunta

I wanted to restart the iteration when the system clock hits 00:00 or 12:00 MN. I got the iteration code from the answer of this (below) link, and it works perfectly.

Public Sub GetLastNumber(ByVal filePath As String)
    Dim lastFileNo As Integer = 1
    Dim files() As String = Directory.GetFiles(filePath, "*.txt")

    For Each file As String In files
        file = Path.GetFileNameWithoutExtension(file)
        Dim numbers As MatchCollection = Regex.Matches(file, "(?<num>[\d]+)")

        For Each number In numbers
            number = CInt(number.ToString())
            If number > 0 And number < 1000 And number > lastFileNo Then lastFileNo = number
        Next
  lastnumber.Text = number
    Next
End Sub

I stumbled something that uses a Timer like this one below, but it's giving me an error saying conversion fail "AM" as String to a Date type.

Public Sub DoStuff(ByVal obj As Object)
    MessageBox.Show("It's already time", "TIME!", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub

Public Sub testT()
    Dim tcb As TimerCallback = AddressOf DoStuff
    Dim t As Timer
    Dim execTime As TimeSpan
    Dim dtNow As DateTime = DateTime.Now
    Dim hc As Integer = 12
    Dim mc As Integer = 0

    If TimeOfDay.ToString("tt").Contains("AM") And hc = 12 Then
        hc = 0
    ElseIf TimeOfDay.ToString("tt").Contains("PM") Then
        hc = 12 + (12 - hc)
        If hc = 24 Then
            hc = 0
        End If
    End If

    Dim dtCandidate As DateTime = New DateTime(dtNow.Year, dtNow.Month, dtNow.Day, hc, mc, 0)

    If dtCandidate < dtNow Then
        dtCandidate.AddDays(1)
    End If

    execTime = dtNow.Subtract(dtCandidate)
    resultBox.Text = execTime.ToString
    t = New Timer(tcb, Nothing, execTime, TimeSpan.Zero)
End Sub

Public Sub realTime_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs)    Handles realTime.Tick
    TimeNow.Text = TimeOfDay.ToString("HH:mm:ss")
    testT()
End Sub

Conversion failure was remedied by using TimeOfDay.ToString("tt").Contains("AM/PM"). Un-representable DateTime error was remedied by correcting the ElseIf statements. Since there's no more error, I tried to put the testT function inside a Timer firing at 1000 ms. After system clock hit midnight(00:00), the message box of the DoStuff function showed every second after midnight. How can this be stopped but can still show up the next time the clock hits midnight?

Can somebody help me out?

Foi útil?

Solução

The code you linked to for the timer is very bad because it is trying to use strings in the manipulation of DateTimes - they are very different things.

I created a new Windows Forms application with only a Label named "TimeNow":

Public Class Form1

    Friend WithEvents realTime As Windows.Forms.Timer
    Private lastAlarmTime As DateTime
    Private alarmTimes As List(Of DateTime)
    Private displayTime As String

    Public Sub DoStuff()
        MessageBox.Show("It's already time", "TIME!", MessageBoxButtons.OK, MessageBoxIcon.Information)
    End Sub

    Public Sub CheckForAnAlarmTime()
        Dim dtNow As DateTime = DateTime.Now()

        For Each tt In alarmTimes
            ' the timer interrupt handler is not necessarily called at exact times. Allow for that.
            If tt > lastAlarmTime AndAlso tt < dtNow Then
                lastAlarmTime = dtNow
                DoStuff()
                SetAlarmTimes()
                Exit For
            End If
        Next

    End Sub

    Public Sub realTime_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles realTime.Tick
        Dim candidateDisplayTime As String = DateTime.Now.ToString("HH:mm:ss")
        ' only update the UI if necessary
        If candidateDisplayTime <> displayTime Then
            displayTime = candidateDisplayTime
            TimeNow.Text = displayTime
        End If

        CheckForAnAlarmTime()

    End Sub

    Private Sub SetAlarmTimes()
        Dim dtNow As DateTime = DateTime.Now()

        alarmTimes = New List(Of DateTime)
        alarmTimes.Add(New DateTime(dtNow.Year, dtNow.Month, dtNow.Day, 12, 0, 0))
        ' Recommendation: do not use exactly midnight without extensive testing, i.e. test over day rollover, month rollover, and year rollover.
        ' With less testing, use a few milliseconds less than midnight.
        alarmTimes.Add(New DateTime(dtNow.Year, dtNow.Month, dtNow.Day, 0, 0, 0).AddMilliseconds(-50))

    End Sub

    Private Sub SetUpAlarmsTimer()
        SetAlarmTimes()
        lastAlarmTime = DateTime.Now()
        realTime_Tick(Me, EventArgs.Empty)
        realTime = New Windows.Forms.Timer()
        realTime.Interval = 200 ' 200ms will update it more accurately w.r.t. visual appearance
        AddHandler realTime.Tick, AddressOf realTime_Tick
        realTime.Start()

    End Sub

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        SetUpAlarmsTimer()

    End Sub

End Class

Change the alarmTimes to whatever you need to check that the alarm is raised only once per alarmTimes item.

I am not willing to wait until midnight to check if alarmTimes.Add(New DateTime(dtNow.Year, dtNow.Month, dtNow.Day, 0, 0, 0) without the .AddMilliseconds(-50) will work as required, or until the end of the month or year to be absolutely sure. And please don't forget about testing around the end of February when it is a leap year.

The reason for checking against the lastAlarmTime is that it is not certain when a timer event will be raised: for a timer set to tick at 1000ms, you might get two events inside one real second, or none inside one real second. Approximately.

EDIT: You might also want to work in UTC to avoid hassle with daylight savings time changes.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top