Every year the Microsoft Scripting Guys host a scripting challenge known as the Microsoft Scripting Games as a sort of Olympics for Windows scripters. This past year presented an interesting challenge that provided an excellent opportunity to use some of VBScript’s Date functions that I’ve been covering in my last couple articles.
There are probably a few different ways to accomplish the task I’ll be presenting you with, but the example you see here is my actual submission for this event. I believe it offers a very efficient and somewhat elegant approach to the challenge.
The challenge was simple. Participants had to write a script capable of outputting a calendar for a specified month as in the example below. The script had to allow a user to specify the month and year and then perform the correct calculations to produce the calendar for the given month in the given year.
I don’t know. Maybe you want to know on what day of the week Napoleon was born. [It was a Tuesday. --Ed.]
While the challenge did not require the calendar to be as neatly formatted as you see above, it’s not difficult at all to add the simple padding between columns, so I saw no reason not to. Participants were also not required to validate user input. It was assumed that the user would only input a correct month and year. Validation is not very hard to do. Those who would like to add validation can learn how at the end of this article series.
The challenge also stated that the script should be written for (and would be tested using) the Cscript.exe engine. For our purposes, I think it’s best to force the use of the Cscript.exe host by beginning our script with the following code.
If LCase(Right(WScript.FullName, 11)) <> "cscript.exe" Then
Very simply, this code snippet uses the WScript object’s FullName property to determine in which host engine the script is running. If it is not Cscript, then the script calls itself from the command line in the proper engine, and then terminates itself.
It is important that our script runs in Cscirpt.exe. You saw in the example on the last page that the calendar spans several lines. If the script were to run in Wscript.exe, each of these lines would result in a separate message box. For obvious reasons, we don’t want that.
If you really wanted to run this script in Wscript, you could. Instead of outputting each line in the script, you would add a line feed character and append them in a single string. This string could then be displayed in a message box. However, message boxes do not use mono-spaced, so the columns would not line up properly.
Before we can do anything at all, our script needs to get the user’s input so that it can determine from what month and year the calendar needs to build. There are two ways of doing this.
strDate = InputBox("Please enter a month and year as MM/YYYY.", "Microsoft Scripting Games 2008")
If strDate = "" Then WScript.Quit
The most obvious is to use a simple input box to receive the user input as a string. Notice in the second line that I’ve provided a little conditional statement that will end script execution if the user presses the cancel button.
WScript.StdOut.Write "Please enter a month and year as MM/YYYY:"
strDate = WScript.StdIn.ReadLine
The second option relies on the fact that our script is running in Cscript.exe. It uses the Standard Input and Output streams to receive the user’s input from within the command window.
arrDateParts = Split(strDate, "/")
intMonth = arrDateParts(0)
intYear = arrDateParts(1)
Regardless of which method you use, you should end up with the same type of string. Now is a good time to break that into parts so that we have separate date and year values. Since we know what character is being used to separate the values, VBScript’s Split function makes quick work of this, and the values can be assigned to variables in just a few simple lines.
Next we need to calculate some more values. Let’s think for a minute about the types of values that are actually needed to create a calendar. First, you obviously need a month and year—which we have. Next, you need to know how many days are in that month. Then, you need to know on which day of the week the first appears. Finally, although it’s not completely necessary, it’s also helpful to know on what weekday the last day of the month falls.
VBScript’s DateSerial function allows us to easily return a Date type for the first day of the month using the string parts that we have already. Supplying a day value of 1 obviously returns the first of that month. The WeekDay function quickly tells us on what weekday that occurs.
We’ll create a simple function called DaysInMonth to determine the number of days in a month. Quite simply, it finds the last day of the month. As it turns out, this is an Integer representation of the number of days in a month. We can then use this value to return a Date for the last day of the month. Let’s take a quick look at that function.
This function very simply finds the first day of the following month by incrementing the month value. Subtracting a single day from this number will return the last day of the month we are working with. Notice that the following month for December is actually January in the next year. A simple If statement can handle this case. If the supplied month is 12, or December, I increment that year instead and use January 1.
I then use the DateDiff function to return the integer number of days between the first day of the current month and the first day of the following month. You could just as easily do this using the DateAdd function.
DaysInMonth = Day(DateAdd("d", -1, dteNextMonth))
I could have used the DateAdd function to move the first day of the following month back a single day making it the last day of the current month. The Day function could then be used to return that Integer value. You can use whichever method you like.
If LCase(Right(WScript.FullName, 11)) <> "cscript.exe" Then
I’m out of space for this article. At this point, our script looks like this. We’ve begun our calendar script, calculated all of the necessary values, and now we’re ready to begin building our script’s output display. We’ll jump right into that in my next article.
If you want to get an early start, you can download the full code for this article here. Until next time, coding!