23

I'm trying to compare a date given by a user to a date in a file, basically a text file with lots of dates and times listed.

for example the user would enter a date such as 22/08/2007 and a time of 1:00, what i need the script to do is count how many dates in the text file are after the date given by the user.

I’ve managed to accomplish this by converting each date in the text file to unix timestamp and then comparing the two. Is there no way of simply comparing two dates in bash?

Thanks in advance

Xleedos
  • 948
  • 2
  • 9
  • 17
  • A little bit more information: in the text file the dates are listed as so... 42.106.251.158 Wed Jul 11 22:57:57 GMT 2007. Each with an IP address before the date. – Xleedos May 05 '11 at 09:09

5 Answers5

19

The GNU date command can convert a date into the number of seconds since 1970. Try this script:

#! /bin/bash
DATE=$(date -d "$3-$2-$1 01" '+%s')
COUNT=0
tr '/' ' ' | {
    while read D M Y ; do
    THIS=$(date -d "$Y-$M-$D 01" '+%s')
    if (( THIS > DATE )) ; then
        COUNT=$((COUNT + 1))
    fi
    done
    echo $COUNT
}

It expects three arguments and the raw dates in stdin:

for D in $(seq 19 25) ; do echo $D/08/2007 ; done | ./count.sh 22 08 2007
3

It will work till 2038. ;-)

ceving
  • 21,900
  • 13
  • 104
  • 178
  • Hi thanks again for a quick response. I’ve already used date to convert the dates/times into Unix time code but thanks anyway. It just seemed a bit long winded and i thought that there must have been an easier way! =) I guess not. Thanks to everyone for your help. – Xleedos May 05 '11 at 10:06
4

If you don't mind an external helper tool look at my dateutils. Your use case is covered by

dgrep -i '%d/%m/%Y %H:%M' '>=2007-08-22 01:00:00' < FILE | wc -l

where FILE is your file with the dates, and -i specifies the date format used in the file (I assumed dates like 22/08/2007 01:00 here). Matching lines will be printed, hence counting them gives you the information you were after.

hroptatyr
  • 4,702
  • 1
  • 35
  • 38
2

...why don't you simply cut out the single numbers, rearrange them from the most signifcant to the less significant, put them toghether to form a new big number and then compare the other one? :) Suppose you have a date in both $1 and $2 and suppose the date format is dd-mm-yyyy (adding hours and minutes is trivial):

d1=`echo "$1" | cut -d "-" -f 1`
m1=`echo "$1" | cut -d "-" -f 2`
y1=`echo "$1" | cut -d "-" -f 3`
date1="$y1$m1$d1"

d2=`echo "$2" | cut -d "-" -f 1`
m2=`echo "$2" | cut -d "-" -f 2`
y2=`echo "$2" | cut -d "-" -f 3`
date2="$y2$m2$d2"

if [ "$date1" -gt "$date2" ]; then
    #date1 > date2
else
    #date2 >= date1
fi

Note that you need zeros for 1-digit fields, for example, dates like this will work:

01-01-2013

and dates like this will NOT

1-1-2013

Cheers :-)

  • I like this technique... you could also use awk to reformat the date string into a number using : date1=$(echo $1 | awk -F'-' '{$3$2$1}') and of course you can do the same for date2... thanks EdoardoSchnell – cptHammer Apr 15 '13 at 08:39
  • Good solution, comparing epoch time of two dates can be inaccurate if there is delay between getting the values. – ibaralf Aug 11 '17 at 17:14
1

the above command compares the date in form of integer and would work fine until you are comparing the dates of same year.

better idea is to break the dates into 3 parts of dd, mm and yyyy and then do a comparison. just as below:

sysdate=`date +%d%m%Y`
sys_dd=`echo $sysdate|cut -c1,2`
sys_mm=`echo $sysdate|cut -c3,4`
sys_yyyy=`echo $sysdate|cut -c5-8`


cd $dir_source #moving in directory where report are placed


for i in *.*       #reading all the files present in directory and comparing with current sysdate
do
filename=$i
filedate=`echo $filename| cut -d '_' -f1`
file_dd=`echo $filedate|cut -c1,2`
file_mm=`echo $filedate|cut -c3,4`
file_yyyy=`echo $filedate|cut -c5-8`


if [ $sys_yyyy -lt $file_yyyy ]
then
echo "future cob file, check for the error"elif [ $sys_yyyy -gt $file_yyyy ]
then
echo "prev cob file , to be removed"
else
     if [ $sys_mm -lt $file_mm ]
     then
     echo "future cob file, check for the error"
     elif [ $sys_mm -gt $file_mm ]
     then
     echo "prev cob file , to be removed"
     else

          if [ $sys_dd -lt $file_dd ]
          then
          echo "future cob file, check for the error"
          elif [ $sys_dd -gt $file_dd ]
          then
          echo "prev cob file , to be removed"
          else
          echo "file date is same is cob date, retaining the file as it is"
          fi
     fi
fi
will
  • 23
  • 5
1

The problem is that dates are printed in such a way that, string-wise, "1/1/2050 1:00" < "2/1/1999 0:00". And since there's no way for a script to know that something is a datetime without you saying so, you essentially have to convert any date to something that can be compared - Either you have to order the elements so that the most important (year) are first, etc. (like ISO dates) or you convert to a number.

l0b0
  • 55,365
  • 30
  • 138
  • 223
  • Hi thanks for the quick response. The dates and times are in a format like so. Wed Jul 11 22:57:57 GMT 2007, the user input is also converted to that format using Date. Is there anything like Tests -ot/-nt to compare two dates? – Xleedos May 05 '11 at 09:17