As I has said earlier in the week, I have been doing a lot with LotusScript classes for reports I have been generating. One of the new @Functions that Damien introduced in the R6 formula engine was @BusinessDays. What started out as trying to find a simple way to determine the number of days between 2 dates turned into the custom class you see below:
Public Class elapsedtime Private startdt As NotesDateTime Private enddt As NotesDateTime Private tstring As String Private bstring As String Private tdays As Long Private bdays As Long Private thours As Integer Private bhours As Integer Private tminutes As Integer Private bminutes As Integer Private tseconds As Integer Private bseconds As Integer Private nondays () As Integer Private nondates () As NotesDateTime Private startofwd As String Private endofwd As String Sub New(dt1 As String, dt2 As String, holidays As String) Dim tmp As Variant Dim x As Integer Set Me.startdt = New NotesDateTime(dt1) Set Me.enddt = New NotesDateTime(dt2) If dt1 = "" Or dt2 = "" Then Exit Sub Redim nondays(1) nondays(0) = 1 nondays(1) = 7 Me.startofwd = "8:00 AM" Me.endofwd = "6:00 PM" If holidays <> "" then tmp = Split(holidays,",") Redim nondates(Ubound(tmp)) For x = 0 To Ubound(tmp) Set nondates(x) = New NotesDateTime(tmp(x)) Next End If Call GetTElapsed() Call GetBElapsed() End Sub Private Sub GetTElapsed() On Error Goto gteerror Dim diff As Long, tmp As Long If Me.startdt.localtime = Me.enddt.localtime Then Me.tdays = 0 Me.thours = 0 Me.tminutes = 0 Me.tseconds = 0 Else diff = Me.enddt.TimeDifference(Me.startdt)/60 Me.tdays = Fix(diff/1440) Me.thours = Fix((diff Mod 1440)/60) Me.tminutes = Fix(diff Mod 60) Me.tseconds = Fix(Me.enddt.TimeDifference(Me.startdt) Mod 60) End If gtefinish : Exit Sub gteerror : Call LogError() Resume gtefinish End Sub Private Sub GetBElapsed() On Error Goto bteerror Dim dt1 As NotesDateTime Dim dt2 As NotesDateTime Dim dt3 As NotesDateTime Dim hdt As NotesDateTime Dim diff As Long, tmp As Long Dim stepcount As Integer Dim addit As Boolean Me.bdays = 0 If Me.startdt.localtime = Me.enddt.localtime Then Me.bhours = 0 Me.bminutes = 0 Me.bseconds = 0 Exit Sub Elseif Me.enddt.TimeDifference(Me.startdt) < 0 Then stepcount = -1 ' Based on the time of the startdt, the values are recalculated to fall within work hours If Hour(Me.enddt.TimeOnly) >= 18 Then Set dt1 = New NotesDateTime(Me.enddt.DateOnly & " " & startofwd) Call dt1.AdjustDay(stepcount) Elseif Hour(Me.enddt.TimeOnly) < 8 Then Set dt1 = New NotesDateTime(Me.enddt.DateOnly & " " & startofwd) Else Set dt1 = New NotesDateTime(Me.enddt.LocalTime) End If ' if the start date falls on a weekend or holiday, move it While CheckIfWorkDay(dt1) = False Call dt1.AdjustDay(1) Wend ' Based on the time of the enddt, the values are recalculated to fall within work hours If Hour(Me.startdt.TimeOnly) < 8 Then Set dt2 = New NotesDateTime(Me.startdt.DateOnly & " " & endofwd) Call dt1.AdjustDay(-1) Elseif Hour(Me.startdt.TimeOnly) >= 18 Then Set dt2 = New NotesDateTime(Me.startdt.DateOnly & " " & endofwd) Else Set dt2 = New NotesDateTime(Me.startdt.LocalTime) End If ' if the end date falls on a weekend or holiday, move it While CheckIfWorkDay(dt2) = False Call dt2.AdjustDay(-1) Wend Else stepcount = 1 ' Based on the time of the startdt, the values are recalculated to fall within work hours If Hour(Me.startdt.TimeOnly) >= 18 Then Set dt1 = New NotesDateTime(Me.startdt.DateOnly & " " & startofwd) Call dt1.AdjustDay(stepcount) Elseif Hour(Me.startdt.TimeOnly) < 8 Then Set dt1 = New NotesDateTime(Me.startdt.DateOnly & " " & startofwd) Else Set dt1 = New NotesDateTime(Me.startdt.LocalTime) End If ' if the start date falls on a weekend or holiday, move it While CheckIfWorkDay(dt1) = False Call dt1.AdjustDay(1) Wend ' Based on the time of the enddt, the values are recalculated to fall within work hours If Hour(Me.enddt.TimeOnly) < 8 Then Set dt2 = New NotesDateTime(Me.enddt.DateOnly & " " & endofwd) Call dt2.AdjustDay(-1) Elseif Hour(Me.enddt.TimeOnly) >= 18 Then Set dt2 = New NotesDateTime(Me.enddt.DateOnly & " " & endofwd) Else Set dt2 = New NotesDateTime(Me.enddt.LocalTime) End If ' if the end date falls on a weekend or holiday, move it While CheckIfWorkDay(dt2) = False Call dt2.AdjustDay(-1) Wend End If While dt2.dateonly <> dt1.DateOnly And dt2.TimeDifference(dt1) > 0 If CheckIfWorkDay(dt1) = False Then Me.bdays = Me.bdays + 1 End If Call dt1.AdjustDay(1) Wend If Hour(dt1.TimeOnly) > Hour(dt2.TimeOnly) Then 'If the tim of the start is later in the day then the time of the end, go back to yesterday 'and calculate the time differently and subtract a business day 'diff = (seconds from start to end of work day) + (seconds from start of workday to end) Call dt1.AdjustDay(-1) Me.bdays = Me.bdays - 1 Set dt3 = New NotesDateTime(dt1.DateOnly & " " & endofwd) diff = dt3.TimeDifference(dt1)/60 Set dt3 = New NotesDateTime(dt2.DateOnly & " " & startofwd) diff = diff + (dt2.TimeDifference(dt3)/60) Else diff = dt2.TimeDifference(dt1)/60 End If Me.bdays = Me.bdays * stepcount Me.bhours = Fix(diff/60) Me.bminutes = Fix(diff Mod 60) Me.bseconds = Fix((dt2.TimeDifference(dt1)) Mod 60) btefinish : Exit Sub bteerror : Call LogError() Resume btefinish End Sub Private Function CheckIfWorkDay(dt) As Boolean Dim i As Integer CheckIfWorkDay = True Forall x In Me.nondays If Weekday(dt.DateOnly) = x Then CheckIfWorkDay = False Exit Forall End If End Forall If CheckIfWorkDay = True Then For i = 0 To Ubound(nondates) If dt.DateOnly = Me.nondates(i).DateOnly Then CheckIfWorkDay = False i = Ubound(Me.nondates) End If Next End If End Function Public Function GetTimeString(elapsetype As String) As String On Error Goto gtserror Dim thisdays As Long, thishours As Integer, thisminutes As Integer, thisseconds As Integer Dim tmp As Integer If elapsetype = "B" Then thisdays = Me.bdays thishours = Me.bhours thisminutes = Me.bminutes thisseconds = Me.bseconds Else thisdays = Me.tdays thishours = Me.thours thisminutes = Me.tminutes thisseconds = Me.tseconds End If tmp = 0 If thisdays = 1 Then GetTimeString = "1 Day" Elseif thisdays = -1 Then GetTimeString = "-1 Day" Elseif thisdays <> 0 Then GetTimeString = Cstr(thisdays) & " Days" End If If GetTimeString = "" Then tmp = thishours Else tmp = Abs(thishours) If tmp = 1 Then GetTimeString = GetTimeString & " 1 Hour" Elseif tmp = -1 Then GetTimeString = GetTimeString & " -1 Hour" Elseif tmp <> 0 Then GetTimeString = GetTimeString & " " & Cstr(tmp) & " Hours" End If If GetTimeString = "" Then tmp = thisminutes Else tmp = Abs(thisminutes) If tmp = 1 Then GetTimeString = GetTimeString & " 1 Minute" Elseif tmp = -1 Then GetTimeString = GetTimeString & " -1 Minute" Elseif tmp <> 0 Then GetTimeString = GetTimeString & " " & Cstr(tmp) & " Minutes" End If GetTimeString = Ltrim(GetTimeString) gtsfinish : Exit Function gtserror : Call LogError() Resume gtsfinish End Function Public Function GetDays(thistype As String) As Long If thistype = "B" Then GetDays = Me.bdays Else GetDays = Me.tdays End If End Function Public Function GetHours(thistype As String) As Integer If thistype = "B" Then GetHours = Me.bhours Else GetHours = Me.thours End If End Function Public Function GetMinutes(thistype As String) As Integer If thistype = "B" Then GetMinutes = Me.bminutes Else GetMinutes = Me.tminutes End If End Function Public Function GetSeconds(thistype As String) As Integer If thistype = "B" Then GetSeconds = Me.bseconds Else GetSeconds = Me.tseconds End If End Function End Class
If you notice, none of the attributes of the class are exposed as Public variables. I did this on purpose because I wanted to make sure that they weren't monkeyed with by any external code. The New() subroutine is passed the start and end date times as strings as well as a comma separated string of holidays. The decision to make the holidays a variable that is passed in will allow this to be used internationally, where the holidays for one division of the company might be different than the others. The weekend days are automatically set to Saturday and Sunday, but they can be changed if your company works something other than a standard 5 day work week. All of the other public functions get passed a variable, B for Business and T for Total, and return the values of the private attributes. The most useful finction is the GetTimeString function, which returns the elapsed time in days, hours, and minutes. This is just the type of thing that managers love to see on their reports.
Created 3/24/2006 9:21:25 PM |
Nice tip.Thanks
Created 3/24/2006 9:21:58 PM |
Nice tip.Thanks