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
Webinar
One Click, Universal Protection: Implementing Centralized Security Policies on Linux Systems

As Linux continues to play an ever increasing role in corporate data centers and institutions, ensuring the integrity and protection of these systems must be a priority. With 60% of the world's websites and an increasing share of organization's mission-critical workloads running on Linux, failing to stop malware and other advanced threats on Linux can increasingly impact an organization's reputation and bottom line.

Learn More

Sponsored by Bit9

Webinar
Linux Backup and Recovery Webinar

Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.

In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.

Learn More

Sponsored by Storix