Why calculate elapsed time or differences in time you might be wonder? There are primarily two reasons to do this:
- Determine the time it took to complete a task; for calculating cost savings or Return on Investment (ROI)
- Generate a unique name
The need to the calculate cost to make something or complete a task/project is nothing new and happens everyday across every company. When calculating cost savings, you need to consider the following pieces of information:
- Does an action/activity have to be performed?
- How often is the action/activity performed?
- How much does the action/activity cost when performed?
- How long does it currently and/or previously take to complete the action/activity?
Even though calculating cost savings is an important conversation, that is best left for a future article.
Until AutoCAD 2017, the date and time stored in the CDATE
and DATE
system variables were the best for calculating time differences in an AutoCAD-based product as they included milliseconds. Starting with AutoCAD 2017-based products, the CDATE
and DATE
system variables no longer include milliseconds. Other date related system variables, such TDCREATE
were also affected by this change. I discussed this change across several articles recently, which can be found here:
- Getting the Current Date/Time with AutoLISP - Part 1
- Getting the Current Date/Time with AutoLISP - Part 2
- PSA: Do Your AutoLISP Programs Use the CDATE or DATE System Variables?
- PSA: Additional Date Related System Variables to Be Aware Of in Custom AutoLISP Programs
Computers can easily handle hundreds of thousands of instructions per second based on their architecture, so milliseconds is a much better measurement in time to measure compared to a full second. Since the CDATE
and DATE
system variables no longer include milliseconds, the MILLISECS
system variable can be used to calculate time differences in milliseconds. As part of a custom AutoLISP program, you might store the current time of MILLISECS
as the start time and then as part of the final tasks to be performed you might get the end value and subtract the differences of the two time values to get the time that has elapsed.
Command: (setq start (getvar "MILLISECS"))
25494432
Command: (setq end (getvar "MILLISECS"))
25499471
Command: (- end start)
5039
Of course, it is always best to wrap any functionality that you might want to use across multiple programs in a utility function; making it easier to manage and maintain. The following is an example of such a function, the Timer
function wraps the functionality that stores the start time and returns the time difference in a single function.
; Global variable for the timer
(setq *g-timer-start-time* nil)
; Stores the current time when called, and then returns
; the time difference when called the next time. Time
; difference is returned in milliseconds.
; Usage: (timer)
(defun timer ( / rTimeDiff)
; Check to see if the function was previously called
(if (= *g-timer-start-time* nil)
(progn
; Stores the current milliseconds
(setq *g-timer-start-time* (getvar "MILLISECS"))
(princ)
)
(progn
; Calculates and returns the time difference
(setq rTimeDiff (- (getvar "MILLISECS") *g-timer-start-time*)
*g-timer-start-time* nil)
rTimeDiff
)
)
)
The following shows a example of how you might use the Timer
function with your custom programs and the output that is returned:
(defun c:CounterLoop ( / loop cnt cur)
; Store the current time
(timer)
; Loop 10000 times and output a message every 100 loops
(setq loop 0 cnt 0)
(repeat 10000
(setq cur (fix (/ loop 100.0)))
(if (= cnt cur)
(progn
(prompt (strcat "\nLoop: " (itoa loop)))
(setq cnt (1+ cnt))
)
)
(setq loop (1+ loop))
)
(prompt (strcat "\nLoop: " (itoa loop)))
; Output the number of elapsed milliseconds
(prompt (strcat "\nElapsed time (ms): " (itoa (timer))))
(princ)
)
Partial output from the previous example:
...
Loop: 9700
Loop: 9800
Loop: 9900
Loop: 10000
Elapsed time (ms): 63
While most programs execute very quickly, some might take much longer based on the tasks they perform. Programs that take longer to execute might complete in tens of thousands of milliseconds, which can be hard to determine just how many seconds or minutes might have elapsed. The following functions can be used to calculate the differences in time and format milliseconds or seconds as hours, minutes, seconds, and milliseconds:
;| Takes two values in milliseconds and returns the
difference as an integer/long or double/float
bMilliseconds = T - Return value in milliseconds
bMilliseconds = nil - Return value in seconds
Usage: (TimeDiff T1 T2 T) - Milliseconds example
Usage: (TimeDiff T1 T2 nil) - Seconds example
Example(s)
(setq T1 24092498)
(setq T2 24188267)
(TimeDiff T1 T2 T)
95769
(TimeDiff T1 T2 nil)
95.769
|;
(defun TimeDiff (nStart nEnd bReturnMilliseconds / nDiff)
;; Get the time difference
(if (> nStart nEnd)
(setq nDiff (- nStart nEnd))
(setq nDiff (- nEnd nStart))
)
;; Return the time difference in milliseconds or seconds
(if (= bReturnMilliseconds nil)
(/ nDiff 1000.0)
nDiff
)
)
;| Formats milliseconds or seconds into the
HH:MM:SS:mmm (00:00:00:000) format
bMilliseconds = T - Time is expressed in milliseconds
bMilliseconds = nil - Time is expressed in seconds
Usage: (FormatTime 122.021 nil) - Seconds example
Usage: (FormatTime 95769 T) - Milliseconds example
Example(s)
(setq T1 24092498)
(setq T2 24188267)
(FormatTime (TimeDiff T1 T2 T) T)
"00:01:35:769"
(FormatTime 122.021 nil)
"00:02:02:021"
|;
(defun FormatTime (dTime bMilliseconds / dDiff sHrs nHrs sMins
nMins sSecs sMSecs nSecs)
(if bMilliseconds
(setq dDiff (/ dTime 1000.0))
(setq dDiff dTime)
)
; Set the default values
(setq sHrs "00"
sMins "00"
sSecs "00"
sMSecs "000")
; Get the number of seconds
(setq nSecs (fix dDiff))
; Get the number of milliseconds left
(setq sMSecs (rtos (* (- dDiff nSecs) 1000.0) 2 0))
; Get the number of minutes
(setq nMins (/ nSecs 60)
sMins (itoa nMins))
; Get the number of hours and minutes, if minutes are greater than 60
(if (> nMins 60)
(setq nHrs (fix (/ nMins 60))
sHrs (itoa nHrs)
nMins (- nMins (* nHrs 60))
sMins (itoa nMins))
)
; Get the number of seconds
(setq sSecs (itoa (- nSecs (* (/ nSecs 60) 60))))
; Format Hours to "00"
(if (= (strlen sHrs) 1)
(setq sHrs (strcat "0" sHrs))
)
; Format Minutes to "00"
(if (= (strlen sMins) 1)
(setq sMins (strcat "0" sMins))
)
; Format Seconds to "00"
(if (= (strlen sSecs) 1)
(setq sSecs (strcat "0" sSecs))
)
; Format Milliseconds to "000"
(while (< (strlen sMSecs) 3)
(setq sMSecs (strcat "0" sMSecs))
)
; Return the output in the 00:00:00:000 format
(strcat sHrs ":" sMins ":" sSecs ":" sMSecs)
)
Hope you found the information in this topic helpful.
Sincerely,
Lee
Comments