Hey, Scripting Guy! Question

Hey, Scripting Guy! We have a logon script that needs to perform certain tasks only on the first and second Mondays of the month. How can I determine whether the script is running on the first or second Monday in a month?

-- WA

SpacerHey, Scripting Guy! AnswerScript Center

Hey, WA. You know, a few months ago the Scripting Guy who writes this column noticed that his watch had stopped; consequently, he went to the store and paid $20 to get a new battery. Less than two months later his watch stopped again. Could the battery have died after just two months? Maybe, but, then again, maybe his watch was truly broken. With that in mind the Scripting Guy who writes this column went back to the store and this time, rather than buy a new battery, he bought a new watch that was on sale for $9.95.

Now, we know what you’re thinking, you’re thinking, “Why would one of the world-famous Scripting Guys wear a $9.95 watch? Shouldn’t the Scripting Guys all wear Rolexes or something like that?”

No, they shouldn’t. And here’s why. Last night this Scripting Guy was boiling water in preparation for cooking some noodles. (Of course, the Scripting Guy who writes this column can cook. Any time you want boiling water for dinner just let him know.) As he reached across the stove to turn down the burner, his $9.95 watch somehow slipped off his arm and plopped into the pot of boiling water.

Amazingly enough, the watch continued to work; being immersed in boiling water for a minute or so had no effect on it whatsoever. Try doing that with a Rolex!

Note. Never mind; whatever you do don’t try doing that with a Rolex. Microsoft’s insurance company probably won’t be too happy if thousands of people suddenly start filing claims for new Rolex watches just because the Scripting Guys told them to try dunking those watches in boiling water.

So what does any of that have to do with writing a script that can determine whether it’s running on the first or second Monday of the month? As near as we can tell, nothing. But it you’ve ever wondered what the Scripting Guy who writes this column is really like, well, now you know.

Note. But please don’t tell the other Scripting Guys about this incident. After all, they look at the Scripting Guy who writes this column as if he was Mary Poppins: practically perfect in every way.

Editor’s Note. Please don’t tell the Scripting Guy who writes this column that the other Scripting Guys know better. He’s happy in his little fantasy world, we’d hate to ruin that for him.

But don’t despair, WA; the following chunk of code should help a bit more when it comes to writing a script that can determine whether it’s running on the first or second Monday of the month:

Dim arrMondays(1)

dtmMonth = Month(Date)
dtmYear = Year(Date)
dtmDate = CDate(dtmMonth & "/1" & "/" & dtmYear)

Do Until i = 1
    intWeekDay = Weekday(dtmDate)
    If intWeekDay = 2 Then
        arrMondays(0) = dtmDate
        arrMondays(1) = dtmDate + 7
        Exit Do
    End If
    dtmDate = dtmDate + 1
Loop

For Each strMonday in arrMondays
    If Date = strMonday Then
        Wscript.Echo "Carry out the task."
    Else
        Wscript.Echo "Don't carry out the task."
    End If
Next

So how does this script work? You would have to ask us that, wouldn’t you?

Well, let’s see if we can figure it out. We start out by declaring an array named arrMondays, and sizing this array so that it can hold two items:

Dim arrMondays(1)

Why two items? Because we need to determine the dates of the first two Mondays in the month. Two Mondays, two slots in the array.

Next we use this block of code to construct a date equal to the first day of the current month:

dtmMonth = Month(Date)
dtmYear = Year(Date)
dtmDate = CDate(dtmMonth & "/1" & "/" & dtmYear)

As you can see, in the first two lines of code we use the Month function to determine the current month, then use the Year function to determine the current year. In line 3, we string those two values, the number 1 and a few / marks together in order to create a date like this:

2/1/2007

Good question: what is the CDate function for in the preceding line of code? Well, CDate is short for character-to-date; it’s designed to convert a string value to a date-time value. We include it here to make sure that 2/1/2007 gets treated as a date and not as a string.

That’s another good question: why do we care about the first day of the month anyway? Well, we have no idea when the first and second Mondays occur; on top of that, we don’t know any fancy way to determine when the first and second Mondays do occur. So we’re going to simply start with the first day of the month and see if it happens to be a Monday. We’ll then check the second day of the month and see if it happens to be a Monday. And then we’ll check the third day of the month and …. We’ll continue checking, day-by-day, until we find the first Monday. And once we know the date of the first Monday all we’ll have to do is add 7 days and we’ll know the date of the second Monday.

Note. And, yes, suppose we wanted to run the script on the first and third Mondays: in that case, all we’d need to do is add 14 to the date of the first Monday.

Here’s the block of code we use to determine the dates of the first two Mondays:

Do Until i = 1
    intWeekDay = Weekday(dtmDate)
    If intWeekDay = 2 Then
        arrMondays(0) = dtmDate
        arrMondays(1) = dtmDate + 7
        Exit Do
    End If
    dtmDate = dtmDate + 1
Loop

What we’ve done here is set up a Do Until loop designed to run until the counter variable i is equal to 0; in effect this is a loop designed to run until we specifically exit the thing. (Why? Because the way the script is constructed, i will never be equal to 0.) Inside that loop we use the Weekday function to determine the day of the week for the first day in the month:

intWeekDay = Weekday(dtmDate)

The Weekday function returns an integer value for the day of the week: 1 for Sunday, 2 for Monday, 3 for Tuesday, etc. Because we only care about Mondays we check to see if intWeekDay is equal to 2. Suppose it isn’t. In that case, we simply add one day to the date-time value dtmDate, loop around, and make this same check with the second day of the month:

dtmDate = dtmDate + 1

But what happens when we do find a Monday? In that case, we assign the value of dtmDate to the first item in the array; we then add 7 days to that value and assign the resulting date to the second item in the array:

arrMondays(0) = dtmDate
arrMondays(1) = dtmDate + 7

And then we call the Exit Do statement and exit the loop.

All that’s left now is to loop through the two dates in the array and check to see if either one happens to be the current date; if it is, then the script must be running on either the first or second Monday of the month. If it is the first or second Monday we’d then run a specified bit of code. In our sample script, we simply echo back whether we should (or should not) perform the appointed task:

For Each strMonday in arrMondays
    If strMonday = Date Then
        Wscript.Echo "Carry out the task."
    Else
        Wscript.Echo "Don't carry out the task."
    End If
Next

That’s all there is to it.

You know, speaking of time, time is definitely running out on the 2007 Winter Scripting Games; in fact, the Games officially end tomorrow morning (February 23, 2007) at 8:00 Redmond time. We know you have your eyes on one of those Dr. Scripto Bobblehead dolls, and there’s only one way to get one: enter at least one event in the Scripting Games, and thus get your name in the Bobblehead drawing. Did we mention that time is running out? Oh. Well, it’s worth mentioning again: time is running out.