Avatar of RobertoFreemano
RobertoFreemanoFlag for United Kingdom of Great Britain and Northern Ireland

asked on 

calculate Time Due From a DateTime value in business hours - vb.net 2003

Hi Experts,

Hi want to write a  winform which adds 8 hours the the current time but only within working hours... between 08:00 am to 18:00 pm - Mon/Fri.

1, click Button1 = current time = 09:00
2. function adds 8 hours to Current time recorded = 17:00

example:  "Your car will be ready on Wednesday at... 17:00"

but...

If Button1 is clicked at at 17:30 on Fri, then calculate new time but ignore hours 18:00 to 07:59 and Sat/Sun

example:  "Your car will be ready on Mondayy at... 15:30"

Can anyone help me?
ProgrammingVisual Basic.NETVisual Basic Classic

Avatar of undefined
Last Comment
RobertoFreemano
Avatar of RobertoFreemano
RobertoFreemano
Flag of United Kingdom of Great Britain and Northern Ireland image

ASKER

Dim dt1 As Date = Date.Now
Dim dt2 As Date = Data.Now.AddHours(8)
--------------------------------------------------------------
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Label1.Text = "Current Time = " & dt1
Label2.Text = "Your car will be ready on Mondayy at...  = " & dt2
End Sub
Avatar of RobertoFreemano

ASKER

The code above only adds 8 hours to the current time... It's a start, but don't know how to exclude certain times & days.

Please help.

Regards,
Roberto
Avatar of MijaeDjinn
MijaeDjinn
Flag of Canada image

You may want to "pretty it up", but this should work:

Function nextDOW(ByVal dow As DayOfWeek, ByVal dtmDate As Date) As Date
        ' Find the next specified day of the week    
        ' after the specified date.                    
        Dim numDays As Integer
        'sunday = 0
        If dtmDate.DayOfWeek > dow Then
            numDays = 7 - (dtmDate.DayOfWeek - dow)
        Else
            numDays = dow - dtmDate.DayOfWeek
        End If
 
        nextDOW = dtmDate.AddDays(numDays)
    End Function
 
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim MaxTime As New TimeSpan(18, 0, 0)
        Dim MinTime As New TimeSpan(7, 59, 0)
        'Dim timeRemaining As TimeSpan
 
        Dim dtNow As DateTime = Now
        Dim dtWantedAt As DateTime = dtNow.AddHours(8)
 
        Dim dtReady As DateTime
 
        'calculate what day it will be ready
        If (dtWantedAt.DayOfWeek = DayOfWeek.Friday And _
            dtWantedAt.TimeOfDay > MaxTime) Or _
            (dtWantedAt.DayOfWeek = DayOfWeek.Saturday Or _
            dtWantedAt.DayOfWeek = DayOfWeek.Sunday) Then
            'will be ready on Monday
            dtReady = nextDOW(DayOfWeek.Monday, dtWantedAt).Date
        ElseIf (dtWantedAt.TimeOfDay > MaxTime) Then
            'will be ready tommorow
            dtReady = dtWantedAt.AddDays(1).Date
        Else
            'will be ready today
            dtReady = dtWantedAt.Date
        End If
 
        'calculate what time it will be ready
        Dim timeLeftToWait As New TimeSpan(8, 0, 0)
 
        If ((dtNow.TimeOfDay > MinTime) And (dtNow.TimeOfDay < MaxTime)) Then
            'requested during hours of operation
            If (dtWantedAt.TimeOfDay > MaxTime) Or (dtWantedAt.TimeOfDay < MinTime) Then
                'wanted outside of hours of operation
                timeLeftToWait = timeLeftToWait.Subtract(MaxTime.Subtract(dtNow.TimeOfDay))
                dtReady = dtReady.Add(timeLeftToWait.Add(MinTime))
            Else
                'wanted during hours of operation
                dtReady = dtReady.Add(dtWantedAt.TimeOfDay)
            End If
        Else
            'requested outside of hours of operation
            Console.WriteLine(timeLeftToWait.Hours)
            dtReady = dtReady.Add(MinTime.Add(timeLeftToWait))
        End If
 
        Label1.Text = "Current Time = " & dtNow.ToLongTimeString
        Label2.Text = "Your car will be ready on " & dtReady.ToLongDateString & " at " & dtReady.ToLongTimeString
 
    End Sub

