Calculating Day of the Week, Finally
As with many of the challenges we tackle, the latest project has sprawled across more articles than I ever expected when I first received the query from a reader. The question seems reasonably simple: given a month, day number and day of the week, calculate the most recent year that matches those criteria.
There are some obscure and complex formulas for doing just this, but instead, I decided it'd be interesting basically to loop backward from the current year for the month in question, parsing and analyzing the output of the handy cal program.
The real challenge has been that the cal program never really was designed to produce easily parsed output, so figuring out the day of the week (DOW, as we've been abbreviating it) involves basically counting the number of leading spaces or otherwise compensating for an average month where the first day starts mid-week, not neatly on Sunday.
An algorithmic-friendly version of cal would have output where days prior to the first day of the month would be output optionally as zeros or underscores, making this oodles easier. But it isn't, so we have to compensate.
Figuring the Day of the Week
Last time, we wrapped up with a shell function that expected the day, month and year as arguments and returned the day of the week of that particular date in that month on that year. In other words, 16 May, 2011, occurs on a Monday:
May 2011
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
The actual return value of the function in this instance is 2, so 1 = Sunday, 2 = Monday, and so on.
Given the desired day of the week that the user specifies and a simple way to decrement the year until we hit a match coupled with the function already shown, it should be relatively easy to assemble all the pieces and create—finally—the script that details when a specific date was on a specific day of the week.
I won't republish all the code from previous posts (the completed script is 83 lines long), but here's the most salient portion at the end, the section that steps back year by year to figure out which one has a matching calendar entry:
echo Looking for $weekday, $day, $month \($monthnum\) \
starting in $mostrecent
# now we need to loop backwards through years until a match
year=$mostrecent
DOW=-1 # start with a dead value
while [ $DOW -ne $desiredDOW ]
do
figureDOW $day $monthnum $year
# echo "> $day $month occurred on a $DOW in $year"
year=$(( $year - 1 ))
done
echo "Got it! $day $month occurred on a $weekday
↪most recently in ${year}:"
cal $month $year
Notice that when we find a match, we not only print out what year had that date on the specified day of the week, but we also print out the calendar for that month as a visual confirmation.
A few sample runs illustrate:
$ whatyear Friday February 9
Got it! 9 feb occurred on a fri most recently in 2006:
February 2006
Su Mo Tu We Th Fr Sa
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28
$ whatyear wed aug 3
Got it! 3 aug occurred on a wed most recently in 2004:
August 2004
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Since we convert the day of the week name and the month name to all lowercase and then truncate anything after the first three letters, you can see that "Friday" and "wed" both work, which is a nice side benefit. Applications with more flexible input options obviously are greatly preferred and make everyone's life easier.
Something's Still Broken
One date breaks the script because it doesn't occur every year: February 29. Here's the problem in a nutshell:
$ cal feb 2010
February 2010
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28
When we try to find a match for "29" on this calendar, there's no matching output, and the conditional tests we have in the script can't handle the empty string.
It's not pretty:
$ whatyear mon feb 29
./whatyear.sh: line 21: [: -eq: unary operator expected
./whatyear.sh: line 72: [: -ne: unary operator expected
Got it! 29 feb occurred on a mon most recently in 2010:
February 2010
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28
You know, if we had these ugly "[" test error messages but the end result was correct, I probably could live with it, but you can see that it's matched on a February that doesn't even have a 29th day—lame.
However, fixing it might be more trouble than it's worth, and it certainly will cause us to sprawl into a subsequent article. Instead, I encourage you to grab the entire source code library, and explore how to fix it yourself. Yes, I am punting!
Next time, I'll start on a new shell scripting challenge, and as usual, I encourage you to send me a quick e-mail note with some ideas you have on what would be compelling for us to develop or any particularly interesting scripting problems you're facing.
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.
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.
Sponsored by AMD
Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6
Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.
Learn more about catching the bad guy in this free white paper.
Sponsored by DLT Solutions
| Dynamic DNS—an Object Lesson in Problem Solving | May 21, 2013 |
| Using Salt Stack and Vagrant for Drupal Development | May 20, 2013 |
| Making Linux and Android Get Along (It's Not as Hard as It Sounds) | May 16, 2013 |
| Drupal Is a Framework: Why Everyone Needs to Understand This | May 15, 2013 |
| Home, My Backup Data Center | May 13, 2013 |
| Non-Linux FOSS: Seashore | May 10, 2013 |
- RSS Feeds
- Dynamic DNS—an Object Lesson in Problem Solving
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- Using Salt Stack and Vagrant for Drupal Development
- New Products
- A Topic for Discussion - Open Source Feature-Richness?
- Validate an E-Mail Address with PHP, the Right Way
- Drupal Is a Framework: Why Everyone Needs to Understand This
- What's the tweeting protocol?
- Tech Tip: Really Simple HTTP Server with Python
- BASH script to log IPs on public web server
4 hours 23 min ago - DynDNS
7 hours 59 min ago - Reply to comment | Linux Journal
8 hours 31 min ago - All the articles you talked
10 hours 55 min ago - All the articles you talked
10 hours 58 min ago - All the articles you talked
10 hours 59 min ago - myip
15 hours 24 min ago - Keeping track of IP address
17 hours 15 min ago - Roll your own dynamic dns
22 hours 29 min ago - Please correct the URL for Salt Stack's web site
1 day 1 hour ago
Enter to Win an Adafruit Pi Cobbler Breakout Kit for Raspberry Pi

It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Pi Cobbler Breakout Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- 5-21-13, Prototyping Pi Plate Kit: Philip Kirby
- Next winner announced on 5-27-13!
Free Webinar: Hadoop
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.
Some of key questions to be discussed are:
- What is the “typical” Hadoop cluster and what should be installed on the different machine types?
- Why should you consider the typical workload patterns when making your hardware decisions?
- Are all microservers created equal for Hadoop deployments?
- How do I plan for expansion if I require more compute, memory, storage or networking?



Comments
auto diagnostic tool
HINO Trucks diagnostics is a tool equipped with all the functions needed to diagnose the trouble, check functions, and configure the settings of the electronic system built into HINO engines.Hino-Bowie Hino Diagnostic Explorer The program runs on a personal computer equipped with a Windows95/98/200/xp operating system,auto diagnostic tool. And it connects to a communication network by means of a diagnosis connector via a communication Interface. After it has been connected to a communication network, it can carry out various operations by extracting information from the engine ECU.
year plus
THEN decrementing it and printing out the solution and the calendar. So Feb 9th appeared in 2007.
The particular magnitude of
The particular magnitude of frequency is determined by the type in the test content. Low-frequency beams have got better sexual penetration effect because of a smaller amount attenuation. Minimal frequency ultrasound tech2 obd2 gm diagnostic ocean can be used for difficult surfaces, because they are tossed a smaller amount. Even so, the results for detection involving smaller sized flaws as well as modifications in the fabric is just not successful as the divergence will become larger together with low consistency ultrasound waves. Higher rate of recurrence cross-bow supports develop more effective ends in case of tiny imperfections http://www.kfzdiagnosegeraet.de/auto-diagnostic-tool-cid90. In the case of ultrasound surf producing tiny divergence, a new concentrated ray can be released to the test supplies. However, because of greater attenuation (attenuation means the progressive drop inside the intensity of any kind of flux by way of a moderate), large frequency waves are not able to penetrate higher absolute depths.
The particular magnitude of
The particular magnitude of frequency is determined by the type in the test content. Low-frequency beams have got better sexual penetration effect because of a smaller amount attenuation. Minimal frequency ultrasound tech2 obd2 gm diagnostic ocean can be used for difficult surfaces, because they are tossed a smaller amount. Even so, the results for detection involving smaller sized flaws as well as modifications in the fabric is just not successful as the divergence will become larger together with low consistency ultrasound waves. Higher rate of recurrence cross-bow supports develop more effective ends in case of tiny imperfections http://www.kfzdiagnosegeraet.de/auto-diagnostic-tool-cid90. In the case of ultrasound surf producing tiny divergence, a new concentrated ray can be released to the test supplies. However, because of greater attenuation (attenuation means the progressive drop inside the intensity of any kind of flux by way of a moderate), large frequency waves are not able to penetrate higher absolute depths.
The particular magnitude of
The particular magnitude of frequency is determined by the type in the test content. Low-frequency beams have got better sexual penetration effect because of a smaller amount attenuation. Minimal frequency ultrasound tech2 obd2 gm diagnostic ocean can be used for difficult surfaces, because they are tossed a smaller amount. Even so, the results for detection involving smaller sized flaws as well as modifications in the fabric is just not successful as the divergence will become larger together with low consistency ultrasound waves. Higher rate of recurrence cross-bow supports develop more effective ends in case of tiny imperfections http://www.kfzdiagnosegeraet.de/auto-diagnostic-tool-cid90. In the case of ultrasound surf producing tiny divergence, a new concentrated ray can be released to the test supplies. However, because of greater attenuation (attenuation means the progressive drop inside the intensity of any kind of flux by way of a moderate), large frequency waves are not able to penetrate higher absolute depths.
A programmer finally
I want to put a calendar on my website to create a delivery schedule, but it 's really not easy for a beginner. Thanks to your article, I realize the difficulty of the work. I think now hire a real programmer to do it...
Autosnap CR800 OBDII/EOBD
Autosnap CR800 OBDII/EOBD Code Reader a mini hand-help device to diagnose your vehicle. It supports all OBDII protocols on all OBDII/EOBD compliant vehicles to enable car owner or technicians to accurately diagnose engine problems. This code reader has a simple and fashionable design, to make your vehicle service experience much easier! nd900 programmer
Simple solution using the 'date' command
Like I did in the comments of the previous articles of this series, I give here a far more reasonable 12 line long solution based on the date command:
#!/bin/shdow=`date -d $1 +%w`shift
count=0
if [ `date +%s` -lt `date -d "$*" +%s` ]
then
count=1
fi
until [ `date -d "$count year ago $*" +%w` = $dow ]
do
count=`expr $count + 1`
done
date -d "$count year ago" +%Y
If you wish the calendar of the related month as the output, just replace the last line by:
ncal -d `date -d "$* $count year ago" +%Y-%m`With this line, the output of
whatyear Friday February 9correctly is:February 2007Su 4 11 18 25
Mo 5 12 19 26
Tu 6 13 20 27
We 7 14 21 28
Th 1 8 15 22
Fr 2 9 16 23
Sa 3 10 17 24
As the other comments pointed out, the result of your script obviously is wrong.
Another way is to use the Korn Shell print %T
#!/bin/ksh
day=$1
month=$2
dom=$3
year=$( printf "%(%Y)T" now )
while [[ $day != $(printf '%(%A)T' "$month $dom $year") ]]
do
(( year-- ))
done
echo $year
$ ./whatyear.sh Friday February 9
2007
$
Did you look at your tests?
Uh, am I blind or did you ask the program for Friday February 9 and then print out a calendar showing that in 2006 Feb 9th was a Thursday? And then asked for wed aug 3 and printed out a calendar for 2004 showing that August 3rd was a Tuesday?
Fix
You're testing your year, THEN decrementing it and printing out the solution and the calendar. So Feb 9th appeared in 2007. But you decrement year before you exit your loop, and then print the answer is 2006 and print the 2006 Feb calendar. That's also why you print out a non-leap year Feburary when searching for Feb. 29th. You need to either decrement and then check (which means you'd need to start with current year plus 1) or increment year after exiting the loop to account for the extra decrement. To fix the errors on Feb. 29th, just check to see if $DOW is 0, and reset it to -1 if it is in the loop.
answer
When you're in uncomfortable position and have no cash to get out from that, you would need to receive the mortgage loans (goodfinance-blog.com). Just because it should aid you unquestionably. I get car loan every time I need and feel good because of that.
Change: while [ $DOW -ne
Change:
while [ $DOW -ne $desiredDOW ]
To:
while [ "$DOW"x -ne "$desiredDOW"x ]