GetDateItemHandleGap

Calculate the number of market days between two date items in a date log

Overview

GetDateItemHandleGap calculates the number of market days between two date items within a validated date log handle context. This function is the public-facing wrapper around the core GetMarketDaysGap() implementation, providing thread-safe mutex protection and handle validation.

Purpose

This function enables applications to determine the count of business/market days between two dates, excluding weekends and holidays as defined by the date log's associated holidays collection. The result can be:

Key Features

Function Signature


LONG _Check_return_ _Success_(return != DATE_LOG_SENTINEL) GetDateItemHandleGap(
    _In_    DATE_LOG_HANDLE   hDateLogHandle,
    _In_    DATE_ITEM_HANDLE  hStartDate,
    _In_    DATE_ITEM_HANDLE  hEndDate,
    _In_    DateGapSpec       DateGapType
);
            

Calling Convention

Standard C calling convention with SAL annotations for parameter validation and return value inspection.

SAL Annotations Explained

Parameters

hDateLogHandle

[In] DATE_LOG_HANDLE

Handle to the date log that owns the date items and provides access to the holidays collection.

  • Must be a valid DATE_LOG_HANDLE obtained from InitializeDateLogHandle() or LoadDateLogHandle()
  • Must have been validated via IsValidDateLogHandle() before calling this function
  • Provides access to the associated holidays handle for market day validation
  • If NULL or invalid, function returns DATE_LOG_SENTINEL
hStartDate

[In] DATE_ITEM_HANDLE

Handle to the starting date item for gap calculation.

  • Must be a valid DATE_ITEM_HANDLE previously retrieved or initialized
  • Can represent any calendar date, not necessarily within the date log
  • Start and end dates can be in any order (function handles both directions)
  • If NULL, function returns DATE_LOG_SENTINEL
hEndDate

[In] DATE_ITEM_HANDLE

Handle to the ending date item for gap calculation.

  • Must be a valid DATE_ITEM_HANDLE previously retrieved or initialized
  • Can represent any calendar date, not necessarily within the date log
  • Start and end dates can be in any order (function handles both directions)
  • If NULL, function returns DATE_LOG_SENTINEL
DateGapType

[In] DateGapSpec

Specifies whether the gap includes or excludes the boundary dates.

Enumeration Value Numeric Description
ExclusiveDateGap 0 Excludes both boundary dates from the count. Counts only dates strictly between start and end. Adjacent dates yield gap of -1.
InclusiveDateGap 1 Includes both boundary dates in the count. For identical dates, returns 0. For adjacent dates, returns 1. Recommended for most use cases.
Validation: If DateGapType value is greater than 1, function returns DATE_LOG_SENTINEL.

Return Values

Success Cases

Positive LONG

Gap calculation succeeded. Positive value indicates end date is chronologically after start date. Magnitude represents count of market days.

0 (Zero)

Both dates are identical (with inclusive gap specification).

Negative LONG

End date is chronologically before start date. Magnitude represents absolute count of market days between dates.

Error Cases

DATE_LOG_SENTINEL (0xFFFFFFFF)

Gap calculation failed. Returned in these scenarios:

Return Value Interpretation Table

Return Value Meaning Action
> 0 End date is after start date; magnitude is day count Use value for gap calculation
== 0 Dates are identical Use value; no gap exists
< 0 End date is before start date; negate for absolute count Use abs(value) or negate based on logic
DATE_LOG_SENTINEL Error occurred; computation not performed Check handle validity and date values; retry if appropriate

Behavior and Operations

Execution Flow

Validate Handle
Validate Dates
Acquire Mutex
Compute Gap
Release Mutex

Step-by-Step Process

1. Handle Validation

Calls IsValidDateLogHandle(hDateLogHandle). If false, returns DATE_LOG_SENTINEL immediately.

2. Parameter Validation

Checks:

If any check fails, returns DATE_LOG_SENTINEL.

3. Mutex Acquisition

Acquires ((PDATE_LOG)hDateLogHandle)->pContext->hMutex with INFINITE timeout.

Blocking Call: This function will block indefinitely until the mutex is acquired. No timeout is applied, unlike MergeDateLogHandle() or other operations.

4. Gap Computation

Within the __try block, calls GetMarketDaysGap() with:

5. Mutex Release

In the __finally block, always releases the mutex to ensure cleanup even on exception.

Holiday Handling

The function delegates to GetMarketDaysGap(), which:

Bidirectional Gap Calculation

The underlying GetMarketDaysGap() handles date order internally:

Examples

Example 1: Calculate Gap Between Two Dates (Inclusive)

// Assuming hDateLog is valid and contains dates from 2025-01-01 onwards
// Weekends and holidays are properly configured

DATE_ITEM_HANDLE hDate1 = NULL;
DATE_ITEM_HANDLE hDate2 = NULL;

// Create date items for 2025-01-06 (Monday) and 2025-01-10 (Friday)
FILETIME ft1 = { /* 2025-01-06 */ };
FILETIME ft2 = { /* 2025-01-10 */ };

InitializeDateItem(hDateLog, &ft1, NULL, &hDate1);
InitializeDateItem(hDateLog, &ft2, NULL, &hDate2);