Open in new window

Avatar of RobertoFreemano

ASKER

Hi MijawDjinn,

It does seem to like: ' dtWantedAt.TimeOfDay > MaxTime)',

error:
Operator '>' is not defined for types 'System.TimeSpan' and 'System.TimeSpan',

This is for vb.net 2003?

Any ideas?

Roberto
Avatar of MijaeDjinn
MijaeDjinn
Flag of Canada image

Switch > to (dtWantedAt.Hour > MaxTime.Hour) and likewise for minutes.
Avatar of RobertoFreemano

ASKER

Like this?

an you check it for me please?
   Function nextDOW(ByVal dow As DayOfWeek, ByVal dtmDate As Date) As Date
        ' Find the next specified day of the week    
        ' after the specified date.                    
        Dim numDays As Integer
        'sunday = 0
        If dtmDate.DayOfWeek > dow Then
            numDays = 7 - (dtmDate.DayOfWeek - dow)
        Else
            numDays = dow - dtmDate.DayOfWeek
        End If
 
        nextDOW = dtmDate.AddDays(numDays)
    End Function
 
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim MaxTime As New TimeSpan(22, 0, 0)
        Dim MinTime As New TimeSpan(7, 59, 0)
        'Dim timeRemaining As TimeSpan
 
        Dim dtNow As DateTime = Now
        Dim dtWantedAt As DateTime = dtNow.AddHours(8)
 
        Dim dtReady As DateTime
 
        'calculate what day it will be ready
        If (dtWantedAt.DayOfWeek = DayOfWeek.Friday And _
            (dtWantedAt.Hour > MaxTime.Hours) Or _
            dtWantedAt.DayOfWeek = DayOfWeek.Saturday Or _
          dtWantedAt.DayOfWeek = DayOfWeek.Sunday) Then
            'will be ready on Monday
            dtReady = nextDOW(DayOfWeek.Monday, dtWantedAt).Date
        ElseIf (dtWantedAt.Hour > MaxTime.Hours) Then
            'will be ready tommorow
            dtReady = dtWantedAt.AddDays(1).Date
        Else
            'will be ready today
            dtReady = dtWantedAt.Date
        End If
 
        'calculate what time it will be ready
        Dim timeLeftToWait As New TimeSpan(8, 0, 0)
 
        If ((dtNow.Hour > MinTime.Hours) And (dtNow.Hour < MaxTime.Hours)) Then
            'requested during hours of operation
            If (dtWantedAt.Hour > MaxTime.Hours) Or (dtWantedAt.Hour < MinTime.Minutes) Then
                'wanted outside of hours of operation
                timeLeftToWait = timeLeftToWait.Subtract(MaxTime.Subtract(dtNow.TimeOfDay))
                dtReady = dtReady.Add(timeLeftToWait.Add(MinTime))
            Else
                'wanted during hours of operation
                dtReady = dtReady.Add(dtWantedAt.TimeOfDay)
            End If
        Else
            'requested outside of hours of operation
            Console.WriteLine(timeLeftToWait.Hours)
            dtReady = dtReady.Add(MinTime.Add(timeLeftToWait))
        End If
 
        Label1.Text = "Current Time = " & dtNow.ToLongTimeString
        Label2.Text = "Your car will be ready on " & dtReady.ToLongDateString & " at " & dtReady.ToLongTimeString
 
    End Sub

Open in new window

Avatar of magicclaw
magicclaw
Flag of United States of America image

Here is another interpretation; I started writing it earlier this afternoon before a meeting so I decided to go ahead and finish it. I also gave it the ability to take any duration, rather than just 8 hour increments.

