Tags: exceptionless/Exceptionless.DateTimeExtensions
Tags
Adds null/empty checks to date math parsing Ensures that the `DateMath.Parse` and `TimeUnit.Parse` methods handle null or empty expressions gracefully by throwing `ArgumentException` or `ArgumentNullException` as appropriate. This prevents unexpected behavior and improves the robustness of the date parsing logic. Also updates `TryParse` methods to accept nullable string parameters.
Modernize library: target net8.0/net10.0, source-gen regex, records, … …immutability (#131) * Modernize library: target net8.0/net10.0, source-gen regex, records, immutability - Drop netstandard2.0, target net8.0 and net10.0 LTS - Convert all Regex fields to [GeneratedRegex] on partial methods - Convert BusinessDay and DateTimeRange to record types - Convert AgeSpan to readonly record struct - Embrace immutability: IReadOnlyList, FrozenDictionary, get/init properties - Enable nullable reference types and implicit usings - Use String./Int32./Char. for static method calls per project convention - Use ReadOnlySpan<char> in TimeUnit and Helper for zero-alloc parsing - Restore all contextual comments stripped during modernization - Preserve public API: restore protected virtual Validate on BusinessWeek - Upgrade test project to xUnit v3 with Microsoft Testing Platform Co-authored-by: Cursor <cursoragent@cursor.com> * Fix CI build: suppress test-only nullable warnings and entry point conflict Co-authored-by: Cursor <cursoragent@cursor.com> * Fix CI: register GitHubActionsTestLogger MTP extension and address PR feedback - Explicitly register GitHubActionsTestLogger as a TestingPlatformBuilderHook to fix --report-github Unknown option error in CI (the packages build props do not flow correctly with single TargetFramework projects) - Remove redundant RegexOptions.Compiled from all [GeneratedRegex] attributes (source generator already compiles at build time) - Use pattern matching null checks (is null) instead of == null - Wrap List<T> assignments with .AsReadOnly() for true immutability on IReadOnlyList<T> properties in ComparisonFormatParser and TwoPartFormatParser Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
Fix date math rounding to respect inclusive/exclusive bracket boundar… …ies (#129) * Fix date math rounding to respect inclusive/exclusive bracket boundaries Previously, TwoPartFormatParser always passed isUpperLimit=false for the start side and isUpperLimit=true for the end side of a range, regardless of bracket type. This is only correct for inclusive [...] brackets. Per Elasticsearch conventions, rounding behavior must change based on whether each boundary is inclusive or exclusive: - Inclusive min ([): rounds down (start of period) — gte semantics - Exclusive min ({): rounds up (end of period) — gt semantics - Inclusive max (]): rounds up (end of period) — lte semantics - Exclusive max (}): rounds down (start of period) — lt semantics This means [now/d TO now/d] correctly produces the entire day (start to end), while {now/d TO now/d} collapses, and mixed brackets like [now/d TO now/d} produce start-of-day to start-of-day. Changes: - Pre-scan closing bracket before parsing parts so isUpperLimit is known upfront (uses a simple backwards char scan, no extra regex) - Pass bracket-aware isUpperLimit to part parsers; wildcard parsers still receive positional isUpperLimit (false=min, true=max) since they use it for position semantics rather than rounding - Allow mixed bracket pairs ([..}, {..]) per Elasticsearch Lucene syntax - Add comprehensive tests for all four bracket combinations with /d, /M, /h rounding and mixed date math operations - Document rounding behavior in README with reference table and common date range patterns Ref: FoundatioFx/Foundatio.Lucene@a8426ab Co-authored-by: Cursor <cursoragent@cursor.com> * Address PR review feedback - Simplify boolean ternary expressions per CodeQL: replace `A ? false : B` with `A is not X && B` and `A ? true : B` with `A is X || B` for the wildcard type checks - Collapse inverted ranges from exclusive brackets instead of letting DateTimeRange reorder bounds and unintentionally expand the range - Update test comment to reflect the explicit collapse behavior Co-authored-by: Cursor <cursoragent@cursor.com> * Fixes bracket parsing logic for inclusivity Corrects the logic for determining inclusive and exclusive date ranges based on brackets. Improves the bracket parsing logic to handle null or empty content and bracket characters, ensuring accurate date range calculations. Also fixes the IsValidBracketPair function to improve bracket validation. --------- Co-authored-by: Cursor <cursoragent@cursor.com>
[Breaking] Enforce case-sensitive date math parsing per Elasticsearch… … spec (#128) Align DateMath parsing with the Elasticsearch date math specification by enforcing case-sensitive matching. The anchor 'now' must be lowercase, and date-math units are case-sensitive (M=months, m=minutes, d=days, D=invalid). Additionally improve string comparison quality across all parsers by replacing instance .Equals() and == with String.Equals(), and eliminating culture-sensitive .ToLower() allocations in favor of String.Equals with OrdinalIgnoreCase or .ToLowerInvariant() where switch statements require it. Breaking changes: - 'Now', 'NOW', and other mixed-case variants of 'now' are no longer valid - Uppercase units D, Y, W, S are no longer valid (were silently accepted) Co-authored-by: Cursor <cursoragent@cursor.com>
Enhances DateMath parser for broader expression support Refines the DateMath regular expression to allow more flexible matching, including positional anchoring and boundary detection. This enables parsing within larger strings, addressing issues with bracketed and curly brace date math expressions. Also introduces DateTimeRangeTests for comprehensive testing of date range parsing and calculation.
PreviousNext