Convert Bstr To DateTime in WMI
C++ If you’re not familiar with the Win32_NTLogEvent API provided by WMI, you can use it very easily with WMI to gain access to all the Windows Event Logs in a system programatically

Fortunately Microsoft provides a very good reference to these API functions – I can see from the online documentation that is has a structure

class Win32_NTLogEvent
{
uint16   Category;
string   CategoryString;
string   ComputerName;
uint8    Data[];
uint16   EventCode;
uint32   EventIdentifier;
uint8    EventType;
string   InsertionStrings[];
string   Logfile;
string   Message;
uint32   RecordNumber;
string   SourceName;
datetime TimeGenerated;
datetime TimeWritten;
string   Type;
string   User;
};

We can see here that one of the fields claims to be a datetime

datetime TimeGenerated

Upon debugging and casting to a BSTR I can see that the provider is just building a string from a date time in the format

YYYYMMDDHHMMSS….

Convert bstr to date time

What I want is to be able to format it as a string and either cast it directly to a datetime object or keep it as a string and send it off the database to be stored as a datetime2 object with timezone information

Thus, the desired format is

YYYY-MM-DD HH:MM:SS+ssZ
e.g. 2019-05-07 10:14:10+0700

First of all I need to break the long bstr string into the date time parts

if (timeGenerated.bstrVal != NULL)
{
	// convert to YYYY-MM-DD HH:MM:SS
	eventLogItem.TimeGenerated = _bstr_t(timeGenerated.bstrVal);
	eventLogItem.TimeGenerated = eventLogItem.TimeGenerated.substr(0, 4) + "-" +
		eventLogItem.TimeGenerated.substr(4, 2) + "-" +
		eventLogItem.TimeGenerated.substr(6, 2) + " " +
		eventLogItem.TimeGenerated.substr(8, 2) + ":" +
		eventLogItem.TimeGenerated.substr(10, 2) + ":" +
		eventLogItem.TimeGenerated.substr(12, 2);
}

This will give me the string in the format YYYY-MM-DD HH:MM:SS

Getting the date time format YYYY-MM-DD HH:MM:SS

So what about the time zone? – Well that’s a bit more tricky

First we want to get a Time Zone Information structure filled by the Windows Operating System

// Get the current timezone information
TIME_ZONE_INFORMATION timezone;
memset(&timezone, 0, sizeof(PTIME_ZONE_INFORMATION));
GetTimeZoneInformation(&timezone);

If we look at the structure

typedef struct _TIME_ZONE_INFORMATION {
  LONG       Bias;
  WCHAR      StandardName[32];
  SYSTEMTIME StandardDate;
  LONG       StandardBias;
  WCHAR      DaylightName[32];
  SYSTEMTIME DaylightDate;
  LONG       DaylightBias;
} TIME_ZONE_INFORMATION, *PTIME_ZONE_INFORMATION, *LPTIME_ZONE_INFORMATION;

We can see the LONG Bias; field.

Microsoft says

The current bias for local time translation on this computer, in minutes. The bias is the difference, in minutes, between Coordinated Universal Time (UTC) and local time. All translations between UTC and local time are based on the following formula:

UTC = local time + bias

So we need to multiply the bias by negative 1 to get the correct +- and divide by 60 to get the hour component

// we want format like +0700 or -11.30
float offsetHours = (timezone.Bias * -1 ) / 60.0F;
string fractional = std::to_string(offsetHours).substr(2, 2);

We also need to take into account partial date time offsets in India like GMT+5:30

Next we just need to pad out the string add the leading +=

// get possible leading 0
string offsetHoursString = offsetHours < 10 ? "0" + std::to_string((int)offsetHours) + fractional : offsetHoursString + fractional;

// add thr +- prefix
offsetHoursString = offsetHours > 0 ? "+" + offsetHoursString : "-" + offsetHoursString;

The final product is the formatted string with timezone taken from the local computer

Finished bstr datetime conversion with timezone offset
Written by admin