To call (pretend you're populating a textbox on a form):
txtOutput.Text = WorkTimer.GetFinishTime(DateTime.Now, New TimeSpan(Integer.Parse(txtHoursToAdd.Text), Integer.Parse(txtMinutesToAdd.Text), 0)).ToString()
Public Class WorkTimer
    Private Const START_OF_DAY As Integer = 8
    Private Const END_OF_DAY As Integer = 17
 
    Public Shared Function GetFinishTime(ByVal startTime As DateTime, ByVal spanToAdd As TimeSpan) As DateTime
        startTime = adjustStartForWeekend(startTime)
        If spanToAdd.Days >= 1 Then
            'You can deal with weekends if you have time spans > 1 day to handle. Model it similarly to the hours.")
            Throw New ArgumentOutOfRangeException("Can only add < 24 hours with this function.")
        End If
        Dim endTime As DateTime
        endTime = addWorkTime(endTime, spanToAdd)
        endTime = addWeekendDays(endTime)
        Return endTime
    End Function
 
    Private Shared Function adjustStartForWeekend(ByVal startTime As DateTime) As DateTime
        Select Case startTime.DayOfWeek
            Case DayOfWeek.Saturday
                Return startTime.Date.AddDays(2).AddHours(START_OF_DAY)
            Case DayOfWeek.Sunday
                Return startTime.Date.AddDays(1).AddHours(START_OF_DAY)
            Case Else
                Return startTime
        End Select
    End Function
 
    Private Shared Function addWeekendDays(ByVal endTime As DateTime) As DateTime
        Select Case endTime.DayOfWeek
            Case DayOfWeek.Saturday
                Return endTime.AddDays(2)
            Case DayOfWeek.Sunday
                Return endTime.AddDays(1)
            Case Else
                Return endTime.AddDays(0)
        End Select
    End Function
 
    Private Shared Function addWorkTime(ByVal startTime As DateTime, ByVal span As TimeSpan) As DateTime
        Dim now As DateTime = DateTime.Now
        Dim endOfToday As DateTime = DateTime.Today.AddHours(END_OF_DAY)
        Dim remainingTimeToday As TimeSpan = endOfToday - now
        If remainingTimeToday > span Then
            Return now.Add(span)
        Else
            span = span.Subtract(remainingTimeToday)
            Return now.Date.AddDays(1).AddHours(START_OF_DAY).Add(span)
        End If
    End Function
 
End Class

Open in new window

Avatar of MijaeDjinn
MijaeDjinn
Flag of Canada image

Probably easier to write a simple function to replace all those.

Private Function IsAfterHours(ByVal dt As DateTime, ByVal min As TimeSpan, ByVal max As TimeSpan) As Boolean
        If dt.Hour > max.Hours Then Return True
        If (dt.Hour = max.Hours) And (dt.Minute > max.Minutes) Then Return True
        If (dt.Hour < min.Hours) Then Return True
        If (dt.Hour = min.Hours) And (dt.Minute < min.Minutes) Then Return True
        Return False
    End Function

Open in new window

Avatar of magicclaw
magicclaw
Flag of United States of America image

The IsAfterHours function you wrote, while fine for telling us if something is after hours, only solves the easy part, determining whether something is after hours. The fun part is calculating the proper offset of time to "skip over" the after-hours period that may be bisecting the 8 hour range.
Avatar of MijaeDjinn
MijaeDjinn
Flag of Canada image

The function is to replace the (TimeSpan > TimeSpan) portions of the Vb .Net 2005 code posted previously.
Avatar of magicclaw
magicclaw
Flag of United States of America image

MijaeDjinn-
Gotcha. Sorry, my mistake; it wasn't immediately clear to me which post you were responding to.
Avatar of RobertoFreemano

ASKER

magicclaw

I found one or two conflicts in the code... similar to when the error as reported above.

Dim remainingTimeToday As TimeSpan = endOfToday - now

error:
'Operator '-' is not defined for types 'Date' and 'Date'
&
'Operator '>' is not defined for types 'System.TimeSpan' and 'System.TimeSpan','
Avatar of RobertoFreemano

ASKER

MijaeDjinn:

I think the amended code that i asked you to check works.... I just wanted you to check that i did what you suggested...

Not to sure where to put this though?



rivate Function IsAfterHours(ByVal dt As DateTime, ByVal min As TimeSpan, ByVal max As TimeSpan) As Boolean
        If dt.Hour > max.Hours Then Return True
        If (dt.Hour = max.Hours) And (dt.Minute > max.Minutes) Then Return True
        If (dt.Hour < min.Hours) Then Return True
        If (dt.Hour = min.Hours) And (dt.Minute < min.Minutes) Then Return True
        Return False
    End Function

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of MijaeDjinn
MijaeDjinn
Flag of Canada image

Blurred text
THIS SOLUTION IS ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
Avatar of magicclaw
magicclaw
Flag of United States of America image

RobertoFreemano -
Try this one:
        Dim remainingTimeToday As TimeSpan = endOfToday.Subtract(now)

Apparently VS2003 doesn't overload the subtraction operator. The .Subtract method should work though.
Avatar of magicclaw
magicclaw
Flag of United States of America image

Sorry, and for the comparison failure, replace with:
        If remainingTimeToday.CompareTo(span) > 0 Then
Avatar of magicclaw
magicclaw
Flag of United States of America image

Full source with the changes I mentioned:
Public Class WorkTimer
    Private Const START_OF_DAY As Integer = 8
    Private Const END_OF_DAY As Integer = 17
 
    Public Shared Function GetFinishTime(ByVal startTime As DateTime, ByVal spanToAdd As TimeSpan) As DateTime
        startTime = adjustStartForWeekend(startTime)
        If spanToAdd.Days >= 1 Then
            'You can deal with weekends if you have time spans > 1 day to handle. Model it similarly to the hours.")
            Throw New ArgumentOutOfRangeException("Can only add < 24 hours with this function.")
        End If
        Dim endTime As DateTime
        endTime = addWorkTime(endTime, spanToAdd)
        endTime = addWeekendDays(endTime)
        Return endTime
    End Function
 
    Private Shared Function adjustStartForWeekend(ByVal startTime As DateTime) As DateTime
        Select Case startTime.DayOfWeek
            Case DayOfWeek.Saturday
                Return startTime.Date.AddDays(2).AddHours(START_OF_DAY)
            Case DayOfWeek.Sunday
                Return startTime.Date.AddDays(1).AddHours(START_OF_DAY)
            Case Else
                Return startTime
        End Select
    End Function
 
    Private Shared Function addWeekendDays(ByVal endTime As DateTime) As DateTime
        Select Case endTime.DayOfWeek
            Case DayOfWeek.Saturday
                Return endTime.AddDays(2)
            Case DayOfWeek.Sunday
                Return endTime.AddDays(1)
            Case Else
                Return endTime.AddDays(0)
        End Select
    End Function
 
    Private Shared Function addWorkTime(ByVal startTime As DateTime, ByVal span As TimeSpan) As DateTime
        Dim now As DateTime = DateTime.Now
        Dim endOfToday As DateTime = DateTime.Today.AddHours(END_OF_DAY)
        Dim remainingTimeToday As TimeSpan = endOfToday.Subtract(now)
        If remainingTimeToday.CompareTo(span) > 0 Then
            Return now.Add(span)
        Else
            span = span.Subtract(remainingTimeToday)
            Return now.Date.AddDays(1).AddHours(START_OF_DAY).Add(span)
        End If
    End Function

Open in new window

Avatar of MijaeDjinn
MijaeDjinn
Flag of Canada image

Corrected full source (I missed one):

Public Class Form1
    Function nextDOW(ByVal dow As DayOfWeek, ByVal dtmDate As Date) As Date
        ' Find the next specified day of the week    
        ' after the specified date.                    
        Dim numDays As Integer
        'sunday = 0
        If dtmDate.DayOfWeek > dow Then
            numDays = 7 - (dtmDate.DayOfWeek - dow)
        Else
            numDays = dow - dtmDate.DayOfWeek
        End If
 
        nextDOW = dtmDate.AddDays(numDays)
    End Function
 
    Private Function IsAfterHours(ByVal dt As DateTime, ByVal min As TimeSpan, ByVal max As TimeSpan) As Boolean
        If dt.Hour > max.Hours Then Return True
        If (dt.Hour = max.Hours) And (dt.Minute > max.Minutes) Then Return True
        If (dt.Hour < min.Hours) Then Return True
        If (dt.Hour = min.Hours) And (dt.Minute < min.Minutes) Then Return True
        Return False
    End Function
 
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim MaxTime As New TimeSpan(18, 0, 0)
        Dim MinTime As New TimeSpan(7, 59, 0)
        'Dim timeRemaining As TimeSpan
 
        Dim dtNow As DateTime = Now
        Dim dtWantedAt As DateTime = dtNow.AddHours(8)
 
        Dim dtReady As DateTime
 
        'calculate what day it will be ready
        If (dtWantedAt.DayOfWeek = DayOfWeek.Friday And _
            IsAfterHours(dtWantedAt, MinTime, MaxTime)) Or _
            (dtWantedAt.DayOfWeek = DayOfWeek.Saturday Or _
            dtWantedAt.DayOfWeek = DayOfWeek.Sunday) Then
            'will be ready on Monday
            dtReady = nextDOW(DayOfWeek.Monday, dtWantedAt).Date
        ElseIf IsAfterHours(dtWantedAt, MinTime, MaxTime) Then
            'will be ready tommorow
            dtReady = dtWantedAt.AddDays(1).Date
        Else
            'will be ready today
            dtReady = dtWantedAt.Date
        End If
 
        'calculate what time it will be ready
        Dim timeLeftToWait As New TimeSpan(8, 0, 0)
 
        If Not IsAfterHours(dtNow, MinTime, MaxTime) Then
            'requested during hours of operation
            If IsAfterHours(dtWantedAt, MinTime, MaxTime) Then
                'wanted outside of hours of operation
                timeLeftToWait = timeLeftToWait.Subtract(MaxTime.Subtract(dtNow.TimeOfDay))
                dtReady = dtReady.Add(timeLeftToWait.Add(MinTime))
            Else
                'wanted during hours of operation
                dtReady = dtReady.Add(dtWantedAt.TimeOfDay)
            End If
        Else
            'requested outside of hours of operation
            Console.WriteLine(timeLeftToWait.Hours)
            dtReady = dtReady.Add(MinTime.Add(timeLeftToWait))
        End If
 
        Label1.Text = "Current Time = " & dtNow.ToLongTimeString
        Label2.Text = "Your car will be ready on " & dtReady.ToLongDateString & " at " & dtReady.ToLongTimeString
 
    End Sub
End Class

Open in new window

Avatar of RobertoFreemano

ASKER

MijaeDjinn:

ERROR: 'Reference to a non-shared member as object reference.'

WHERE:
Label1.Text = "Current Time = " & dtNow.ToLongTimeString
Label2.Text = "Your car will be ready on " & dtReady.ToLongDateString & " at " & dtReady.ToLongTimeString
Avatar of MijaeDjinn
MijaeDjinn
Flag of Canada image

print the labels however works for you, it's just sample code
Avatar of MijaeDjinn
MijaeDjinn
Flag of Canada image

If you want changed the sub to a function that accepts the time to check and returns the time it is ready at. It is up to you from here.
Avatar of RobertoFreemano

ASKER

Thanks Guys

Both code work, but I prefer the original code which seems to work best for me.

Regards,
Roberto
Avatar of RobertoFreemano

ASKER

Hi MijaeDjinn.

I'm trying to extend the time so it will say "Your car will be ready in 5 days" instead of 8 hours.

I've tried changing:
dtReady = dtWantedAt.AddDays(1).Date
to
dtReady = dtWantedAt.AddDays(5).Date

But I can't seem to figure out how to do this.

I wonder if you'd be so kind as to point me in the right direction.

Thanks,
Roberto
Visual Basic Classic
Visual Basic Classic

Visual Basic is Microsoft’s event-driven programming language and integrated development environment (IDE) for its Component Object Model (COM) programming model. It is relatively easy to learn and use because of its graphical development features and BASIC heritage. It has been replaced with VB.NET, and is very similar to VBA (Visual Basic for Applications), the programming language for the Microsoft Office product line.

165K
Questions
--
Followers
--
Top Experts
Get a personalized solution from industry experts
Ask the experts
Read over 600 more reviews

TRUSTED BY

IBM logoIntel logoMicrosoft logoUbisoft logoSAP logo
Qualcomm logoCitrix Systems logoWorkday logoErnst & Young logo
High performer badgeUsers love us badge
LinkedIn logoFacebook logoX logoInstagram logoTikTok logoYouTube logo