Bash script to calculate duration between two time stamps, and also report minutes, hours, days, weeks, months and years

This is an improvement on an old script to calculate duration for clip trimming.

Typical usage example is to calculate duration of a clip for trimming a video with a program like mencoder (this is needed because it expects start position in HH:MM:SS format, but end position as duration since start position).

Anyway, let's say I want to trim a video starting at 00:01:22 until 00:23:44, to get duration, I'd run:

$ calc-duration 00.01.22 00.23.44

And get back:

00:22:22 (duration in HH:MM:SS format)
 
Or:
 
1342 seconds
22 minutes

My mencoder syntax would then be:

$ mencoder -ss 00.01.22 -endpos 00:22:22 -oac copy -ovc copy in.avi -o out.avi

In addition, the script will report duration in years/months/hours/etc. For example, number of hours I will have lived if I die in 2050:

$ calc-duration 1974-06-16 00:00:05 2050-01-01 02:30:10

Output:

662235:30:05 (duration in HH:MM:SS format)
 
Or:
 
2384047805 seconds
39734130 minutes
662235 hours
27593 days
3941 weeks
906 months
75 years

Let's see how old my daughter will be then:

$ calc-duration 2008-11-13 13.30.00 2050-01-01 02:30:10
 
360565:00:10 (duration in HH:MM:SS format)
 
Or:
 
1298034010 seconds
21633900 minutes
360565 hours
15023 days
2146 weeks
493 months
41 years

And here's the script:

#!/bin/bash
 
# calculates duration from supplied arguments.
# if 2 args, assumes time1 time2 (and uses current date as date1 and date2)
# if 4 args, assumes date1 time1 date2 time2
 
Usage() 
{
cat <<EOF
 
 USAGE
 =====
 
    $(basename $0) [start] [stop]
 
 DESCRIPTION
 ===========
 
    Calculates duration between start and stop times. Dates and times
    can be in column or dot delimited format. Can optionally include
    date as first arg. If no date provided, script defaults to today. 
 
 LIMITATIONS
 ===========
 
    Script calculates using seconds since 1970-01-01, as such it can't
    work with dates older than that. Future dates are fine though.
 
    Months and years are approximations, since not all months and years
    are the same length. This script assumes 365.25 days in a year and
    30.43 days in a month on average.
 
 EXAMPLES
 ========
 
    1. Start/stop times in traditional HH:MM:SS format:
 
      $(basename $0) 00:00:05 00:00:10
 
    2. Dots are easier to type than colons, so that's supported too:
 
      $(basename $0) 00.00.05 00.00.10
 
    3. Date and time example (using the authors estimated time of death):
 
      $(basename $0) 1974-06-16 00:00:05 2050-01-01 02:30:10  
 
EOF
}
 
if [[ $1 =~ ^--help|-h$ ]]; then
  Usage
  exit 0
fi
 
if [ "$#" -eq "2" ]; then
  time1="$(sed 's/\./:/g' <<<$1)"
  date1="$(date +%F)"
  time2="$(sed 's/\./:/g' <<<$2)"
  date2="$(date +%F)"
elif [ "$#" -eq "4" ]; then
  date1="$(sed 's/\./-/g' <<<$1)"
  time1="$(sed 's/\./:/g' <<<$2)"
  date2="$(sed 's/\./-/g' <<<$3)"
  time2="$(sed 's/\./:/g' <<<$4)"
else 
  echo
  echo "[$(basename $0)] ERROR: please check your input"
  echo "see --help for usage info"
  exit 1
fi
 
time1sec=$(date --date="$date1 $time1" +%s)
time2sec=$(date --date="$date2 $time2" +%s)
 
if [ -z "${time1sec##*[!0-9]*}" ] || [ -z "${time2sec##*[!0-9]*}" ]; then
  echo "[$(basename $0)] ERROR: please check your input"
  exit 1
else
  secdiff=$(( $time2sec-$time1sec ))
fi
 
h=$(( secdiff / 3600 ))
m=$(( ( secdiff / 60 ) % 60 ))
s=$(( secdiff % 60 ))
 
printf "\n%02d:%02d:%02d (duration in HH:MM:SS format)\n" $h $m $s
 
echo "
Or:
 
$secdiff seconds"
 
[[ $secdiff -ge 60 ]] && echo "$(bc <<<"$secdiff/60") minutes"
[[ $secdiff -ge 3600 ]] && echo "$(bc <<<"$secdiff/3600") hours"
[[ $secdiff -ge 86400 ]] && echo "$(bc <<<"$secdiff/86400") days"
[[ $secdiff -ge 604800 ]] && echo "$(bc <<<"$secdiff/604800") weeks"
[[ $secdiff -ge 2629800 ]] && echo "$(bc <<<"$secdiff/2629800") months"
[[ $secdiff -ge 31557600 ]] && echo "$(bc <<<"$secdiff/31557600") years"

Leave a comment

NOTE: Enclose quotes in <blockquote></blockquote>. Enclose code in <pre lang="LANG"></pre> (where LANG is one of these).