# Work the Shell - More Fun with Days and Dates

in
Figuring out how to calculate the year for a given date and day of week is a task that's not as easy as it sounds.
Could the Date Occur in the Current Year?

The next set of tests is one I rewrote a couple times to ensure that I wasn't tripping myself up, because my first thought simply was to use a test like this:

```if [ \$month -le \$thismonth -a \$day -le \$thisday ]
```

But, then I realized that in edge cases it wouldn't actually work properly. For example, let's say it's April 4 and you're checking for March 11. The month test succeeds, but the day test fails—not what we want. Instead, let's use a cascading set of conditional tests:

```if [ \$monthnum -gt \$thismonth ] ; then
# month is in the future, can't be this year
mostrecent=\$(( \$thisyear - 1 ))
elif [ \$monthnum -eq \$thismonth -a \$day -gt \$thisday ] ; then
# right month, but seeking a date in the future
mostrecent=\$(( \$thisyear - 1 ))
else
mostrecent=\$thisyear
fi
```

With just this much code, we can at least test the normalization of data input and comparison tool. I ran this set of tests on March 1, by the way:

```\$ whatyear.sh Monday Aug 3
Decided that for 8/3 we're looking at year 2010
\$ sh whatyear.sh mon jan 9
Decided that for 1/9 we're looking at year 2011
\$ whatyear.sh mon mar 1
Decided that for 3/1 we're looking at year 2011
\$ whatyear.sh mon mar 2
Decided that for 3/2 we're looking at year 2010
```

It correctly identified that the current date could be a match, but that the subsequent day (mar 2) had to be in the previous year for it to be a possibility.

Good. Next month, we'll put the rest of the LEGO pieces in the model and have a working script. The big task left? Parsing the output of cal to figure out the day of the week for a given date.

Dave Taylor has been hacking shell scripts for a really long time, 30 years. He's the author of the popular Wicked Cool Shell Scripts and can be found on Twitter as @DaveTaylor and more generally at www.DaveTaylorOnline.com.

______________________

Dave Taylor has been hacking shell scripts for over thirty years. Really. He's the author of the popular "Wicked Cool Shell Scripts" and can be found on Twitter as @DaveTaylor and more generally at www.DaveTaylorOnline.com.

## Comment viewing options

### GNU `date' is enough...

As we are talking about Linux, the GNU `date' utility could be far more clever than you might thought, so there is no need to mess with the output of `cal'...

Quick hint:
`date -d "Sep 25 2008" +%A`
`date -d "Sep 25 2008" +%u`

But this probably is GNU only, AFAIK, at least the BSD `date' does not have such magic.

Here is an `sh' script listing I just crafted:

```#!/bin/sh

export LC_TIME=C

usage()
{
cat <<!
USAGE:
\${0##*/} WEEKDAY MONTH_NAME Day
\${0##*/} WEEKDAY MONTH-DAY
\${0##*/} WEEKDAY MONTH/DAY
!
}

if [ \$# -ne 3 -a \$# -ne 2 ]; then
usage
exit 1
fi
if [ \$# -eq 3 ]; then
# GNU `date' accepts "Sep 25 2008"
fmt="\$2 \$3 %d"
else
# And also accepts "2011-9-25" or "9/25/2011"
case "\$2" in
*-*)
fmt="%d-\$2"
;;
*/*)
fmt="\$2/%d"
;;
*)
echo "Uknown date: \$2"
usage
exit 1
;;
esac
fi

case \$(echo \$1 | tr '[:upper:]' '[:lower:]' | cut -c1-3) in
mon) weekday=1 ;;
tue) weekday=2 ;;
wed) weekday=3 ;;
thu) weekday=4 ;;
fri) weekday=5 ;;
sat) weekday=6 ;;
sun) weekday=7 ;;
*)
echo "\$1: Unknown weekday"
exit 1
;;
esac

MY_DATE_FMT="%Y/%m/%d"
MY_WDAY_FMT="%A"

MAX_TRY=5

y0=\$(date +%Y)
i=0
found=0
while [ \$i -lt \$MAX_TRY ]; do
y=\$((y0 - i))
str=\$(printf "\$fmt" \$y)
if ! j=\$(date -d "\$str" +%u); then
# `date' will complain, so I keep quiet
exit 1
fi
if [ \$j -eq \$weekday ]; then
echo \$(date -d "\$str" +\$MY_DATE_FMT) is \
\$(date -d "\$str" +\$MY_WDAY_FMT)
found=1
fi
i=\$((i + 1))
done

test \$found -eq 0 && exit 1
exit 0```