Matthew Long’s post on the useful DayTimeExpression
module of the System.ExpressionFilter
data filter is the only useful information I could find on its use, save for the MSDN documentation. However, in using the module, I’ve noticed what appears to be a bug in its implementation.
The problem
The module works by checking whether a date-time is bound (or not bound, as defined by <InRange />
) by a window that’s defined by (a) a days of the week mask and (b) a time window, the start and end of which are specified by the number of seconds since midnight. The problem appears to be that the date-time is interpreted as local time, despite being defined in ISO 8601 format, e.g. 2015-05-29T17:15:00Z
, rather than being correctly interpreted as UTC and converted to local time before being checked against the defined window. This problem occurs whether a date-time is manually specified, e.g. <Value Type="DateTime">2015-05-29T17:15:00Z</Value>
, or is obtained at runtime, e.g. <XPathQuery Type="DateTime">./@time</XPathQuery>
.
The workaround
It may be possible to solve this problem using XQuery/XPath, but my solution is to return the current local date-time from the PowerShell script called by the data source, albeit presented as UTC in ISO 8601 format. For example, if the script were executed at 17:15 (local time), the script would return, in its property bag, a property with a value of 2015-05-29T17:15:00Z
. This is a hack, as, because I’m on BST (UTC+1), this value should be 2015-05-29T16:15:00Z
, but this triggers the bug.
In my PowerShell script:
$Bag.AddValue("Date-time executed (local time)", (Get-Date).ToString("yyyy-MM-ddTHH:mm:ssZ"))
In my monitor type:
<Expression> <DayTimeExpression> <ValueExpression> <XPathQuery Type="DateTime">Property[@Name='Date-time executed (local time)']</XPathQuery> </ValueExpression> <StartTime>$Config/SecondsFromMidnightCheckWindowStart$</StartTime> <EndTime>$Config/SecondsFromMidnightCheckWindowEnd$</EndTime> <Days>$Config/DaysOfWeekMask$</Days> <InRange>true</InRange> </DayTimeExpression> </Expression>
I am now able to define the window using the number of seconds from midnight, local time, and System.ExpressionFilter
correctly checks this window against the execution time.
It is not a bug.
DataItemElement class has a method which converts string to DateTime:
public DateTime ToDateTime()
{
if (elementType == DataItemElementType.DateTime)
{
return dateTimeValue;
}
if (elementType == DataItemElementType.String)
{
return XmlConvert.ToDateTime(stringValue, XmlDateTimeSerializationMode.Utc);
}
throw new FormatException(string.Format(CultureInfo.CurrentUICulture, ExceptionMessages.FormatExceptionDateTimeConversion, ToString()));
}
As you see it always expects that your value is UTC and it formatted as xsd:dateTime (ISO 8601).