【问题标题】:Run code every hour of the hour每小时运行一次代码
【发布时间】:2017-11-29 12:06:19
【问题描述】:

我想每小时执行一次代码加上3 mins 上的form_load。我写了一些代码,但这还不够我的目标。例如,如果我在8:10 打开应用程序,我希望它在9:0310:0311:03 等处执行。

对此最好的方法是什么?我尝试在下面的代码中使用 Timer。

    Dim currentDate As DateTime = DateTime.Now
    Dim minutesLeft = 60 - currentDate.Minute 'Computes how many minutes left until an hour
    Dim toMilisecs = (minutesLeft + 3) * 60000 'Convert (mins + 3) to milisecs
    tmrDPL.Interval = toMilisecs 'Set tmrDPL.Interval to toMilisecs


    If tmrDPL.Interval = 180000 Then 'Execute every hh:03 hr
        'Execute code
    End If

【问题讨论】:

  • 这很有趣,我只是想提出一个想法,如果您将代码放在这样的办公文件中,则需要打开并运行该文件才能运行代码。可能值得将您的代码移动到 VBScript(接近 VBA(后期绑定)),然后设置要运行的计划任务
  • 它是 Windows 窗体还是 Office 应用程序? vba 标签和 form_load 事件不匹配
  • @S.Serp 这是一个windows窗体
  • 这就是计划任务的用途。

标签: .net windows vb.net winforms


【解决方案1】:

已编辑:(考虑当前时间分钟在 xx:03 之前的时间)

您可以使用计时器并在第一次调用后调整其间隔,如下所示:

在表单加载中:

Dim t As DateTime = DateTime.Now
Dim m as Integer = t.Minute
If m < 3 Then 
    m = 3 - m 'we should call timer soon before next hour
Else
    m = (60 - m) + 3 'here (60-m) counts minutes left in this hour
    If m = 3 Then DoMyTasks() 'execute your code... 'remove this based on your needs!
End If

tmrDPL.Interval = (m * 60 - t.Second) * 1000 'specify first interval in millisec.

在计时器tick 事件中:

If tmrDPL.Interval <> 3600000 Then '60*60*1000
    tmrDPL.Interval = 3600000 'next calls must be after one hour from now
End If
DoMyTasks() 'execute your code... 

【讨论】:

  • 这并不适用于所有情况。例如,如果应用程序在08:01 启动,则第一次运行将在09:03 而不是08:03
  • @MatSnow 代码更新以考虑当前时间分钟在 xx:03 之前的时间
  • 也许这对 OP 来说无关紧要,但它不会完全从 **:03 开始,取决于应用程序的启动时间,计时器将始终在例如 **:03:59 处运行。
  • @MatSnow 是的,这是一个快速代码,用于显示有关时间间隔的要点...由... - t.Second 轻松更新以包括秒数
【解决方案2】:

这是一个更准确地计算开始时间的解决方案。 因为 S. Serp 的答案并不是在 **:03 处启动计时器,而是取决于应用程序在 **:03:59 处的启动时间。

Private Sub InitTimer()
    Dim currDate As DateTime = Date.Now
    Dim startMinute As Integer = 3
    Dim startTime As New TimeSpan(currDate.Hour, startMinute, 0)
    Dim secondsToNextRun As Integer = (3600 + startMinute * 60) -
                                     ((currDate.Minute * 60) + currDate.Second +
                                     If(currDate.TimeOfDay.Ticks > startTime.Ticks, 0, 3600))

    'calculate ms from s (add 1ms, for the case that secondsToNextRun = 0)
    tmrDLP.Interval = secondsToNextRun * 1000 + 1
    tmrDLP.Enabled = True
End Sub

Private Sub tmrDLP_Tick(sender As Object, e As EventArgs) Handles tmrDLP.Tick
    If tmrDLP.Interval <> 3600000 Then
        tmrDLP.Interval = 3600000
    End If

    'run your code here
    '...
End Sub

【讨论】:

  • 这是否意味着当我在8:00 运行应用程序时,它将执行8:03 的代码?
  • 是的。我想说的是,例如,当您在 08:30:59 运行 S.Serg 的代码时。接下来它将在09:03:59 而不是09:03:00 运行。
  • tick 事件中的 60000 值必须是 3600000 才能将一小时转换为毫秒。似乎是我的错字被复制到您的答案中;D
  • @S.Serp LOL :-D,你是对的。复制和粘贴是危险的。 ;-)
【解决方案3】:

只需几行代码,这个目标就不是那么容易实现的了。要做到干净,你必须检查你是否已经通过了触发点,而不仅仅是你刚刚击中它。我写了一个最小的类来做到这一点。如果您愿意,可以使用它,或者根据您的需要对其进行调整。

Public Class OffsetTimer
    Private cycle As Long
    Private offset As Long
    Private nextTrigger As Long

    Public Sub New(Byval initCycle As Long, Byval initOffset As Long)
        cycle = initCycle
        offset = initOffset

        'Calculate next trigger point
        nextTrigger = offset + ((Date.Now.Ticks /  cycle) * cycle)
        While(Date.Now.Ticks >= nextTrigger) 'If next trigger time still is in the past...
            'offset was to small, so add an additional cycle
            nextTrigger = nextTrigger + cycle
        End While
    End Sub

    Public Function CheckTrigger as Boolean
        Dim retVar As Boolean
        Dim ticks As Long

        retVar = False
        ticks = Date.Now.Ticks

        'If trigger point lies in presence or even past...
        If nextTrigger <= ticks Then
            'Prepare Return True
            retVar = True
            'Calculate next trigger point
            nextTrigger = nextTrigger + cycle
        End If

        Return retVar
    End Function
End Class

如果已达到nextTrigger 时间,CheckTrigger 函数将返回 True

您也可以使用类似的计算来获取到下一个触发点的时间(例如Date.Now.Ticks - nextTrigger),并为其设置Timer 的间隔。 如果您仍有疑问,请将其留在 cmets 中。

【讨论】:

    猜你喜欢
    • 2012-10-03
    • 2012-08-28
    • 2012-09-02
    • 1970-01-01
    • 1970-01-01
    • 2018-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多