LucSpan
LucSpan

Reputation: 1971

Compare two dates in Bash in MAC OSX

I'm new to Bash, apologies in advance.


Set-up

I have a particular end date end which depends on a particular starting date s and a period length p such that, end=s+p.


Problem

I want to execute a command if and only if today's date is before or equal to the end date.

That is: execute command iff date ≤ end.


Code

s='20/09/2017'
p='1'
end=$( date -j -v +"$p"d -f "%d/%m/%Y" "$s")

if [[ date < “$end” ]];
then
   echo 'ok'
fi

There are 2 things not the way they should be,

  1. p=1 implies end = '21/09/2017' < date = '26/09/2017', but still I get an ok.
  2. I use date < “$end” but I want date ≤ “$end”

How to correct 1 and 2?

Upvotes: 2

Views: 3692

Answers (3)

Renaud Pacalet
Renaud Pacalet

Reputation: 29403

  1. Your:

    end=$( date -j -v+"$p"d -f "%d/%m/%Y" "$s" )
    

    does not produce what you expect:

    echo "$end"
    Thu Sep 21 14:40:54 CEST 2017
    

    What you expect can be obtained with:

    end=$( date -j -v+"$p"d -f "%d/%m/%Y" "$s" +"%d/%m/%Y" )
    
  2. Your comparison:

    if [[ date < “$end” ]]; then
    

    does not behave as you think. date is not expanded as the result of the invocation of the date command. So, your comparison is a string comparison (< in the [[.]] conditional expression context) between string "date" and string "Thu Sep 21 14:40:54 CEST 2017". You should use something like:

    date=$( date )
    if [[ "$date" < “$end” ]]; then
    

    instead (but using date as a variable name is probably not a very good idea).

  3. As noticed by the other answers, the date format you chose is not the best for comparisons. So, combining the various fixes with the other wise suggestions, you could try something like:

    s='20170920'
    p='1'
    end=$( date -j -v+"$p"d -f "%Y%m%d" "$s" +"%Y%m%d" )
    now=$( date +"%Y%m%d" )
    if (( now <= end )); then
       echo 'ok'
    fi
    

    Note: if (( now <= end )); then is an arithmetic comparison and it should work in this specific case. Note also that it uses now and end, not $now and $end: the ((.)) arithmetic comparison interprets variable names as the integer value stored in the variable. Anyway, using dates, even in YYYYmmdd format, as if they were integers is not that clean. Using UNIX timestamps, which should be OK at least until year 2038, is probably cleaner:

    s='20170920'
    p='1'
    end=$( date -j -v+"$p"d -f "%Y%m%d" "$s" +"%s" )
    now=$( date +"%s" )
    if (( now <= end )); then
       echo 'ok'
    fi
    

    because here now and end are number of seconds since the Epoch, that is, true integers. Note, however, that the result could be different from that of the previous solution because you have now a one-second accuracy instead of one-day. Chose which one corresponds to your needs.

Upvotes: 2

hek2mgl
hek2mgl

Reputation: 158280

When you format the date like YYYYMMDD you can simply use an alphanumeric comparison:

start=$(date +'%Y%m%d')
end=$(date +'%Y%m%d')

# -gt means greater than - for example.
# check `help test` to get all available operators
if [ $start -gt $end ] ; then ...

Upvotes: 6

John Zwinck
John Zwinck

Reputation: 249652

First you need to use a date format which is lexicographical, meaning the big units come first. I highly recommend the ISO standard YYYY-MM-DD or YYYYMMDD. Second, <= can be written as -le (less or equal).

Upvotes: 3

Related Questions