Exceptionless.DateTimeExtensions

repository·main·Indexed 42 days ago

https://github.com/exceptionless/exceptionless.datetimeextensions

A suite of extension methods for DateTime, DateTimeOffset, and TimeSpan, featuring specialized utilities for Business Days, TimeUnit parsing, and DateMath operations. It includes a DateTimeRange class that supports Elasticsearch-style date math expressions, bracket notation, and timezone-aware parsing.

Tokens
3.5K
Snippets
10
Records
11
Agent score
4%

What's inside Exceptionless.DateTimeExtensions

  1. Understand rounding behavior in DateTimeRange boundaries

    main

    Rounding direction (/d, /M, etc.) is determined by the inclusivity of the boundaries, following Elasticsearch conventions.

    Inclusive boundaries round to maximize the matched range:

    • Inclusive min ([): rounds down (start of period).
    • Inclusive max (]): rounds up (end of period).

    Exclusive boundaries round to minimize the matched range:

    • Exclusive min ({): rounds up (end of period).
    • Exclusive max (}): rounds down (start of period).
    BoundaryBracketOperatorRounding directionnow/d resolves to
    Inclusive lower[>=Floor (start of period)2025-02-16T00:00:00
    Exclusive lower{>Ceiling (end of period)2025-02-16T23:59:59.999
    Inclusive upper]<=Ceiling (end of period)2025-02-16T23:59:59.999
    Exclusive upper}<Floor (start of period)2025-02-16T00:00:00
  2. Use Elasticsearch date math syntax in DateTimeRange

    main

    The library supports full Elasticsearch date math syntax for defining ranges:

    • Anchors: now, or explicit dates using the || separator.
    • Operations: +1d (add), -1h (subtract), /d (round).
    • Units: y (years), M (months), w (weeks), d (days), h/H (hours), m (minutes), s (seconds).
    • Timezone Support: Preserves explicit timezones (Z, +05:00, -08:00) or falls back to the system timezone.
    • Escaped slashes: \/d is treated identically to /d.
    // Common date range queries
    var last15Minutes = DateTimeRange.Parse("[now-15m TO now]", now);     // 15 minutes ago through now
    var lastHour     = DateTimeRange.Parse("[now-1h/h TO now-1h/h]", now); // Start through end of last hour
    var last24Hours  = DateTimeRange.Parse("[now-24h TO now]", now);      // 24 hours ago through now
    var today        = DateTimeRange.Parse("[now/d TO now/d]", now);      // Start of day through end of day
    var yesterday    = DateTimeRange.Parse("[now-1d/d TO now-1d/d]", now); // Start through end of yesterday
    var tomorrow     = DateTimeRange.Parse("[now+1d/d TO now+1d/d]", now); // Start through end of tomorrow
    var last7Days    = DateTimeRange.Parse("[now-7d/d TO now-1d/d]", now); // Last 7 full days (not including today)
    var thisWeek     = DateTimeRange.Parse("[now/w TO now/w]", now);      // Start of week through end of week
    var lastWeek     = DateTimeRange.Parse("[now-1w/w TO now-1w/w]", now); // Start through end of last week
    var thisMonth    = DateTimeRange.Parse("[now/M TO now/M]", now);      // Start of month through end of month
    var lastMonth    = DateTimeRange.Parse("[now-1M/M TO now-1M/M]", now); // Start through end of last month
    var yearToDate   = DateTimeRange.Parse("[now/y TO now]", now);        // Start of year through now
    var lastYear     = DateTimeRange.Parse("[now-1y/y TO now-1y/y]", now); // Start through end of last year
    
    // Short-form comparison operators
    var recentItems  = DateTimeRange.Parse(">=now-1h", now);    // From 1 hour ago to max
    var futureOnly   = DateTimeRange.Parse(">now", now);         // After now to max
    var beforeToday  = DateTimeRange.Parse("<now/d", now);       // Min to start of today
    var throughToday = DateTimeRange.Parse("<=now/d", now);      // Min to end of today
  3. Install Exceptionless.DateTimeExtensions via NuGet

    main

    You can install the Exceptionless.DateTimeExtensions package using the NuGet package manager to access extended functionality for DateTimeRange, Business Day, and various DateTime, DateTimeOffset, and TimeSpan extension methods.

    # Install via NuGet Package Manager Console
    Install-Package Exceptionless.DateTimeExtensions
  4. Calculate if a datetime is within business hours using BusinessDay

    main

    The BusinessDay class allows you to define business hours and check if a specific DateTime falls within those hours. You can specify the day of the week and the start/end times for the business day.

    var date = DateTime.Now.StartOfDay().AddHours(8);
    
    var day = new BusinessDay(date.Date.DayOfWeek,
        date.Subtract(TimeSpan.FromHours(1)).TimeOfDay,
        date.AddHours(1).TimeOfDay);
    
    bool isDay = day.IsBusinessDay(date);
  5. Work with date ranges using DateTimeRange

    main

    The DateTimeRange class provides support for parsing Elasticsearch-style date math expressions and bracket notation (e.g., [start TO end]). It supports wildcard notation for open-ended ranges and preserves timezone information.

    // Basic range parsing
    var range = DateTimeRange.Parse("yesterday", DateTime.Now);
    if (range.Contains(DateTime.Now.Subtract(TimeSpan.FromHours(6)))) {
      //...
    }
    
    // Elasticsearch Date Math support with proper timezone handling
    var elasticRange = DateTimeRange.Parse("2025-01-01T01:25:35Z||+3d/d", DateTime.Now);
    
    // Bracket notation support [start TO end]
    var bracketRange = DateTimeRange.Parse("[2023-01-01 TO 2023-12-31]", DateTime.Now);
    
    // Wildcard support for open-ended ranges
    var wildcardRange = DateTimeRange.Parse("[2023-01-01 TO *]", DateTime.Now); // From date to infinity
  6. Parse time units with TimeUnit

    main

    The TimeUnit class allows you to parse string representations of time durations into TimeSpan objects.

    TimeSpan oneNanosecond = TimeUnit.Parse("1nanos");
    TimeSpan oneMicrosecond = TimeUnit.Parse("1micros");
    TimeSpan oneMillisecond = TimeUnit.Parse("1ms");
    TimeSpan oneSecond = TimeUnit.Parse("1s");
    TimeSpan oneMinute = TimeUnit.Parse("1m");
    TimeSpan oneHour = TimeUnit.Parse("1h");
    TimeSpan oneDay = TimeUnit.Parse("1d");
  7. Use DateTimeOffset extension methods

    main

    The library provides extension methods for DateTimeOffset to easily find the start or end of a month and to generate approximate age strings.

    using Exceptionless.DateTimeExtensions;
    
    DateTimeOffset.Now.ToApproximateAgeString(); // "Just now"
    var startOfMonth = DateTimeOffset.Now.ToStartOfMonth();
    var endOfMonth = DateTimeOffset.Now.ToEndOfMonth();
  8. Use DateTime extension methods

    main

    The library provides several extension methods for the DateTime type to simplify common operations like finding the start of a minute or calculating approximate age strings.

    using Exceptionless.DateTimeExtensions;
    
    DateTime.Now.ToApproximateAgeString(); // "Just now"
    var time = DateTime.Now.StartOfMinute();
    var lastWeek = DateTime.Now.LastWeek();
    var nextWeek = DateTime.Now.NextWeek();
  9. Use TimeZoneInfo with DateMath

    main

    You can provide a TimeZoneInfo object to DateMath methods. When using now in an expression, it will resolve based on the provided timezone. Note that if the expression contains an explicit timezone (e.g., +05:00), that timezone is preserved and takes precedence over the TimeZoneInfo parameter.

    using Exceptionless.DateTimeExtensions;
    
    var utcTimeZone = TimeZoneInfo.Utc;
    var easternTimeZone = TimeZoneInfo.FindSystemTimeZoneById("US/Eastern");
    
    // "now" will use current time in the specified timezone
    var utcResult = DateMath.Parse("now+1h", utcTimeZone);
    var easternResult = DateMath.Parse("now/d", easternTimeZone, isUpperLimit: false);
    
    // TryParse with timezone
    if (DateMath.TryParse("now+2d-3h", easternTimeZone, false, out var result)) {
        Console.WriteLine($"Eastern time result: {result:O}");
    }
    
    // Dates without explicit timezone use the provided TimeZoneInfo
    var localDate = DateMath.Parse("2023-06-15T14:30:00||+1M", easternTimeZone);
    
    // Dates with explicit timezone are preserved regardless of TimeZoneInfo parameter
    var preservedTz = DateMath.Parse("2023-06-15T14:30:00+05:00||+1M", easternTimeZone);
  10. Parse date math expressions with DateMath

    main

    The DateMath utility class provides direct access to Elasticsearch date math expression parsing without requiring the full DateTimeRange functionality. It supports Parse (throws on error), TryParse (returns bool), and timezone-aware overloads.

    using Exceptionless.DateTimeExtensions;
    
    // Parse date math expressions with standard .NET conventions
    var baseTime = DateTimeOffset.Now;
    
    // Parse method - throws ArgumentException on invalid input
    var result = DateMath.Parse("now+1h", baseTime);
    var rounded = DateMath.Parse("now-1d/d", baseTime, isUpperLimit: false); // Start of yesterday
    
    // TryParse method - returns bool for success/failure
    if (DateMath.TryParse("2023.06.15||+1M/d", baseTime, false, out var parsed)) {
        Console.WriteLine($"Parsed: {parsed:O}");
    }
    
    // Upper limit behavior affects rounding
    var startOfDay = DateMath.Parse("now/d", baseTime, isUpperLimit: false); // 00:00:00
    var endOfDay = DateMath.Parse("now/d", baseTime, isUpperLimit: true);     // 23:59:59.999
    
    // Explicit dates with timezone preservation
    var utcResult = DateMath.Parse("2025-01-01T01:25:35Z||+3d/d", baseTime);
    var offsetResult = DateMath.Parse("2023-06-15T14:30:00+05:00||+1M", baseTime);