Solved

Calculating an interval of time

Posted on 2008-06-16
10
1,953 Views
Last Modified: 2008-06-16
Hi all,

i need to figure out how to calculate an interval of time - in ms.
I am working on a backup project that the user will run, select the date and time of the next run and then start the program.
This program will run on that day and time, then reset and run again the same day and time the next week.


For example, the user starts the program on Monday, at 11:24 am.
They select Friday, at 20:30 (8:30 pm) and start the program.  The code below calculates the number of ms for the interval of the System.Timers.Timer
Friday at 20:30 comes, the program runs and resets itself to run the next friday at 20:30 (recalculating the new interval)

what i'm needing to calculate is the interval from when the user clicks 'start' until the program actually runs.

What I have so far is
2 combo-boxes
(DayBox)  with Sunday-Saturday, so that the indecies of the combobox correspond with Date.DayOfWeek values, ie Sunday=0, Monday=1, etc)

(TimeBox) with times (in 24h format, in 30 minute increments - ie 00:00, 00:30, 01:00 ...... 23:00,23:30)

The following code seems to work, but after writing it, it seems very cumbersome.
Does anyone have a simpler, or more elegant way to do this?

Private Enum MSeconds

        Days = 86400000

        Hours = 3600000

        Minutes = 60000

        Seconds = 1000

End Enum
 

Private Function GetNextInterval() As Long

        Dim day As Integer = Now.DayOfWeek

        Dim day2 As Integer = DayBox.SelectedIndex

        Dim d As Integer = 0

        Dim h As Integer = CInt(Split(TimeBox.Text, ":")(0))

        Dim m As Integer = CInt(Split(TimeBox.Text, ":")(1))

        Dim s As Integer = 0

        ' number of days til next backup

        If day > day2 Then

            ' if today is past backup day

            d = 7 - (day - day2)

        ElseIf day2 > day Then

            d = day2 - day

        Else

            'day=day2

            Dim time As New Date(Now.Year, Now.Month, Now.Day, h, m, s)

            Dim ts As TimeSpan = time - Now

            If ts.TotalMilliseconds > 0 Then

                ' its passed already

                d = 6

            Else

                d = 0

            End If

        End If
 

        ' number of hours

        If h = 0 Then

            ' use 24

            If Now.Hour = 0 Then

                h = 0

            Else

                h = 24 - Now.Hour

            End If

        Else

            If h > Now.Hour Then

                h = h - Now.Hour

            ElseIf h < Now.Hour Then

                h = 24 - (Now.Hour - h)

            Else

                h = 0

            End If

        End If

        ' number of minutes

        If m = 0 Then

            ' use 60

            If m = Now.Minute Then

                m = 0

            Else

                m = 60 - m

            End If

        ElseIf m = 30 Then

            If m > Now.Minute Then

                m = 30 - Now.Minute

            Else

                m = 60 - (Now.Minute - m)

            End If

        End If

        ' number of secods - leave at 0

        s = 0

        Return d * MSeconds.Days + h * MSeconds.Hours + m * MSeconds.Minutes + s * MSeconds.Seconds

    End Function

Open in new window

0
Comment
Question by:sgaggerj
  • 3
  • 3
  • 2
  • +1
10 Comments
 
LVL 18

Expert Comment

by:jcoehoorn
ID: 21794819
Don't use a timer for this.  Set up a windows scheduled task instead.

But if you absolutely must use a timer, you're making this way too hard.  Just return the ts.TotalMilliseconds that you calculated at the top.
0
 
LVL 7

Assisted Solution

by:orcic
orcic earned 75 total points
ID: 21794908
I agree with jcoehoorn. Your simplified function would be something like....

Private Function GetNextInterval() As Long
        Dim day As Integer = Now.DayOfWeek
        Dim day2 As Integer = DayBox.SelectedIndex
        Dim d As Integer = 0
        Dim h As Integer = CInt(Split(TimeBox.Text, ":")(0))
        Dim m As Integer = CInt(Split(TimeBox.Text, ":")(1))
        Dim s As Integer = 0
        ' number of days til next backup
        If day > day2 Then
            ' if today is past backup day
            d = 7 - (day - day2)
        ElseIf day2 > day Then
            d = day2 - day
        Else
            'day=day2
            Dim time As New Date(Now.Year, Now.Month, Now.Day, h, m, s)
            Dim ts As TimeSpan = time - Now
            If ts.TotalMilliseconds > 0 Then
                ' its passed already
                d = 6
            Else
                d = 0
            End If
        End If
     Dim time1 As New Date(Now.Year, Now.Month, Now.Day+d, h, m, s)
     Dim ts1 As TimeSpan = time1 - Now
     Return ts1.TotalMilliseconds
  End Function
0
 
LVL 7

Expert Comment

