Conversation
src/Exceptionless.DateTimeExtensions/FormatParsers/FormatParsers/ComparisonFormatParser.cs
Fixed
Show fixed
Hide fixed
src/Exceptionless.DateTimeExtensions/FormatParsers/FormatParsers/TwoPartFormatParser.cs
Fixed
Show fixed
Hide fixed
src/Exceptionless.DateTimeExtensions/FormatParsers/FormatParsers/TwoPartFormatParser.cs
Fixed
Show fixed
Hide fixed
src/Exceptionless.DateTimeExtensions/FormatParsers/FormatParsers/ComparisonFormatParser.cs
Fixed
Show fixed
Hide fixed
There was a problem hiding this comment.
Pull request overview
This PR enhances the date math parsing functionality to fully support Elasticsearch-compatible range semantics with proper handling of bracket inclusivity, short-form comparison operators, and escaped slashes. The changes ensure that boundary inclusivity (indicated by bracket type or comparison operator) correctly controls rounding direction in date math expressions.
Changes:
- Added support for all four bracket combinations (
[],[},{],{}) in range syntax, where bracket type controls whether boundaries round to start or end of period - Implemented short-form comparison operators (
>,>=,<,<=) as syntactic sugar for one-sided ranges - Added support for escaped forward slashes (
\/) in date math expressions to accommodate contexts where/must be escaped (e.g., Lucene query syntax)
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| TwoPartFormatParser.cs | Enhanced to pre-detect closing brackets and set appropriate rounding direction (isUpperLimit) for both start and end expressions based on bracket type; updated validation to allow mixed bracket pairs |
| ComparisonFormatParser.cs | New parser implementing short-form comparison operators with correct inclusivity-based rounding |
| DateMath.cs | Updated regex patterns to support escaped forward slashes (\/) in operations; normalized escaped slashes during processing |
| TwoPartFormatParserTests.cs | Added comprehensive tests for all four bracket combinations with various rounding scenarios; removed tests for previously-invalid mixed brackets that are now valid per Elasticsearch |
| DateTimeRangeTests.cs | Added tests for comparison operators with and without rounding, covering all four operator types |
| DateMathTests.cs | Added tests verifying escaped and unescaped slashes produce identical results |
| README.md | Updated documentation with rounding behavior table, real-world patterns, and examples of the new features |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /// The parser must set inclusivity correctly so that downstream rounding | ||
| /// doesn't need separate handling. | ||
| /// | ||
| /// >value → exclusive lower bound (MinInclusive = false) → isUpperLimit = true | ||
| /// >=value → inclusive lower bound (MinInclusive = true) → isUpperLimit = false | ||
| /// <value → exclusive upper bound (MaxInclusive = false) → isUpperLimit = false | ||
| /// <=value → inclusive upper bound (MaxInclusive = true) → isUpperLimit = true |
There was a problem hiding this comment.
The documentation references MinInclusive and MaxInclusive properties that don't exist in the DateTimeRange class. While these are used conceptually to explain the operator semantics, the actual implementation doesn't track inclusivity explicitly - instead, it's encoded in the rounding behavior (isUpperLimit parameter). Consider clarifying that these are conceptual properties used for explanation, not actual class members, or rephrase the documentation to avoid suggesting they are properties of DateTimeRange.
| /// The parser must set inclusivity correctly so that downstream rounding | |
| /// doesn't need separate handling. | |
| /// | |
| /// >value → exclusive lower bound (MinInclusive = false) → isUpperLimit = true | |
| /// >=value → inclusive lower bound (MinInclusive = true) → isUpperLimit = false | |
| /// <value → exclusive upper bound (MaxInclusive = false) → isUpperLimit = false | |
| /// <=value → inclusive upper bound (MaxInclusive = true) → isUpperLimit = true | |
| /// The parser must interpret the operator's inclusive/exclusive semantics | |
| /// correctly so that downstream rounding (driven by the isUpperLimit flag) | |
| /// produces the expected boundaries. | |
| /// | |
| /// >value → exclusive lower bound → treated as an upper-limit rounding case (isUpperLimit = true) | |
| /// >=value → inclusive lower bound → treated as a lower-limit rounding case (isUpperLimit = false) | |
| /// <value → exclusive upper bound → treated as a lower-limit rounding case (isUpperLimit = false) | |
| /// <=value → inclusive upper bound → treated as an upper-limit rounding case (isUpperLimit = true) |
README.md
Outdated
| // [now/d TO now/d] → start of today through end of today (full day, inclusive both ends) | ||
| // [now/d TO now/d} → start of today through start of today (exclusive upper) | ||
| // {now/d TO now/d] → end of today through end of today (exclusive lower) | ||
| // {now/d TO now/d} → end of today through start of today (exclusive both ends) |
There was a problem hiding this comment.
The documentation for {now/d TO now/d} is misleading. The comment states "end of today through start of today", but the DateTimeRange constructor automatically swaps start and end if start > end (see DateTimeRange.cs lines 25-31). This means {now/d TO now/d} would actually produce the same result as [now/d TO now/d] (start of today through end of today) rather than an inverted or empty range. Consider either documenting this swapping behavior or using an example with different time periods that doesn't trigger the swap (like the test cases do with now-7d vs now).
| // {now/d TO now/d} → end of today through start of today (exclusive both ends) | |
| // {now/d TO now/d} → logically "end of today through start of today" (exclusive both ends), but DateTimeRange normalizes start/end so this evaluates the same as [now/d TO now/d] |
c5d7192 to
331d884
Compare
| /// <=now/d → range from MinValue to end of today | ||
| /// </summary> | ||
| [Priority(24)] | ||
| public class ComparisonFormatParser : IFormatParser |
| Assert.Equal(baseTime.StartOfDay(), range.End); | ||
| } | ||
|
|
||
| #region Short-form comparison operators (>, >=, <, <=) |
AGENTS.md
Outdated
| # AGENTS.md | ||
|
|
||
| You are an expert .NET engineer working on Exceptionless.DateTimeExtensions, a focused utility library providing DateTimeRange, Business Day/Week calculations, Elasticsearch-compatible date math parsing, and extension methods for DateTime, DateTimeOffset, and TimeSpan. Your changes must maintain backward compatibility, correctness across edge cases (especially timezone handling), and parsing reliability. Approach each task methodically: research existing patterns, make surgical changes, and validate thoroughly. | ||
| This file provides guidance to WARP (warp.dev) when working with code in this repository. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
niemyjski
left a comment
There was a problem hiding this comment.
Looks good minus the agents file
Enhance date math parsing to support escaped slashes and short-form comparison operators, ensuring consistent behavior for inclusive and exclusive boundaries. Update regex patterns and validation logic to accommodate these changes.