You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
# Agent Guidelines for Exceptionless.DateTimeExtensions
1
+
# AGENTS.md
2
2
3
-
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.
3
+
This file provides guidance to WARP (warp.dev) when working with code in this repository.
4
4
5
-
**Craftsmanship Mindset**: Every line of code should be intentional, readable, and maintainable. Write code you'd be proud to have reviewed by senior engineers. Prefer simplicity over cleverness. When in doubt, favor explicitness and clarity.
6
-
7
-
## Repository Overview
5
+
## Overview
8
6
9
7
Exceptionless.DateTimeExtensions provides date/time utilities for .NET applications:
- Target **netstandard2.0**: be mindful of API availability
117
109
- Use `ConfigureAwait(false)` in library code (not in tests)
110
+
- Private/internal fields use `_camelCase` prefix
118
111
119
112
### Parsing & Date Math Patterns
120
113
@@ -128,192 +121,24 @@ The library uses a **priority-ordered parser chain** for `DateTimeRange.Parse()`
128
121
### Common Patterns
129
122
130
123
-**Extension methods**: Group by target type (`DateTimeExtensions.cs`, `DateTimeOffsetExtensions.cs`, `TimeSpanExtensions.cs`)
131
-
-**Safe arithmetic**: Use overflow-protected add/subtract methods (`SafeAdd`, `SafeSubtract`) to avoid `ArgumentOutOfRangeException`
132
-
-**Start/End helpers**: Provide `StartOf*` and `EndOf*` for all time periods (minute, hour, day, week, month, year)
133
-
-**Exceptions**: Use `ArgumentException` for invalid input. Use `FormatException` for parsing failures. Return `false` from `TryParse` methods instead of throwing.
134
-
135
-
### Single Responsibility
136
-
137
-
- Each class has one reason to change
138
-
- Methods do one thing well; extract when doing multiple things
139
-
- Keep files focused: one primary type per file
140
-
- Each parser handles one specific format pattern
141
-
- If a method needs a comment explaining what it does, it should probably be extracted
142
-
143
-
### Performance Considerations
144
-
145
-
-**Avoid allocations in hot paths**: Parsing methods are called frequently; minimize string allocations
124
+
-**Safe arithmetic**: Use `SafeAdd`, `SafeSubtract` to avoid `ArgumentOutOfRangeException`
125
+
-**Exceptions**: Use `ArgumentException` for invalid input, `FormatException` for parsing failures. Return `false` from `TryParse` methods.
146
126
-**Compiled regex**: Use `RegexOptions.Compiled` for frequently-used patterns
147
-
-**Span-based parsing**: Where compatible with netstandard2.0, prefer span-based approaches
148
-
-**Profile before optimizing**: Don't guess—measure
149
-
-**Cache parser instances**: Parsers are discovered once via reflection and reused
150
-
151
-
## Making Changes
152
-
153
-
### Before Starting
154
-
155
-
1.**Gather context**: Read related files, search for similar implementations, understand the full scope
156
-
2.**Research patterns**: Find existing usages of the code you're modifying using grep/semantic search
157
-
3.**Understand completely**: Know the problem, side effects, and edge cases before coding
158
-
4.**Plan the approach**: Choose the simplest solution that satisfies all requirements
159
-
5.**Check dependencies**: Verify you understand how changes affect dependent code
160
-
161
-
### Pre-Implementation Analysis
162
-
163
-
Before writing any implementation code, think critically:
164
-
165
-
1.**What could go wrong?** Consider timezone edge cases, overflow/underflow, leap years, DST transitions
166
-
2.**What are the parsing edge cases?** Ambiguous input, whitespace, case sensitivity, partial matches
167
-
3.**What assumptions am I making?** Validate each assumption against existing tests
168
-
4.**Is this the root cause?** Don't fix symptoms—trace to the core problem
169
-
5.**Is there existing code that does this?** Search before creating new utilities
170
-
171
-
### Test-First Development
172
-
173
-
**Always write or extend tests before implementing changes:**
174
-
175
-
1.**Find existing tests first**: Search for tests covering the code you're modifying
176
-
2.**Extend existing tests**: Add test cases to existing test classes/methods when possible for maintainability
177
-
3.**Write failing tests**: Create tests that demonstrate the bug or missing feature
178
-
4.**Implement the fix**: Write minimal code to make tests pass
179
-
5.**Refactor**: Clean up while keeping tests green
180
-
6.**Verify edge cases**: Add tests for boundary conditions, timezone handling, and error paths
181
-
182
-
**Why extend existing tests?** Consolidates related test logic, reduces duplication, improves discoverability, maintains consistent test patterns.
183
-
184
-
### While Coding
185
-
186
-
-**Minimize diffs**: Change only what's necessary, preserve formatting and structure
187
-
-**Preserve behavior**: Don't break existing functionality or change semantics unintentionally
188
-
-**Build incrementally**: Run `dotnet build` after each logical change to catch errors early
189
-
-**Test continuously**: Run `dotnet test` frequently to verify correctness
190
-
-**Match style**: Follow the patterns in surrounding code exactly
191
-
192
-
### Validation
193
-
194
-
Before marking work complete, verify:
195
-
196
-
1.**Builds successfully**: `dotnet build Exceptionless.DateTimeExtensions.slnx` exits with code 0
197
-
2.**All tests pass**: `dotnet test Exceptionless.DateTimeExtensions.slnx` shows no failures
198
-
3.**No new warnings**: Check build output for new compiler warnings (warnings are treated as errors)
199
-
4.**API compatibility**: Public API changes are intentional and backward-compatible when possible
200
-
5.**Timezone correctness**: Verify explicit timezones are preserved and rounding respects offset
201
-
6.**Breaking changes flagged**: Clearly identify any breaking changes for review
202
-
203
-
### Error Handling
204
-
205
-
-**Validate inputs**: Check for null, empty strings, invalid ranges at method entry
206
-
-**Fail fast**: Throw exceptions immediately for invalid arguments (don't propagate bad data)
207
-
-**Meaningful messages**: Include parameter names and expected values in exception messages
208
-
-**TryParse pattern**: Always provide a `TryParse` alternative that returns `bool` instead of throwing
209
-
-**Use guard clauses**: Early returns for invalid conditions, keep happy path unindented
210
127
211
128
## Testing
212
129
213
-
### Philosophy: Battle-Tested Code
214
-
215
-
Tests are not just validation—they're **executable documentation** and **design tools**. Well-tested code is:
216
-
217
-
-**Trustworthy**: Confidence to refactor and extend
218
-
-**Documented**: Tests show how the API should be used
219
-
-**Resilient**: Edge cases are covered before they become production bugs
220
-
221
-
### Framework
222
-
223
-
-**xUnit** as the primary testing framework
224
-
-**Foundatio.Xunit** provides `TestWithLoggingBase` for test output logging
225
-
- Follow [Microsoft unit testing best practices](https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-best-practices)
226
-
227
-
### Test-First Workflow
228
-
229
-
1.**Search for existing tests**: `dotnet test --filter "FullyQualifiedName~MethodYouAreChanging"`
230
-
2.**Extend existing test classes**: Add new `[Fact]` or `[Theory]` cases to existing files
231
-
3.**Write the failing test first**: Verify it fails for the right reason
232
-
4.**Implement minimal code**: Just enough to pass the test
233
-
5.**Add edge case tests**: Null inputs, timezone boundaries, leap years, DST transitions, overflow
234
-
6.**Run full test suite**: Ensure no regressions
235
-
236
-
### Test Principles (FIRST)
237
-
238
-
-**Fast**: Tests execute quickly
239
-
-**Isolated**: No dependencies on external services or execution order
240
-
-**Repeatable**: Consistent results every run
241
-
-**Self-checking**: Tests validate their own outcomes
242
-
-**Timely**: Write tests alongside code
243
-
244
-
### Naming Convention
245
-
246
-
Use the pattern: `MethodName_StateUnderTest_ExpectedBehavior`
Copy file name to clipboardExpand all lines: README.md
+42-2Lines changed: 42 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -56,12 +56,52 @@ var wildcardRange = DateTimeRange.Parse("[2023-01-01 TO *]", DateTime.Now); // F
56
56
57
57
#### Date Math Features
58
58
59
-
Supports full Elasticsearch date math syntax following [official specifications](https://www.elastic.co/guide/en/elasticsearch/reference/current/common-options.html#date-math):
59
+
Supports full [Elasticsearch date math syntax](https://www.elastic.co/guide/en/elasticsearch/reference/current/common-options.html#date-math):
60
60
61
61
-**Anchors**: `now`, explicit dates with `||` separator
-**Timezone Support**: Preserves explicit timezones (`Z`, `+05:00`, `-08:00`) or uses system timezone as fallback
65
+
-**Escaped slashes**: `\/d` is treated identically to `/d` for contexts where `/` must be escaped
66
+
67
+
##### Real-World Patterns
68
+
69
+
```csharp
70
+
// Common date range queries
71
+
varthisMonth=DateTimeRange.Parse("[now/M TO now/M]", now); // Start of month through end of month
72
+
varlastMonth=DateTimeRange.Parse("[now-1M/M TO now/M}", now); // Start of last month through start of this month
73
+
varyearToDate=DateTimeRange.Parse("[now/y TO now]", now); // Start of year through now
74
+
varlast7Days=DateTimeRange.Parse("[now-7d/d TO now]", now); // Start of 7 days ago through now
75
+
varlast15Minutes=DateTimeRange.Parse("[now-15m TO now]", now); // 15 minutes ago through now
76
+
varlast24Hours=DateTimeRange.Parse("[now-24h TO now]", now); // 24 hours ago through now
77
+
vartomorrow=DateTimeRange.Parse("[now+1d/d TO now+1d/d]", now); // Start through end of tomorrow
78
+
79
+
// Short-form comparison operators
80
+
varrecentItems=DateTimeRange.Parse(">=now-1h", now); // From 1 hour ago to max
81
+
varfutureOnly=DateTimeRange.Parse(">now", now); // After now to max
82
+
varbeforeToday=DateTimeRange.Parse("<now/d", now); // Min to start of today
83
+
varthroughToday=DateTimeRange.Parse("<=now/d", now); // Min to end of today
84
+
```
85
+
86
+
##### Rounding Behavior with Boundaries
87
+
88
+
Rounding direction (`/d`, `/M`, etc.) is controlled by boundary inclusivity, following [Elasticsearch range query rounding rules](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-query.html#date-math-rounding):
89
+
90
+
| Boundary | Bracket | Operator | Rounding direction |`now/d` resolves to |
0 commit comments