by:orcic
ID: 21794978
replace
 Dim time1 As New Date(Now.Year, Now.Month, Now.Day+d, h, m, s)
with
  Dim time1 As Date
  time1=DateSerial (Now.Year, Now.Month, Now.Day+d).AddHours(h).AddMinutes(m).AddSeconds(s)
 
0
 
LVL 1

Author Comment

by:sgaggerj
ID: 21795831
I think it should also be
Dim ts1 as TimeSpan
if (Now-time1).totalmilliseconds > 0 then
   ts1=now-time1
else
   ts1=time1-now
endif

otherwise it could return a negative value, right?

that's why i used
Dim l As Long = d * MSeconds.Days + h * MSeconds.Hours + m * MSeconds.Minutes + s * MSeconds.Seconds
so it would always be a positive value

however, i just ran a couple other tests and it doesn't seem to be working right.

If I have it start Monday, at 15:00 (now it's currently 13:20), it comes up with 6 days, 2 hours, etc etc.
it should only be 1 hour 40 minutes
because Monday at 3pm hasn't arrived yet.

i made a couple adjustments because the hours weren't working properly


Private Function GetNextInterval() As Long

        Dim day As Integer = Now.DayOfWeek

        Dim day2 As Integer = DayBox.SelectedIndex

        Dim d As Integer = 0

        Dim h As Integer = CInt(Split(TimeBox.Text, ":")(0))

        Dim m As Integer = CInt(Split(TimeBox.Text, ":")(1))

        Dim s As Integer = 0

        ' number of days til next backup

        If day > day2 Then

            ' if today is past backup day

            d = 7 - (day - day2)

        ElseIf day2 > day Then

            d = day2 - day

        Else

            'day=day2

            Dim time As New Date(Now.Year, Now.Month, Now.Day, h, m, s)

            If time > Now Then

                d = 0

            Else

                d = 6

            End If

            'Dim ts As TimeSpan = time - Now

            'If ts.TotalMilliseconds > 0 Then

            '    ' its passed already

            '    d = 6

            'Else

            '    d = 0

            'End If

        End If
 

        ' number of hours

        If h = 0 Then

            ' use 24

            If Now.Hour = 0 Then

                h = 0

            Else

                h = 24 - Now.Hour

            End If

        Else

            If h > Now.Hour Then

                h = h - Now.Hour

            ElseIf h < Now.Hour Then

                h = 24 - (Now.Hour - h)

            Else

                h = 0

            End If

        End If

        ' number of minutes

        If m = 0 Then

            ' use 60

            If m = Now.Minute Then

                m = 0

            Else

' CHANGED HERE FROM m=60-m and added h-=1

                m = 60 - Now.Minute

                h -= 1

            End If

        ElseIf m = 30 Then

            If m > Now.Minute Then

                m = 30 - Now.Minute

            Else

                m = 60 - (Now.Minute - m)

            End If

        End If

        ' number of secods - leave at 0

        s = 0
 

        Dim time1 As New Date

        time1 = DateSerial(Now.Year, Now.Month, Now.Day + d).AddHours(h).AddMinutes(m).AddSeconds(s)

        Dim ts1 As TimeSpan

        If (time1 - Now).TotalMilliseconds > 0 Then

            ts1 = time1 - Now

        Else

            ts1 = Now - time1

        End If

        EndTime = Now.AddMilliseconds(ts1.TotalMilliseconds)

        Return ts1.TotalMilliseconds

    End Function

Open in new window

0
 
LVL 85

Accepted Solution

by:
Mike Tomlinson earned 425 total points
ID: 21796008
Good grief...you waaaaaaaaaay overcomplicated it:
    Private Function GetNextInterval() As Long

        Dim h As Integer = CInt(Split(TimeBox.Text, ":")(0))

        Dim m As Integer = CInt(Split(TimeBox.Text, ":")(1))

        Dim dtBase As DateTime = DateTime.Now.AddDays(DayBox.SelectedIndex - DateTime.Now.DayOfWeek)

        Dim dtTarget As New DateTime(dtBase.Year, dtBase.Month, dtBase.Day, h, m, 0)

        If dtTarget < DateTime.Now Then

            dtTarget = dtTarget.AddDays(7)

        End If

        Return dtTarget.Subtract(DateTime.Now).TotalMilliseconds

    End Function

Open in new window

0
Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

 
LVL 18

Expert Comment

by:jcoehoorn
ID: 21796013
One thing to remember:  Now is a very dynamic value, so this code is fatally flawed:
Dim ts1 as TimeSpan
if (Now-time1).totalmilliseconds > 0 then
   ts1=now-time1
else
   ts1=time1-now
endif

This would be more correct:
Dim ts1 as TimeSpan

Dim curTime As Date = Now

if (curTime - time1).totalmilliseconds > 0 then

   ts1=curTime - time1

else

   ts1=time1 - curTime 

endif

Open in new window

0
 
LVL 1

Author Comment

by:sgaggerj
ID: 21796789
heheh 'good grief'.  Yea I know I have a wierd way of looking at things!

That's pretty much what i was looking for Idle...

i came up with something a little different

add

DayBox as DateTimePicker

then

Private Function GetNextInterval() As Long
        Dim DayToRun As Date = DayBox.Value
        Dim TargetDate As Date = New Date(DayToRun.Year, DayToRun.Month, DayToRun.Day, CInt(Split(TimeBox.Text, ":")(0)), CInt(Split(TimeBox.Text, ":")(1)), 0)

        Dim ts As TimeSpan
        If TargetDate > Now Then
            ts = TargetDate - Now
        Else
            ts = Now - TargetDate
        End If
        Return ts.TotalMilliseconds
 End Function

though changing my if/then statement to be more like jcoehoorn's would probably be better.

I thought I was going to be able to gloat and say my solution had less lines than Idle_Mind's ..... waaahh!

Thanks guys!

0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 21796892
I wouldn't say you have a weird way of looking at things...  =)

Often times we already have one algorithm figured out in our heads...and this prevents us from seeing things from a different perspective.  That's one of the really nice things about EE...people read the problem and see completely different things...and then often bring different approaches to the table.

...don't start the "line counting" games though...we'll have to lump you in with the C/C++ programmers mentality of "less must be better!".   =\

Here is my algorithm with even fewer lines:
(it's super hard to read...but it ~must~ be better since it's shorter!)
    Private Function GetNextInterval() As Long

        Dim dtTarget As New DateTime(DateTime.Now.AddDays(DayBox.SelectedIndex - DateTime.Now.DayOfWeek).Year, DateTime.Now.AddDays(DayBox.SelectedIndex - DateTime.Now.DayOfWeek).Month, DateTime.Now.AddDays(DayBox.SelectedIndex - DateTime.Now.DayOfWeek).Day, CInt(Split(TimeBox.Text, ":")(0)), CInt(Split(TimeBox.Text, ":")(1)), 0)

        Return IIf(dtTarget < DateTime.Now, dtTarget.AddDays(7).Subtract(DateTime.Now).TotalMilliseconds, dtTarget.Subtract(DateTime.Now).TotalMilliseconds)

    End Function

Open in new window

0
 
LVL 85

Assisted Solution

by:Mike Tomlinson
Mike Tomlinson earned 425 total points
ID: 21796996
For grits and shins...and the betterment of the world (NOT!)...   ;)

