Hey, Scripting Guy! Question

Hey, Scripting Guy! On a Windows 2000 computer, how can I subtract days from a UTC date-time value?

-- KP

SpacerHey, Scripting Guy! AnswerScript Center

Hey, KP. Yes, we do blame all of this on Scripting Guy Dean Tsaltas. The Scripting Guy who writes this column has known Dean for six years now, and Dean has spent those entire six years complaining about the weather in the Seattle area. Not because it was bad, mind you, but because it was boring. “In the spring and summer it’s always 75 degrees and sunny,” he’d say. “In the fall and winter it’s always 50 degrees and cloudy. You could set your watch by it.”

Note. Technically, yes, you could set your watch by it. But we don’t recommend it. After all, if someone asks you the time and you reply, “Oh, it’s about 20 after 50 degrees and cloudy,” well, that just doesn’t seem all that helpful to us.

Anyway, Dean obviously complained one too many times, and, in the process, upset the weather gods. In retaliation– and in the past 12 weeks or so – we’ve had record-setting rainfall, unprecedented windstorms and power failures, and ice storms. Oh, and this past Wednesday, an unholy mixture of sleet, hail, and snow, a crazy combination which – in the city of Kirkland, at least – turned the roads from bare and dry to sheets of ice in a matter of minutes.

The best part, of course, is that the Scripting Guy who writes this column took the bus on Wednesday, primarily because he wanted the Scripting Son to have the better car, just in case the predictions of heavy snow came true. Although he is somewhat ashamed to admit this, the Scripting Guy who writes this column usually doesn’t take the bus, mainly because he has to transfer. But on Wednesday he didn’t have to transfer.

That’s because his first bus could only get within 8 or 9 blocks of the transfer station before a car darted in front of it. That caused the bus driver to have to stop on an icy hill, and that caused the bus to get stuck. Consequently, all the passengers had to get off and walk to the transfer station in downtown Kirkland.

In turn, that meant that the Scripting Guy who writes this column missed his transfer; he could see the bus rounding the corner and driving off just as he reached the transfer station. Not wanting to stand around in the cold for 30 minutes waiting for the next bus, he decided to walk for awhile.

Within a few minutes he caught up to and then passed his bus, a bus which hadn’t moved an inch since rounding he corner. Shrugging his shoulders the Scripting Guy trudged on; within a few minutes he passed another bus, a bus which had to have been sitting in traffic for at least half an hour. Not too far down the road he passed a third bus, one which had to have been sitting in traffic for at least an hour. Although it’s about 5 miles from downtown Kirkland to the Scripting Home, the Scripting Guy who writes this column decided he’d just walk the rest of the way.

And for good reason: for the first 3 miles or so of his journey the only time he saw a car move was when a driver gave up, pulled off to the side of the road, and parked. At that point each car would then creep forward one car length. But that didn’t happen too often. After all, this is Seattle, and people don’t get out of their car for anything around here. You name it and we have a drive-through window for it: the bank, the fast food place, the coffee shop, the pharmacy. Microsoft has yet to install a drive-through window where employees can pull up and do their work without ever having to leave their car, but we’re sure it’s coming.

Anyway, an hour or so later the Scripting Guy who writes this column walked through his front door, a little cold and quite a bit wet. Thanks a lot, Dean!

On the bright side, though, the walk did give him plenty of time to come up with a script that can subtract a specified number of days (say, 30) from a UTC value. The script is still a bit cold and a bit wet, but here goes:

strComputer = "."

Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set objOS = objWMIService.ExecQuery("Select * from Win32_OperatingSystem")
 
For Each strOS in objOS
    dtmInstallDate = strOS.InstallDate
    dtmDate = CDate(Mid(dtmInstallDate, 5, 2) & "/" & _
        Mid(dtmInstallDate, 7, 2) & "/" & Left(dtmInstallDate, 4))
    Wscript.Echo dtmDate - 30
Next

Obviously the first step in subtracting days from a UTC (Universal Time Coordinate) value is to get yourself a UTC value. Rather than create a make-believe value we opted to use a real one: the date that the operating system was installed on the local computer. To that end, we start off by connecting to the WMI service on the local computer, then use this line of code to retrieve a collection consisting of the current operating system installed on that computer:

Set objOS = objWMIService.ExecQuery("Select * from Win32_OperatingSystem")

Note. Yes, we know: it would be very cool if, on a multi-boot machine, this code could retrieve a collection of all the operating systems installed on the computer. Unfortunately, though, that’s not the case; the best we can do is identify the operating system currently in use.

Next we set up a For Each loop to loop through our collection (which, again, will have only one item in it). Inside that loop we grab the value of the InstallDate property and store it in a variable named dtmInstallDate. On our test computer that means that dtmInstallDate is equal to this:

20060301162313.000000-480

Note. No, the Scripting Guy who writes this column didn’t freeze his brain. That really is the installation date; it’s just in UTC format. If you need more information on deciphering a UTC value see the Microsoft Windows 2000 Scripting Guide.

Now, if we were running Windows XP, Windows Server 2003, or Windows Vista, our job would be much easier; that’s because we could use the SWbemDateTime object to easily convert this UTC value to a “real” date-time value. However, we’re running on Windows 2000; therefore, we need to use this crazy-looking code in order to convert 20060301162313.000000-480 to a real date:

dtmDate = CDate(Mid(dtmInstallDate, 5, 2) & "/" & _
    Mid(dtmInstallDate, 7, 2) & "/" & Left(dtmInstallDate, 4)) 

As it turns out, there’s actually a little rhyme and reason to a UTC value:

The first four digits – 2006 – represent the year.

The next two digits – 03 – represent the month.

The next two digits – 01 – represent the day.

In other words, our UTC value (ignoring hours and minutes and seconds) happens to be March 1, 2006. That oddball line of code is simply using the Mid and Left functions to grab the appropriate characters in the string, combine them with a few forward slash characters (/), and then create the date value 03/01/2006. In other words:

Mid(dtmInstallDate, 5, 2) grabs the month: characters 5 and 6.

Mid(dtmInstallDate, 7, 2) grabs the day: characters 7 and 8.

Left(dtmInstallDate, 4) grabs the year: characters 1, 2, 3, and 4.

Put them all together and run them through the CDate function (which converts a string value to a date-time value) and we end up with a “real” date: 03/01/2006. And once we have a real date, subtracting 30 days from it (and echoing back the value) is as easy as this:

Wscript.Echo dtmDate - 30

Does that really work? Of course it does:

1/30/2006

And, sure, you could convert 1/30/2006 to a UTC value if you wanted to or needed to; for more information, see the Scripting Guide. We’d loan you our copy, except we had to burn it in order to keep warm during our 5-mile slog through the snow and sleet.