Working with Dates in WMI

As you begin scripting with WMI, you will quickly learn that WMI uses its own date and time format. In order to build queries in WMI you will need an understanding of this date and time format as well as a knowledge of how to convert between WMI dates and traditional VBScript dates.

WMI uses the CMI_Datetime format, commonly referred to as simply datetime.  On the surface, the datetime format is a string representation of a given date and time.  Like the VBScript’s VT_Date format, this is local to the current system.  Let’s take a look at an example.

strComputer = "."

 

Set objWMIService = GetObject("winmgmts:" & strComputer & "rootcimv2")

 

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

 

For Each objOperatingSystem In colOperatingSystems

    Wscript.Echo objOperatingSystem.InstallDate

Next

This simple WMI script returns the date that the current operating was installed.

20080213195848.000000-300

At first glance, this script’s output is a bit ambiguous.  In fact, it looks almost cryptic.  But deciphering the datetime format is really not as hard as it might seem.

{mospagebreak title=The Datetime format}

Again, the Datetime format is just a string representation.  This statement includes a couple of points that you should keep in mind.  First, dates and times in WMI are always treated as strings; and second, this is a formatted string—meaning that the string has several parts.

The string appears to be a fixed width floating point number.  It actually has a set number of digit groups, each relating to a part of the date and time.  It can be broken down into these parts very easily.

20080213195848.000000-300

Going back to the example date that we found in the beginning of this article, we can break this down into a legible date and time.  The string you see actually represents February 13, 2008 7:58 PM EST.  Here’s how.

  • The first four digits represent a four digit year: 2008.
  • The next two digits represent a two digit month: 02, or February.
  • The next two digits represent a two digit day: 13, the 13th of the month.
  • The next two digits represent a two digit hour in 24-hour format: 19, or 7 PM.
  • The next two digits represent a two digit minute: 58.
  • The final two digits before the decimal point represent a two digit second: 48.
  • The first six digits following the decimal point represent microseconds.  These are often not used, but must be represented by zeros to maintain the fixed length of the Datetime value.
  • The last portion of the datetime format is a signed three digit value that represents the time zone as a GMT offset: -300, or minus 300 minutes (GMT -5 Hours).  This represents Eastern Standard Time.

So the fixed width Datetime format looks like this:  YYYYMMDDhhmmss.mmmmmm±UUU

It’s important to understand the last (UUU) portion of this thoroughly.  By definition this is the offset in number of minutes that the time deviates from UTC.  This is why it is recommended that dates are first converted to GMT, since GMT has a UTC offset value of 0.

{mospagebreak title=Converting VBScript dates to WMI Dates} 

VBScript dates must first be converted to WMI’s datetime format if you wish to use them in a query.  This can be done easily by building a function that serves this purpose.  However, WMI’s COM interface provides a class specifically for working with date and time conversions.

dtmDate = #January 1, 2008#

 

Set dateTime = CreateObject("WbemScripting.SWbemDateTime")

 

dateTime.SetVarDate(dtmDate, True)

 

WScript.Echo "CIM datetime " & dateTime

WScript.Echo "Local datetime " & dateTime.GetVarDate()

The WbemScripting object’s SWbemDateTime class returns a date or time as a datetime value.  By creating an instance of this object class, you can easily prepare dates and times for use in WMI queries.  Since the SWbemDateTime class’s default method is Value, a reference to the object will return the datetime value without specifying the actual Value property.

CIM datetime 20080101000000.000000-300
Local datetime 1/1/2008

The SetVarDate method is used to set the datetime value by providing a VBScript date.  It accepts a VBScript Date value as its parameter.  A second, optional parameter is a Boolean value that indicates whether the time is a local time or GMT time.  This is the easiest way to get a date from VBScript into WMI datetime format.  You are not, however, limited to this conversion.  The SWbemDateTime class has several other useful methods as well for returning date and time portions.

dtmDate = Now()

 

Set dateTime = CreateObject("WbemScripting.SWbemDateTime")

 

dateTime.SetVarDate(Now)

 

WScript.Echo "Year:" & dateTime.Year

WScript.Echo "Month:" & dateTime.Month

WScript.Echo "Day:" & dateTime.Day

WScript.Echo "Hours:" & dateTime.Hours

WScript.Echo "Minutes:" & dateTime.Minutes

WScript.Echo "Seconds:" & dateTime.Seconds

WScript.Echo "Microseconds:" & dateTime.Microseconds

