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.

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

GNU `date' is enough...

zeroxia's picture

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
Webcast
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers

Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.

Learn More

Sponsored by AMD

White Paper
Private PaaS for the Agile Enterprise

If you already use virtualized infrastructure, you are well on your way to leveraging the power of the cloud. Virtualization offers the promise of limitless resources, but how do you manage that scalability when your DevOps team doesn’t scale? In today’s hypercompetitive markets, fast results can make a difference between leading the pack vs. obsolescence. Organizations need more benefits from cloud computing than just raw resources. They need agility, flexibility, convenience, ROI, and control.

Stackato private Platform-as-a-Service technology from ActiveState extends your private cloud infrastructure by creating a private PaaS to provide on-demand availability, flexibility, control, and ultimately, faster time-to-market for your enterprise.

Learn More

Sponsored by ActiveState