Reputation: 308
I am new to VBA and have encountered an issue.
My objective is to find an elegant way of evaluating negative time values.
For example, the body of code below generates a message box which displays 12:30:00 AM
. I would expect it to display 11:30:00 PM
.
Sub Main() 'Run Test
Dim difference As Date
difference = #12:00:00 AM# - #12:30:00 AM#
MsgBox difference
End Sub
I have created a solution to this issue, but would like to know the coding community's feedback.
Some of the code is not necessary, but I have written it for functionality that may be important in the future.
The run
sub routine allows you to run the test
function with your specified values.
The test
function tests the timeDiff
& timeSum
logic.
The timeDiff
function finds the time-difference between t1
and t0
.
The timeSum
function finds the time-sum of t1
and t0
.
The asDuration
function removes the AM/PM suffix from a time value.
The asMilitary
function converts 12-hour format to 24 hour-format.
The concat
function I created to more easily concatenate strings.
Sub Main() 'Run Test
MsgBox Test("0:29:0", "23:30:0")
End Sub
Function Test(startT As Date, endT As Date) 'Test timeDiff & timeSum logic
Dim nextShift As Date, prevShift As Date, hours As Date
hours = timeDiff(endT, startT)
prevShift = timeDiff(startT, "0:30:0")
nextShift = timeSum("0:30:0", endT)
Test = concat("Start -", startT, "", "End - ", endT, "", "Duration -", asDuration(hours), "", "Next Shift: ", nextShift, "", "Prev Shift: ", prevShift)
End Function
Function timeDiff(t1 As Date, t0 As Date) As Date 'Return Time1 minus Time0
Dim units(0 To 2) As String
units(0) = Hour(t1) - Hour(t0)
units(1) = Minute(t1) - Minute(t0)
units(2) = Second(t1) - Second(t0)
If units(2) < 0 Then
units(2) = units(2) + 60
units(1) = units(1) - 1
End If
If units(1) < 0 Then
units(1) = units(1) + 60
units(0) = units(0) - 1
End If
units(0) = IIf(units(0) < 0, units(0) + 24, units(0))
timeDiff = Join(units, ":")
End Function
Function timeSum(t1 As Date, t0 As Date) As Date 'Return Time1 plus Time0
Dim units(0 To 2) As String
units(0) = Hour(t1) + Hour(t0)
units(1) = Minute(t1) + Minute(t0)
units(2) = Second(t1) + Second(t0)
If units(2) >= 60 Then
units(2) = units(2) Mod 60
units(1) = units(1) + 1
End If
If units(1) >= 60 Then
units(1) = units(1) Mod 60
units(0) = units(0) + 1
End If
units(0) = IIf(units(0) >= 24, units(0) Mod 24, units(0))
timeSum = Join(units, ":")
End Function
Function asDuration(time As Date) As String 'Display as duration; Remove AM/PM suffix from time
time = asMilitary(time)
asDuration = Left(time, Len(time))
End Function
Function asMilitary(time As Date) As String 'Convert 12-hour format to 24-hour-format
asMilitary = Hour(time) & ":" & Minute(time) & ":" & Second(time)
End Function
Function concat(ParamArray var() As Variant) As String 'Return arguments of function call concatenated as a single string
For Each elem In var()
concat = IIf(elem <> "", concat & elem & " ", concat & vbNewLine)
Next
End Function
Upvotes: 1
Views: 1838
Reputation: 308
Option Compare Database
Sub Main() 'Run Test
MsgBox Test("00:29:00", "23:30:00")
End Sub
Function Test(startT As Date, endT As Date) 'Test timeDiff logic
Dim nextShift As Date, prevShift As Date, hours As Date
hours = timeDiff(endT, startT)
prevShift = timeDiff(startT, "0:30:0")
nextShift = timeDiff("0:30:0", endT)
Test = concat("Start -", startT, "", "End - ", endT, "", "Duration -", asDuration(hours), "", "Next Shift: ", nextShift, "", "Prev Shift: ", prevShift)
End Function
Function timeDiff(t1 As Date, t0 As Date) As Date 'Returns t1-t0
dayAnchor = #1/1/2015#
timeDiff = ((dayAnchor + TimeValue(t1)) - TimeValue(t0)) - dayAnchor
End Function
Function asDuration(time As Date) As String 'Display as duration; Remove AM/PM suffix from time
t = Hour(time) & ":" & Minute(time) & ":" & Second(time)
asDuration = Left(t, Len(t))
End Function
Function concat(ParamArray var() As Variant) As String 'Return arguments of function call concatenated as a single string
For Each elem In var()
concat = IIf(elem <> "", concat & elem & " ", concat & vbNewLine)
Next
End Function
Upvotes: 0
Reputation: 8557
It turned out to be a bit trickier than my initial tests. Just typing into the immediate window of the VBA Editor allowed me to work several items by hand that the Editor "intelligently corrected" for me. But the underlying solution remains the same in any case.
The key is to "anchor" your time value on a date -- any date will do because it will be subtracted away later. But this makes your math work out as expected.
Option Explicit
Sub test()
Debug.Print TimeDiff("12:00:00", "00:30:00")
Debug.Print TimeDiff("0:29:0", "23:30:0")
Debug.Print TimeDiff("16:00:00", "4:30:00")
End Sub
Function TimeDiff(t1 As Date, t0 As Date) As Date
'--- returns t1-t0
Dim d1 As Date
Dim dayAnchor As Date
dayAnchor = #1/1/2015#
d1 = dayAnchor + t1
TimeDiff = (d1 - t0) - dayAnchor
End Function
Upvotes: 2