// Calculate market days between the dates (inclusive)
LONG lGap = GetDateItemHandleGap(
    hDateLog,
    hDate1,
    hDate2,
    InclusiveDateGap  // Include both boundary dates
);

if (lGap != DATE_LOG_SENTINEL) {
    printf("Market days from Jan 6 to Jan 10: %ld\n", lGap);  
    // Output: 5 (Mon, Tue, Wed, Thu, Fri)
} else {
    printf("Error calculating gap\n");
}

FreeDateItem(hDate1);
FreeDateItem(hDate2);
                
Example 2: Reversed Date Order (Negative Gap)

// Dates provided in reverse chronological order

DATE_ITEM_HANDLE hLater = NULL;   // 2025-01-10
DATE_ITEM_HANDLE hEarlier = NULL; // 2025-01-06

// ... initialize hLater and hEarlier ...

LONG lGap = GetDateItemHandleGap(
    hDateLog,
    hLater,      // Passed as "start" (chronologically later)
    hEarlier,    // Passed as "end" (chronologically earlier)
    InclusiveDateGap
);

if (lGap != DATE_LOG_SENTINEL) {
    printf("Gap: %ld\n", lGap);  
    // Output: -5 (negative because end is before start)
    printf("Absolute gap: %ld\n", labs(lGap));  
    // Output: 5
} else {
    printf("Error calculating gap\n");
}
                
Example 3: Error Handling with Invalid Parameters

DATE_LOG_HANDLE hDateLog = NULL;
DATE_ITEM_HANDLE hDate1 = NULL;
DATE_ITEM_HANDLE hDate2 = NULL;

// ... initialize handles ...

// Case 1: Invalid date log handle
LONG lGap = GetDateItemHandleGap(NULL, hDate1, hDate2, InclusiveDateGap);
if (lGap == DATE_LOG_SENTINEL) {
    printf("Error: Invalid date log handle\n");  // Expected
}

// Case 2: NULL date items
lGap = GetDateItemHandleGap(hDateLog, NULL, hDate2, InclusiveDateGap);
if (lGap == DATE_LOG_SENTINEL) {
    printf("Error: NULL start date\n");  // Expected
}

// Case 3: Invalid gap type (> 1)
lGap = GetDateItemHandleGap(hDateLog, hDate1, hDate2, 99);
if (lGap == DATE_LOG_SENTINEL) {
    printf("Error: Invalid gap type\n");  // Expected
}
                
Example 4: Inclusive vs. Exclusive Gap Specification

// Same two dates, different gap specifications

DATE_ITEM_HANDLE hDate1 = /* Monday */;
DATE_ITEM_HANDLE hDate2 = /* Tuesday */;

// Inclusive: counts both Mon and Tue
LONG lInclusiveGap = GetDateItemHandleGap(
    hDateLog,
    hDate1,
    hDate2,
    InclusiveDateGap
);
printf("Inclusive gap: %ld\n", lInclusiveGap);  // Output: 1 (Mon and Tue counted)

// Exclusive: counts no dates between Mon and Tue (adjacent dates)
LONG lExclusiveGap = GetDateItemHandleGap(
    hDateLog,
    hDate1,
    hDate2,
    ExclusiveDateGap
);
printf("Exclusive gap: %ld\n", lExclusiveGap);  // Output: -1 (no dates between)
                

Threading and Concurrency

Thread Safety

Fully thread-safe. The function acquires the date log context mutex before accessing the holidays handle or performing gap calculation.

Synchronization Details

Multiple Thread Scenario


// Thread 1
LONG gap1 = GetDateItemHandleGap(hDateLog, hDate1, hDate2, InclusiveDateGap);

// Thread 2 (may block if Thread 1 is still computing)
LONG gap2 = GetDateItemHandleGap(hDateLog, hDate3, hDate4, InclusiveDateGap);

// Thread 3 (may also block)
LONG gap3 = GetDateItemHandleGap(hDateLog, hDate5, hDate6, InclusiveDateGap);

// Threads execute sequentially with mutex serialization
            

Blocking Behavior

Warning: Because this function uses INFINITE timeout for mutex acquisition, calling threads will block indefinitely if:
  • Another thread is holding the mutex and never releases it
  • The mutex is corrupted or invalid
  • A deadlock occurs in the holidays holiday lookup logic
Consider implementing application-level timeouts if unbounded blocking is unacceptable.

Important Notes and Considerations

Performance Characteristics

Input Constraints

Holiday and Weekend Configuration

Important: The gap calculation respects the holiday handle's weekend and holiday configuration. Ensure the date log's associated holidays handle is properly populated before calling this function.

Error Recovery

If this function returns DATE_LOG_SENTINEL:

  1. Verify hDateLogHandle is valid via IsValidDateLogHandle()
  2. Verify hStartDate and hEndDate are not NULL
  3. Verify DateGapType is 0 or 1
  4. Verify neither date is a weekend or holiday
  5. Check system resources (memory, mutexes)
  6. Review application logs for internal error details

Sentinel Value Semantics

Sentinel Value: DATE_LOG_SENTINEL (0xFFFFFFFF or -1 as signed LONG) is used to indicate error. This value should never be returned on success, but applications must check return value explicitly before using the result.

Related Functions