The long sought after "one liner" function:
    Private Function GetNextInterval() As Long

        Return IIf(New DateTime(DateTime.Now.AddDays(DayBox.SelectedIndex - DateTime.Now.DayOfWeek).Year, DateTime.Now.AddDays(DayBox.SelectedIndex - DateTime.Now.DayOfWeek).Month, DateTime.Now.AddDays(DayBox.SelectedIndex - DateTime.Now.DayOfWeek).Day, CInt(Split(TimeBox.Text, ":")(0)), CInt(Split(TimeBox.Text, ":")(1)), 0) < DateTime.Now, (New DateTime(DateTime.Now.AddDays(DayBox.SelectedIndex - DateTime.Now.DayOfWeek).Year, DateTime.Now.AddDays(DayBox.SelectedIndex - DateTime.Now.DayOfWeek).Month, DateTime.Now.AddDays(DayBox.SelectedIndex - DateTime.Now.DayOfWeek).Day, CInt(Split(TimeBox.Text, ":")(0)), CInt(Split(TimeBox.Text, ":")(1)), 0)).AddDays(7).Subtract(DateTime.Now).TotalMilliseconds, (New DateTime(DateTime.Now.AddDays(DayBox.SelectedIndex - DateTime.Now.DayOfWeek).Year, DateTime.Now.AddDays(DayBox.SelectedIndex - DateTime.Now.DayOfWeek).Month, DateTime.Now.AddDays(DayBox.SelectedIndex - DateTime.Now.DayOfWeek).Day, CInt(Split(TimeBox.Text, ":")(0)), CInt(Split(TimeBox.Text, ":")(1)), 0)).Subtract(DateTime.Now).TotalMilliseconds)

    End Function

Open in new window

0
 
LVL 1

Author Comment

by:sgaggerj
ID: 21797080
Yea, that's exactly why i post here too.

It's not that hard to read though, and it definitely IS better!!!!

/ducks for cover

=)

Thanks again!

J
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

Article by: jpaulino
XML Literals are a great way to handle XML files and the community doesn’t use it as much as it should.  An XML Literal is like a String (http://msdn.microsoft.com/en-us/library/system.string.aspx) Literal, only instead of starting and ending with w…
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now