WScript.Echo "UTC Offset:" & dateTime.UTC

The example above enumerates each of the properties that the SWbemDateTime class provides for returning date and time portions.  These are self explanatory. 

Year:2008
Month:9
Day:10
Hours:23
Minutes:48
Seconds:22
Microseconds:0
UTC Offset:-240

Here you see that the UTC offset is -240.  Earlier, on this same system the offset was -300.  What does that mean?  The Eastern Time Zone in the United States observes Daylight Savings Time.  Each spring our clock moves ahead one hour, reducing the UTC offset by 60 minutes.  Thus, the current offset is only -240 when daylight savings time is being observed.

{mospagebreak title=Converting WMI dates to VBScript Dates}

You will also need to be able to convert WMI’s datetime values into VBScript’s Date values.  There are two approaches to this.  The first is obvious.

strComputer = "."

Set objWMIService = GetObject("winmgmts:" & strComputer & "rootcimv2")

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

 

For Each objOperatingSystem In colOperatingSystems

    WScript.Echo DatetimeToDate(objOperatingSystem.InstallDate)

Next

 

Function DatetimeToDate(strDate)

   DatetimeToDate = _

       CDate(Mid(strDate, 5, 2) & _

       "/" & _

       Mid(strDate, 7, 2) & _

       "/" & _

       Left(strDate, 4) & _

       " " & _

       Mid (strDate, 9, 2) & _

       ":" & _

       Mid(strDate, 11, 2) & _

       ":" & _

       Mid(strDate, 13, 2))

End Function

This example again returns the date on which the current operating system was installed.  This time, the value is being converted to a VT_Date compatible string.  Since WMI’s DateTime format is nothing more than a formatted string, VBScript’s string functions can be used to extract the necessary parts.  Here, the DatetimeToDate function takes a datetime string such as “20080101000000.000000-300” and converts it to a string like “01/01/2008 00:00:00.”  This string is then converted to a VBScript Date value using the CDate function.

Function DatetimeToDate(strUTC)

   Set datetime = CreateObject("WbemScripting.SWbemDateTime")

   datetime.Value = strUTC

 

   DatetimeToDate = datetime.GetVarDate(True)

End Function

A simpler version of this function could be constructed using the WMI COM object I showed you previously.  In this case, the datetime value is used to set the SWbemDateTime object’s Value property directly.  Then the GetVarDate method is used to return the VBS-compatible Date.  Notice that this function accepts a single Boolean value that indicates whether the returned date is considered local or returned in GMT (adjusted for the offset).

{mospagebreak title=Building Queries with Dates}

Now that you’ve seen how to convert between VBScript Date values and WMI datetime values, let’s move on to the good stuff and learn how to construct queries using dates and times.

Keep in mind that datetime values must contain all parts for both the date and the time.  Any unused values should be added as zeros.

Remember that datetime values are nothing more than strings.  Thus, they can be very easily added to a query, since queries themselves are strings.  Like other string values, datetime values should be surrounded with single quotation marks.

dtmTargetDate = #09/01/2008#

Set datetime = CreateObject("WbemScripting.SWbemDateTime")

datetime.SetVarDate(dtmTargetDate)

 

strComputer = "."

Set objWMIServices = GetObject("winmgmts:{impersonationLevel=impersonate}!" & strComputer & "rootcimv2")

 

Set colFolders = objWMIServices.ExecQuery("SELECT * FROM Win32_Directory WHERE CreationDate > ‘" & datetime & "’")

For Each objFolder in colFolders

   WScript.Echo objFolder.Name

Next

The WMI query in this example will list all files created since the date provided.  It uses the W32_Directory class to iterate through the files on the current system, checking each file’s creation date.  The W32_Directory’s CreationDate property returns a file’s creation date in standard WMI datetime format.  Thus, you must convert a date to this format before querying this value.

As you can see, using date and time values in VBScript can be confusing.  When you add WMI into the mix, this only gets more complicated.  But if you take things slow, and think carefully, you can avoid most common pitfalls. 

Also, keep in mind that both VBScript’s VT_Date format and WMI’s DateTime format are both relative to the local system’s regional settings.  Whenever scripting across platforms or querying remote systems, you should always deal strictly with GMT times (and avoid time zones) whenever possible.  Until next time, keep coding!

3 thoughts on “Working with Dates in WMI

[gp-comments width="770" linklove="off" ]