IsDateItemHoliday

Determine if a date item is a market holiday

Overview

IsDateItemHoliday is the exported, self-locking counterpart of the internal IsMarketHoliday(). It accepts a DATE_LOG_HANDLE, DATE_RANGE_HANDLE or HOLIDAYS_HANDLE, resolves and locks the associated holidays handle as needed, and delegates the actual holiday check.

Unlike the BOOL predicates in this family, the result is a signed int with three outcomes: 1 (holiday), 0 (not a holiday) and -1 (error). Always test for a negative result before treating the value as a boolean, because -1 is non-zero and would be misread as “is a holiday” in an if test.

Key Features

Function Signature


signed int _Check_return_ _On_failure_(return < 0) IsDateItemHoliday(
    _In_ DATE_ITEM_HANDLE       hDateItem,
    _In_ DATE_COLLECTION_HANDLE hDateLogHandle
);

_On_failure_(return < 0) documents that a negative return value signals failure. datelog.h declares the related IsDateItemMarketHoliday(hDateItem, hHolidays), which takes a HOLIDAYS_HANDLE and is documented there as returning 1 for a weekend or holiday, 0 for a valid market day and -1 on error; this page documents the date-collection-handle form IsDateItemHoliday and its holiday-only wording.

Parameters

hDateItem

[In] DATE_ITEM_HANDLE

The date item to check.

hDateLogHandle

[In] DATE_COLLECTION_HANDLE

A DATE_LOG_HANDLE, DATE_RANGE_HANDLE or HOLIDAYS_HANDLE that supplies (or is) the holidays handle used for the check.

Return Values

ValueMeaning
1The date is a market holiday.
0The date is not a market holiday.
-1Invalid parameters, a locking failure, or an internal error occurred.

The function returns plain integers, not HRESULTs; do not use SUCCEEDED/FAILED on the result. The related error codes ERR_DATE_IS_HOLIDAY, ERR_INVALID_DATELOG_HANDLE and ERR_INVALID_HOLIDAY_HANDLE in date_error.h are returned by other functions and are all folded into -1 or 1 here as described above.

Remarks

Thread Safety

The function resolves and locks the holidays handle it needs for the duration of the check and unlocks it afterwards, so calls from different threads against the same shared context are serialized by the library. A locking failure is reported as -1. Duplicate the handle with DuplicateDateLogHandle to give each thread its own handle.

Handle Lifetime and Ownership

Ordering and Related Functions

Note: -1 is non-zero. Writing if (IsDateItemHoliday(...)) treats errors as holidays. Compare against 1, 0 and < 0 explicitly.

See Also

Sample Code

The sample builds a holidays handle and a date log for 2025-01-02 through 2025-03-31, creates a date item for each candidate date, and classifies it with IsDateItemHoliday using explicit handling of the three possible results. Holiday dates that the library refuses to turn into items are reported separately. All items and handles are released on every path.


#include <Windows.h>
#include <stdio.h>
#include "datelog.h"

static BOOL MakeFileTime(WORD wYear, WORD wMonth, WORD wDay, PFILETIME pFt)
{
    SYSTEMTIME st = { 0 };

    st.wYear = wYear;
    st.wMonth = wMonth;
    st.wDay = wDay;
    return SystemTimeToFileTime(&st, pFt);
}

/* Creates a holidays handle and loads it with the range [first, last]. */
static HRESULT BuildHolidays(PFILETIME pFirst, PFILETIME pLast, HOLIDAYS_HANDLE *phHolidays)
{
    HRESULT hr = S_OK;
    HOLIDAYS_HANDLE hHolidays = NULL;
    DATE_ITEM_HANDLE hFirst = NULL;
    DATE_ITEM_HANDLE hLast = NULL;

    *phHolidays = NULL;

    hr = InitializeDateLogHandle(NULL, DATE_LOG_MAX, NULL, &hHolidays, HandleIsForHolidays);
    if (FAILED(hr)) goto cleanup;

    hr = InitializeDateItem(hHolidays, pFirst, NULL, &hFirst);
    if (FAILED(hr)) goto cleanup;

    hr = InitializeDateItem(hHolidays, pLast, NULL, &hLast);
    if (FAILED(hr)) goto cleanup;

    hr = LoadDateLogHandle(NULL, hFirst, hLast, hHolidays, NULL, 0);
    if (FAILED(hr)) goto cleanup;

    *phHolidays = hHolidays;
    hHolidays = NULL;

cleanup:
    FreeDateItem(hLast);
    FreeDateItem(hFirst);
    if (hHolidays != NULL) {
        (void)CloseDateLogHandle(hHolidays);
    }
    return hr;
}

