Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

How to compare two dates in a shell script?

For example something like

todate=2013-07-18
cond=2013-07-15

if [ $todate -ge $cond ];
then
    break
fi                           

It doesn't work. How can I achieve the desired result?

share|improve this question
    
What do you want to loop for? Do you mean conditional rather than loop? –  Mat Jul 25 '13 at 7:46
    
Why you tagged files? Are those dates actually file times? –  manatwork Jul 25 '13 at 7:47
    
Check out this on stackoverflow: stackoverflow.com/questions/8116503/… –  slm Jul 25 '13 at 14:04

7 Answers 7

You are missing the date format for the comparison:

#!/bin/bash

todate=$(date -d 2013-07-18 +"%y%m%d")
cond=$(date -d 2013-07-15 +"%y%m%d")

if [ $todate -ge $cond ]; #put the loop where you need it
then
 echo 'yes';
fi

You are missing looping structures too, how are you planning to get more dates?

share|improve this answer

This is not a problem of looping structures but of data types.

Those dates (todate and cond) are strings, not numbers, so you cannot use the "-ge" operator of test. (Remember that square bracket notation is equivalent to the command test.)

What you can do is use a different notation for your dates so that they are integers. For example:

date +%Y%m%d

will produce an integer like 20130715 for July 15th, 2013. Then you can compare your dates with "-ge" and equivalent operators.

enter code here

Update: if your dates are given (e.g. you are reading them from a file in 2013-07-13 format) then you can preprocess them easily with tr.

$ echo "2013-07-15" | tr -d "-"
20130715
share|improve this answer

Can use a standard string comparison to compare the chronological ordering [of strings in a year, month, day format].

date_a=2013-07-18
date_b=2013-07-15

if [[ "$date_a" > "$date_b" ]] ;
then
    echo "break"
fi

Thankfully, when [strings that use the YYYY-MM-DD format] are sorted* in alphabetical order, they are also sorted* in chronological order.

(* - sorted or compared)

Nothing fancy needed in this case. yay!

Cheers, -David

share|improve this answer

dates are strings, not integers; you can't compare them with standard arithmetic operators.

one approach you can use, if the separator is guaranteed to be -:

IFS=-
read -ra todate <<<"$todate"
read -ra cond <<<"$cond"
for ((idx=0;idx<=numfields;idx++)); do
  (( todate[idx] > cond[idx] )) && break
done
unset IFS

This works as far back as bash 2.05b.0(1)-release.

share|improve this answer

There is also this method from the article titled: Simple date and time calulation in BASH from unix.com.

These functions are an excerpt from a script in that thread!

date2stamp () {
    date --utc --date "$1" +%s
}

dateDiff (){
    case $1 in
        -s)   sec=1;      shift;;
        -m)   sec=60;     shift;;
        -h)   sec=3600;   shift;;
        -d)   sec=86400;  shift;;
        *)    sec=86400;;
    esac
    dte1=$(date2stamp $1)
    dte2=$(date2stamp $2)
    diffSec=$((dte2-dte1))
    if ((diffSec < 0)); then abs=-1; else abs=1; fi
    echo $((diffSec/sec*abs))
}

Usage

# calculate the number of days between 2 dates
    # -s in sec. | -m in min. | -h in hours  | -d in days (default)
    dateDiff -s "2006-10-01" "2006-10-32"
    dateDiff -m "2006-10-01" "2006-10-32"
    dateDiff -h "2006-10-01" "2006-10-32"
    dateDiff -d "2006-10-01" "2006-10-32"
    dateDiff  "2006-10-01" "2006-10-32"
share|improve this answer

The operator -ge only works with integers, which your dates aren't.

If your script is a bash or ksh or zsh script, you can use the < operator instead. This operator is not available in dash or other shells that don't go much beyond the POSIX standard.

if [[ $cond < $todate ]]; then break; fi

In any shell, you can convert the strings to numbers while respecting the order of dates simply by removing the dashes.

if [ "$(echo "$todate" | tr -d -)" -ge "$(echo "$cond" | tr -d -)" ]; then break; fi

Alternatively, you can go traditional and use the expr utility.

if expr "$todate" ">=" "$cond"; then break; fi

As invoking subprocesses in a loop can be slow, you may prefer to do the transformation using shell string processing constructs.

todate_num=${todate%%-*}${todate#*-}; todate_num=${todate_num%%-*}${todate_num#*-}
cond_num=${cond%%-*}${cond#*-}; cond_num=${cond_num%%-*}${cond_num#*-}
if [ "$todate_num" -ge "$cond_num" ]; then break; fi

Of course, if you can retrieve the dates without the hyphens in the first place, you'll be able to compare them with -ge.

share|improve this answer

The right answer is still missing:

todate=$(date -d 2013-07-18 +%s)
cond=$(date -d 2014-08-19 +%s)

if [ $todate -ge $cond ];
then
    break
fi  
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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