posted on Sunday, December 02, 2007 9:21 PM by thomasswilliams

Don't Show 'Time Taken: 456.6 seconds' to Users

Instead, use this basic "natural language" elapsed time function in VB.NET.

I use this simple function to show elapsed time in the user interface. It came about because although I believe it's useful to provide some feedback at the end of long-running processes, I was getting sick of strings like "Time taken: 456.6 seconds" which is indecipherable to real people.

This VB.NET function returns a string like "less than 10 seconds", "under 1 minute", "around 4 minutes" which, as you can see, changes the unit of measure depending on how long the elapsed time is:

    ''' 
    ''' Returns an approximate, rounded string of the difference in seconds, minutes or hours between the passed 
    ''' start and end DateTimes (depending on how long the difference is), to return feedback to the user 
    ''' on how long a process takes to run.
    ''' 
    ''' The starting or commencement time.
    ''' The end or finish time.
    ''' A natural-sounding sentence fragment that can be used after an opening like "The process finished 
    ''' in ". The return value will not have leading or trailing spaces, or a full stop or other punctuation, and 
    ''' may possibly be empty if either  or  is Nothing.
    ''' I wrote this to replace the over-exact and hard to understand "456.75 seconds"-type strings 
    ''' that I had previously used to return elapsed time for long-running processes. This function has special cases 
    ''' for under 30 seconds, under a minute, under half an hour, etc. which means that the information provided is 
    ''' exact enough, but not too precise.
    ''' Debug.Write("The process finished in " + GetFriendlyTimeElapsed(Now, DateAdd(DateInterval.Minute, 74, Now)))
    ''' Debug.Write("The process finished in " + GetFriendlyTimeElapsed(dat1, dat2))
    ''' 
    
Friend Function GetFriendlyTimeElapsedString(ByVal StartTime As System.Nullable(Of DateTime), _
                                                 
ByVal EndTime As System.Nullable(Of DateTime)) As String

        
' if we didn't get two dates, leave
        
If Not (StartTime.HasValueOrElse Not (EndTime.HasValueThen Return String.Empty

        
' get the timespan between the two times
        
Dim tsElapsed As TimeSpan EndTime.Value StartTime.Value

        
' check that the start date is less than the end date
        'Debug.Assert(StartTime.Value < EndTime.Value, "The start time should be less than the end time.")

        ' take action depending on number of seconds for small figures (up to about 3600 seconds or 1 hour), 
        ' or if longer than an hour return exact hours and minutes. Up to 1 hour, the return is intentionally 
        ' rough or inexact to return more natural language. Note that the CASE statements have to be in ascending
        ' order, because once the criteria is met we exit the SELECT construct.
        
Select Case tsElapsed.TotalSeconds
            
Case Is <= 1
                
' special case for 1 or 0 seconds, or if the start time is *after* the end time (resulting in a 
                ' negative number of seconds)
                
Return "less than 1 second"
            
Case Is 31
                
' return "less than x seconds", rounded to nearest 5 seconds
                
Return "less than " & ((Int(tsElapsed.TotalSeconds 5) * 5) + 5).ToString("F0") & " seconds"
            
Case Is 61
                
' if more than 30 seconds but less than a minute, special case - return "less than 1 minute"
                
Return "less than 1 minute"
            
Case Is 91
                
' around 1 minute
                
Return "around 1 minute"
            
Case Is 1620
                
' if less than 27 minutes, return "around x minutes", rounded to nearest minute
                
Return "around " & (tsElapsed.TotalSeconds 60).ToString("F0") & " minutes"
            
Case Is 1800
                
' if time is between 27 minutes and 30 minutes, return "under 1/2 an hour"
                
Return "under 1/2 an hour"
            
Case Is 1980
                
' up to 33 minutes, return "around 1/2 an hour"
                
Return "around 1/2 an hour"
            
Case Is 2520
                
' less than 42 minutes, return nearest minutes
                
Return "approximately " & (tsElapsed.TotalSecondss 60).ToString("F0") & " minutes"
            
Case Is 2700
                
' under 45 minutes (between 42 and 45)
                
Return "under 45 minutes"
            
Case Is 2880
                
' just over 45 minutes (up to 48 minutes)
                
Return "just over 45 minutes"
            
Case Is 3420
                
' if under 57 minutes, return "approximately x minutes", rounded to nearest minute
                
Return "approximately " & (tsElapsed.TotalSeconds 60).ToString("F0") & " minutes"
            
Case Is 3900
                
' approximately 1 hour (from 57 up to 65 minutes)
                
Return "about 1 hour"
            
Case Else
                
' catch all case, after 65 minutes: return number of hours and minutes
                ' we need special formatting in case we hit 1 minute or 1 hour to leave the "s" off the end
                
Return tsElapsed.Hours.ToString("F0") & " hour" CStr(IIf(tsElapsed.Hours 1"s"String.Empty)) & _
                    
" and " tsElapsed.Minutes.ToString("F0") & " minute" CStr(IIf(tsElapsed.Minutes 1"s"String.Empty))
        
End Select

    End Function

I'm also trying out the Simple-Talk Code Prettifier (via Mladen Prajdić) which this version of Community Server does not like (how old is the version DNJ is running anyway?).

For recommendations as to where you might display the elapsed time to users, see SSW's Rule To Better Windows Forms.

Tags: time, code, vb.net, natural, development

Comments

# OT: Merry Christmas and Blog Stats 2007 Edition @ Monday, December 17, 2007 9:53 PM

Merry Christmas to all my reader(s). I hope you have a great Christmas and New Year, and I’ll see you...

Anonymous