Need Help on date subtraction

I have dates as follows in a file

20121029135649
20121029135721
20121030091540
20121030093420
20121030094340
20121030095427
20121030095856
20121030100104
20121030100251

All these dates are in sorted order. I need to find out the difference between the dates as follows

2nd row date - 1st row date
3rd row date - 2nd row date
4th row date - 3rd row date

For eg:

20121029135649  20121029135721     difference in minutes
20121029135721  20121030091540     difference in minutes
20121030091540  20121030093420     difference in minutes
20121030093420  20121030094340     difference in minutes

I have tried using date -d "" +%s, but didn't find a correct solution.
I am using HP-UX OS. Please give me a solution.

You may have a go with this (although I feel someone will come up with a better solution soon):

perl -MTime::Local -lne 'if($. > 1) {
/(....)(..)(..)(..)(..)(..)/;
$currtime=timelocal($6,$5,$4,$3,($2-1),$1-1900);
printf "%s\t%s --> %.2f minutes\n",$prevline,$_,(($currtime-$prevtime)/60);
$prevline=$_;
$prevtime=$currtime;
next
}
$prevline=$_;
/(....)(..)(..)(..)(..)(..)/;
$prevtime=timelocal($6,$5,$4,$3,($2-1),$1-1900);
' file
1 Like

If you have the perl with Date::Calc module, then you can use Mktime to calculate the epoch. Then subtract the both epoch and divide it by 60 (seconds) to find the minutes.

$time = Mktime($year,$month,$day, $hour,$min,$sec);
 
you can retrieve the $year,$month....$sec by using the below
 
/(....)(..)(..)(..)(..)(..)/

1 Like

Shell function and printf (ksh) examples.

$ perl -M"Date::Calc 'Mktime'" -lane 'sub convert{$_[0]=~/(....)(..)(..)(..)(..)(..)/; return Mktime($1,$2,$3,$4,$5,$6)}if($.==1){$a=convert $F[0];$first=$_;next}$b=convert $F[0]; print $first." ".$_." ".($b-$a)/60;$first=$_;$a=$b' input.txt
20121029135649 20121029135721 0.533333333333333
20121029135721 20121030091540 1158.31666666667
20121030091540 20121030093420 18.6666666666667
20121030093420 20121030094340 9.33333333333333
20121030094340 20121030095427 10.7833333333333
20121030095427 20121030095856 4.48333333333333
20121030095856 20121030100104 2.13333333333333
20121030100104 20121030100251 1.78333333333333

If you have ksh93:

#!/bin/ksh

LASTLINE=""
last=""

while read CURRLINE
do
    this=${CURRLINE:0:4}"-"${CURRLINE:4:2}"-"${CURRLINE:6:2}" "${CURRLINE:8:2}":"${CURRLINE:10:2}":"${CURRLINE:12:2}
    [[ -n $last ]] && {
        SEC=$(( $(printf "%(%s)T" "$this") - $(printf "%(%s)T" "$last") ))
        MIN=$(( SEC/60 ))
        SEC=$(( SEC%60 ))
        printf "%s  %s  %d:%02d\n" $CURRLINE $LASTLINE $MIN $SEC
    }
    LASTLINE=$CURRLINE
    last=$this
done < infile

Output for your examples

20121029135721 20121029135649 0:32
20121030091540 20121029135721 1158:19
20121030093420 20121030091540 18:40
20121030094340 20121030093420 9:20
20121030095427 20121030094340 10:47
20121030095856 20121030095427 4:29
20121030100104 20121030095856 2:08
20121030100251 20121030100104 1:47     

or Gnu sed/awk

[root@node3 ~]# cat get_date 
sed -r 's!(....)(..)(..)(..)(..)(..)!echo -n "& ";date -d "\1-\2\-\3 \4:\5:\6" +%s!eg' ${1} | \
awk 'NR!=1{printf("%s %s %02d:%02d:%02d", p,$1,($2-q)/3600,($2-q)%3600/60,($2-q)%3600%60);printf("\n")}{p=$1;q=$2}'
[root@node3 ~]# bash get_date infile 
20121029135649 20121029135721 00:00:32
20121029135721 20121030091540 19:18:19
20121030091540 20121030093420 00:18:40
20121030093420 20121030094340 00:09:20
20121030094340 20121030095427 00:10:47
20121030095427 20121030095856 00:04:29
20121030095856 20121030100104 00:02:08
20121030100104 20121030100251 00:01:47