@@ -218,21 +218,44 @@ public bool Evaluate(object left, string expression, bool convertNumericString)
218218 private bool TryConvertStringToDouble ( string right , out double result )
219219 {
220220 result = 0d ;
221- if ( double . TryParse ( right , out double val ) )
221+ if ( double . TryParse ( right , out double val ) )
222222 {
223223 result = val ;
224224 return true ;
225225 }
226- else
226+ // Time-like strings ("10:04", "7 AM") go to the time parser; everything
227+ // else is offered to DateTime.TryParse first so date criteria like
228+ // ">=2026-2-1" compare against the actual date serial rather than the
229+ // time-string parser's midnight fallback (which would yield 0).
230+ if ( ! LooksLikeTime ( right ) && DateTime . TryParse ( right , out DateTime date ) )
227231 {
228- var timeVal = _timeStringParser . Parse ( right ) ;
229- if ( double . IsNaN ( timeVal ) )
232+ result = date . ToOADate ( ) ;
233+ return true ;
234+ }
235+ var timeVal = _timeStringParser . Parse ( right ) ;
236+ if ( double . IsNaN ( timeVal ) )
237+ {
238+ return false ;
239+ }
240+ result = timeVal ;
241+ return true ;
242+ }
243+
244+ private static bool LooksLikeTime ( string s )
245+ {
246+ if ( string . IsNullOrEmpty ( s ) ) return false ;
247+ if ( s . IndexOf ( ':' ) >= 0 ) return true ;
248+ var trimmed = s . TrimEnd ( ) ;
249+ if ( trimmed . Length >= 2 )
250+ {
251+ var suffix = trimmed . Substring ( trimmed . Length - 2 ) ;
252+ if ( string . Equals ( suffix , "AM" , StringComparison . OrdinalIgnoreCase ) ||
253+ string . Equals ( suffix , "PM" , StringComparison . OrdinalIgnoreCase ) )
230254 {
231- return false ;
255+ return true ;
232256 }
233- result = timeVal ;
234- return true ;
235257 }
258+ return false ;
236259 }
237260 }
238261}
0 commit comments