4

In a log file, I need to print the Elapsed time, in the following format:

"Process completed %s - Elapsed %s",
<time now in HH:MM:SS format>,
<difference from start date to end date in HH:MM:SS format>

Example:

Process completed 23:57:59 - Elapsed 103:22:59

How could I achieve this?

  • 2
    Where do you get the start and end dates? – glenn jackman Feb 12 '14 at 17:54
  • 1
    Which ksh? ksh88 or ksh93? – Mikel Feb 12 '14 at 18:25
  • The start date is the system date when the script starts. The end date is the system date when the script ends. I suppose I am using ksh93 (how can I verify that??). – UltraCommit Feb 13 '14 at 5:37
5

Ksh has a special parameter SECONDS which always contains the number of seconds since the epoch. Evaluating $SECONDS at the beginning and at the end of the job gives you the start and end times, and the difference is the elapsed time.

Unix time doesn't take leap seconds into account: a day in Unix time is always exactly 84000 seconds. Therefore time-of-day arithmetic on Unix time is easy.

start=$SECONDS
…
end=$SECONDS
elapsed=$((end - start))
printf 'Process completed %d:%02d:%02d - Elapsed %d:%02d:%02d\n' \
       $((end / 3600)) $((end / 60 % 60)) $((end % 60)) \
       $((elapsed / 3600)) $((elapsed / 60 % 60)) $((elapsed % 60))
  • Bash has a $SECONDS built-in too, but it behaves differently from Ksh - it is the number of integer seconds elapsed since the current shell instance was invoked. But deltas would be similar, so this answer should work there as well. – Amit Naidu Jul 2 at 18:32
2

Like this (Warning: those of a sensitive disposition look away now - this is old school ksh):

t1=`date '+%H:%M:%S'`
sleep 2
t2=`date '+%H:%M:%S'`

t1h=`expr $t1 : '\(..\):.*'`
t2h=`expr $t2 : '\(..\):.*'`
t1m=`expr $t1 : '..:\(..\).*'`
t2m=`expr $t2 : '..:\(..\).*'`
t1s=`expr $t1 : '..:..:\(..\)'`
t2s=`expr $t2 : '..:..:\(..\)'`

hdiff=`expr $t2h - $t1h`
mdiff=`expr $t2m - $t1m`
sdiff=`expr $t2s - $t1s`

if [ $tm1 -gt $tm2 ];then
    hdiff=`expr $hdiff - 1`
    mdiff=`expr $tm1 - $tm2`
fi
if [ $ts1 -gt $ts2 ];then
    mdiff=`expr $mdiff - 1`
    sdiff=`expr $sm1 - $sm2`
fi

if [ $hdiff -lt 10 ];then
    hdiff="0$hdiff"
fi
if [ $mdiff -lt 10 ];then
    mdiff="0$mdiff"
fi
if [ $sdiff -lt 10 ];then
    sdiff="0$sdiff"
fi
echo "Elapsed time $hdiff:$mdiff:$sdiff"
1

Sorry this is for bash, didn't notice you wanted korn shell untill just now, I can't help with that, but it might give you the basic principle.

StartTime=$( date +"%s" )

# do some stuff
sleep 4

EndTime=$( date )
ElapsedSecs=$(( `date -d"$EndTime" +%s` - StartTime  ))  
secs=$((  ElapsedSecs % 60    ))  
mins=$((  ( ElapsedSecs / 60 ) % 60    ))  
hrs=$((  ElapsedSecs / 3600    ))
EndTimeFormated=$( date -d"$EndTime" +"%H:%M:%S"  )  
echo "Process completed $EndTimeFormated - Elapsed " `printf "%02d:%02d%02d\n" $hrs $mins $secs`
0

The simplest and cleanest option is to use date:

date -ud "@$elapsed" "+Elapsed Time: %T"

Here, $elapsed represents the time delta in seconds.

You can avoid forking the external date process by sticking to shell built-ins [1][2]. The printf shell command has a %(...)T date/time format specifier that is often overlooked:

TZ=UTC0 printf "Elapsed Time: %(%T)T\n" $elapsed

The TZ=UTC0 and date -u set the timezone to UTC, which prevents any timezone/DST related ambiguity.

Since this question emphasizes formatting, these methods are much more convenient and far less error-prone than calculating date parts because you have the entire range of date format options available to you - no math needed. They work well for intervals of up to 24 hours, and other than the sub-second precision, should work in Bash v4.2+ as well.

Example:

Suppose you wanted to add nanoseconds as well:

$ start=$SECONDS
$ #wait or run process
$ date -ud "@$((SECONDS-start))" "+Elapsed Time: %H:%M:%S.%N"
Elapsed Time: 00:00:12.003247901

$ #Or, preferably
$ TZ=UTC0 printf "Elapsed Time: %(%H:%M:%S.%N)T\n" $((SECONDS-start))
Elapsed Time: 00:00:12.005056068

Bonus

You can abstract out your time measurement with aliases to make things easier. For example, we can emulate the Oracle TIMING command like this:

alias timingstart='start=$SECONDS'
alias timingstop='TZ=UTC0 printf "Elapsed Time: %(%T)T\n" $((SECONDS-start))' 

So, now:

$ timingstart
$ sleep 2
$ timingstop
Elapsed Time: 00:00:02

[1] For the $SECONDS variable, see man ksh | less +/SECONDS
[2] For printf time formats, see man ksh | less +/date-format -j.9

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.