/* Creates a date log or range handle of the given type and generates [first, last] into it. */
static HRESULT BuildCollection(HOLIDAYS_HANDLE hHolidays, DateHandleType type,
                               PFILETIME pFirst, PFILETIME pLast, DATE_LOG_HANDLE *phCollection)
{
    HRESULT hr = S_OK;
    DATE_LOG_HANDLE hCollection = NULL;
    DATE_ITEM_HANDLE hFirst = NULL;
    DATE_ITEM_HANDLE hLast = NULL;

    *phCollection = NULL;

    hr = InitializeDateLogHandle(NULL, DATE_LOG_MAX, hHolidays, &hCollection, type);
    if (FAILED(hr)) goto cleanup;

    hr = InitializeDateItem(hHolidays, pFirst, NULL, &hFirst);
    if (FAILED(hr)) goto cleanup;

    hr = InitializeDateItem(hHolidays, pLast, NULL, &hLast);
    if (FAILED(hr)) goto cleanup;

    hr = LoadDateLogHandle(NULL, hFirst, hLast, hCollection, NULL, 0);
    if (FAILED(hr)) goto cleanup;

    *phCollection = hCollection;
    hCollection = NULL;

cleanup:
    FreeDateItem(hLast);
    FreeDateItem(hFirst);
    if (hCollection != NULL) {
        (void)CloseDateLogHandle(hCollection);
    }
    return hr;
}

typedef struct _SAMPLE_DATE {
    WORD wYear;
    WORD wMonth;
    WORD wDay;
} SAMPLE_DATE;

int main(void)
{
    static const SAMPLE_DATE candidates[] = {
        { 2025,  1, 20 },   /* a Monday; may be a holiday depending on the holidays data */
        { 2025,  2, 18 },   /* an ordinary trading day              */
        { 2025,  3, 31 }
    };
    int exitCode = 1;
    HRESULT hr = S_OK;
    FILETIME ftFirst = { 0 };
    FILETIME ftLast = { 0 };
    HOLIDAYS_HANDLE hHolidays = NULL;
    DATE_LOG_HANDLE hDateLog = NULL;
    size_t i = 0;

    if (!MakeFileTime(2025, 1, 2, &ftFirst) || !MakeFileTime(2025, 3, 31, &ftLast)) {
        printf("Invalid calendar date.\n");
        return 1;
    }

    hr = BuildHolidays(&ftFirst, &ftLast, &hHolidays);
    if (FAILED(hr)) {
        printf("BuildHolidays failed: 0x%08lX\n", (unsigned long)hr);
        goto cleanup;
    }

    hr = BuildCollection(hHolidays, HandleIsForDatelog, &ftFirst, &ftLast, &hDateLog);
    if (FAILED(hr)) {
        printf("BuildCollection failed: 0x%08lX\n", (unsigned long)hr);
        goto cleanup;
    }

    for (i = 0; i < sizeof(candidates) / sizeof(candidates[0]); i++) {
        FILETIME ft = { 0 };
        DATE_ITEM_HANDLE hItem = NULL;
        int holiday = 0;

        if (!MakeFileTime(candidates[i].wYear, candidates[i].wMonth, candidates[i].wDay, &ft)) {
            continue;
        }

        hr = InitializeDateItem(hDateLog, &ft, NULL, &hItem);
        if (hr == ERR_DATE_IS_HOLIDAY) {
            /* The library refuses to create an item for a holiday or weekend. */
            printf("%04u-%02u-%02u: InitializeDateItem reports a holiday or weekend\n",
                   candidates[i].wYear, candidates[i].wMonth, candidates[i].wDay);
            continue;
        }
        if (FAILED(hr)) {
            printf("%04u-%02u-%02u: InitializeDateItem failed: 0x%08lX\n",
                   candidates[i].wYear, candidates[i].wMonth, candidates[i].wDay, (unsigned long)hr);
            continue;
        }

        holiday = IsDateItemHoliday(hItem, hDateLog);
        if (holiday < 0) {
            printf("%04u-%02u-%02u: the holiday check failed\n",
                   candidates[i].wYear, candidates[i].wMonth, candidates[i].wDay);
        } else if (holiday == 1) {
            printf("%04u-%02u-%02u: market holiday\n",
                   candidates[i].wYear, candidates[i].wMonth, candidates[i].wDay);
        } else {
            printf("%04u-%02u-%02u: not a market holiday\n",
                   candidates[i].wYear, candidates[i].wMonth, candidates[i].wDay);
        }

        FreeDateItem(hItem);
    }

    exitCode = 0;

cleanup:
    if (hDateLog != NULL) {
        (void)CloseDateLogHandle(hDateLog);
    }
    if (hHolidays != NULL) {
        (void)CloseDateLogHandle(hHolidays);
    }
    return exitCode;
}