Store all dates in a given date range into a variable

I want to store all possible dates between two user input dates. The input will be as like 20140605 and 20140830.

I want to store every date between the given dates into a variable using a loop so that I can use it.

The date generated or calculated must be in the same format as the input.

startdate=20141030
starttime=165800

enddate=20141120
endtime=175050

day=`expr $startdate % 100`
month=`expr $startdate % 10000`
year=`expr $startdate % 100000000`
month=`expr $month / 100`
year=`expr $year / 10000`
echo "$year  $month  $day"

while [ $enddate -ge $cdate ]
do
var=$cdate

#using variable var

if  [ $day -eq 31 ]; then
cdate=`expr $cdate - $day`
day=1
((month++))
cdate=`expr $cdate + 100 + $day`
#cdate=`expr $cdate + $day`
    if  [ $month -eq 13 ]; then
        #tmp=`expr $month * 100`
        cdate=`expr $cdate - $month * 100`
        month=1
        ((year++))
        cdate=`expr $cdate + 10100`
        if [ $year -eq 2999 ]; then
            ((year++))
            echo $cdate
            cdate=30010100
        fi
    fi
else
    ((day++))
    ((cdate++)) 
fi

if [ $enddate == $cdate ]; then
check=1
fi
done

I have tried to implement my requirement this way. But on compilation it says:

unary operator expected

What is the cause of this error, and how can I do this in a better way using a shell script?

Asked By: FredOscatore

||

I would take a completely different approach to this. Doing all the date calculations by hand is error prone (there aren’t always 31 days in a month, you have leap years, etc). Plus skimming through your code, it’s very hard to tell what you’re doing (which is a very bad thing).

#!/bin/bash
startdate=20141030
enddate=20141120

dates=()
for (( date="$startdate"; date != enddate; )); do
    dates+=( "$date" )
    date="$(date --date="$date + 1 days" +'%Y%m%d')"
done
echo "${dates[@]}"

This uses the date command to handle all computations, storing each date in the $dates array.

The result looks like this:

20141030 20141031 20141101 20141102 20141103 20141104 20141105 20141106 20141107 20141108 20141109 20141110 20141111 20141112 20141113 20141114 20141115 20141116 20141117 20141118 20141119
Answered By: phemmer

If, as you explained in your comments, your end goal here is to find all files modified within a given date range, then saving said range into a variable is pointless. Instead, you can give the range to find directly:

find . -mtime $start -mtime $end

Personally, I would use a different approach. Just create two temp files, one created a second before your start date and one created a second after your end date. Then use GNU find’s -newer test to find files that are newer than the first and not newer than the latter.

The tricky bit is getting $start and $end correctly. You could try something like:

#!/usr/bin/env bash

## If you really want to use this format, 
## then you must be consistent and always 
## us YYYYMMDD and HHMMSS.
startdate=20141030
starttime=165800

enddate=20141120
endtime=175050

## Get the start and end times in a format that GNU date can understand
startdate="$startdate $( sed -r 's/(..)(..)(..)/1:2:3/' <<<$starttime)"
enddate="$enddate $( sed -r 's/(..)(..)(..)/1:2:3/' <<<$endtime)"

## GNU find has the -newer test which lets you find files
## that are newer than the target file. We can use this
## and create two temporary files with the right dates.
tmp_start=$(mktemp)
tmp_end=$(mktemp)

## Now we need a date that is one seond before the
## start date and one second after the end date.
## We can then use touch and date to set the creation date 
## of the temp files to these dates. 
minusone=$(date -d "$startdate -1 sec" +%s)
plusone=$(date -d "$enddate +1 sec" +%s)

## Set the creation times of the temp files.
## The @ is needed when using seconds since
## the epoch as a date string.
touch -d "@$minusone" $tmp_start
touch -d "@$plusone" $tmp_end

## At this point we have two files, tmp_start and
## tmp_end with a creation date of $startdate-1 
## and $enddate+1 respectively. We can now search
## for files that are newer than one and not newer
## than the other.
find . -newer $tmp_start -not -newer $tmp_end

## Remove the temp files
rm $tmp_start $tmp_end
Answered By: terdon
Categories: Answers Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.