Determine if a date item is covered by a holidays handle's range
IsDateItemCoveredByHolidaysHandle is the exported, self-locking counterpart of the internal IsDateCoveredByHolidaysHandle(). It accepts either a DATE_LOG_HANDLE/DATE_RANGE_HANDLE (from which the associated holidays handle is extracted) or a HOLIDAYS_HANDLE directly, validates and locks whichever handles it needs, and returns whether hDateItem falls strictly within the holidays handle’s covered range and is not itself a holiday.
The covered range is documented as the half-open interval [first, last) of the holidays core: the first date of the core is covered, the last date of the core is not. Because the result is a BOOL, the function cannot tell you which of the failing conditions occurred.
DATE_COLLECTION_HANDLE); the holidays handle is resolved internally when a log or range is supplied.FALSE for dates that are outside the covered range, for dates that are themselves holidays, for invalid parameters and for locking or handle-resolution failures.
BOOL _Check_return_ IsDateItemCoveredByHolidaysHandle(
_In_ DATE_ITEM_HANDLE hDateItem,
_In_ DATE_COLLECTION_HANDLE hDateLogHandle
);
_Check_return_ means the result must be inspected. DATE_COLLECTION_HANDLE is the generic collection handle type declared in datelog.h; it can hold any of DATE_LOG_HANDLE, DATE_RANGE_HANDLE or HOLIDAYS_HANDLE.
[In] DATE_ITEM_HANDLE
The date item to test.
InitializeDateItem, GetDateItemCopy or FindDateItemHandle.FALSE is returned.FreeDateItem.[In] DATE_COLLECTION_HANDLE
A DATE_LOG_HANDLE, DATE_RANGE_HANDLE or HOLIDAYS_HANDLE.
InitializeDateLogHandle or DuplicateDateLogHandle, or a holidays handle returned by GetDateLogHolidayHandle. For a log or range, the handle must have an associated holidays handle; for a holidays handle, its core must be populated.FALSE is returned.CloseDateLogHandle. The function does not retain it after returning.| Value | Condition |
|---|---|
TRUE | hDateItem is within [first, last) of the holidays core and is not a holiday itself. |
FALSE | The item is not covered, is itself a holiday, a parameter is invalid, or a locking / handle-resolution failure occurred. |
No HRESULT is returned. The library error codes that describe the same situations elsewhere are ERR_DATE_NO_COVERED (date not covered by the holidays collection), ERR_DATE_IS_HOLIDAY, ERR_INVALID_DATELOG_HANDLE and ERR_INVALID_HOLIDAY_HANDLE (see date_error.h); this function folds all of them into FALSE.
The function validates and locks the handles it needs for the duration of the check and unlocks them before returning. Concurrent callers on the same shared context are therefore serialized by the library. If locking fails, the function returns FALSE. Use DuplicateDateLogHandle to give each thread its own handle.
GetDateLogHolidayHandle is a new, independently reference-counted handle that the caller must close with CloseDateLogHandle; it is safe to close it after this call returns.LoadDateLogHandle); an empty or invalid holidays handle cannot cover any date.InitializeDateItem already refuses holiday dates with ERR_DATE_IS_HOLIDAY; this function adds the range check.IsDateCoveredByDateLog compares against a date log’s first date as well as the holidays handle.IsDateItemHoliday reports holidays separately and distinguishes errors (-1) from a negative answer (0).IsDateCoveredByDateLogIsDateItemHolidayIsValidDateLogHandleGetDateLogHolidayHandleInitializeDateItemLoadDateLogHandleFreeDateItemCloseDateLogHandleThe sample builds a holidays handle and a date log for 2025-01-02 through 2025-03-31, obtains the log’s own holidays handle, and tests four dates against both the log and the holidays handle. Every date item and all three 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, 2 }, /* first date of the holidays range */
{ 2025, 2, 18 }, /* inside the range */
{ 2025, 3, 31 }, /* last date of the range */
{ 2025, 4, 1 } /* beyond the range */
};
int exitCode = 1;
HRESULT hr = S_OK;
FILETIME ftFirst = { 0 };
FILETIME ftLast = { 0 };
HOLIDAYS_HANDLE hHolidaysSource = NULL;
DATE_LOG_HANDLE hDateLog = NULL;
HOLIDAYS_HANDLE hHolidays = 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, &hHolidaysSource);
if (FAILED(hr)) {
printf("BuildHolidays failed: 0x%08lX\n", (unsigned long)hr);
goto cleanup;
}
hr = BuildCollection(hHolidaysSource, HandleIsForDatelog, &ftFirst, &ftLast, &hDateLog);
if (FAILED(hr)) {
printf("BuildCollection failed: 0x%08lX\n", (unsigned long)hr);
goto cleanup;
}
/* The caller owns the returned holidays handle and must close it. */
hHolidays = GetDateLogHolidayHandle(hDateLog);
if (hHolidays == NULL) {
printf("The date log has no usable holidays handle.\n");
goto cleanup;
}
for (i = 0; i < sizeof(candidates) / sizeof(candidates[0]); i++) {
FILETIME ft = { 0 };
DATE_ITEM_HANDLE hItem = NULL;
if (!MakeFileTime(candidates[i].wYear, candidates[i].wMonth, candidates[i].wDay, &ft)) {
continue;
}
hr = InitializeDateItem(hDateLog, &ft, NULL, &hItem);
if (FAILED(hr)) {
printf("%04u-%02u-%02u: no date item (0x%08lX)%s\n",
candidates[i].wYear, candidates[i].wMonth, candidates[i].wDay,
(unsigned long)hr, hr == ERR_DATE_IS_HOLIDAY ? " - holiday or weekend" : "");
continue;
}
/* The collection argument may be a date log or a holidays handle. */
printf("%04u-%02u-%02u: via date log = %s, via holidays handle = %s\n",
candidates[i].wYear, candidates[i].wMonth, candidates[i].wDay,
IsDateItemCoveredByHolidaysHandle(hItem, hDateLog) ? "covered" : "not covered",
IsDateItemCoveredByHolidaysHandle(hItem, hHolidays) ? "covered" : "not covered");
FreeDateItem(hItem);
}
exitCode = 0;
cleanup:
if (hHolidays != NULL) {
(void)CloseDateLogHandle(hHolidays);
}
if (hDateLog != NULL) {
(void)CloseDateLogHandle(hDateLog);
}
if (hHolidaysSource != NULL) {
(void)CloseDateLogHandle(hHolidaysSource);
}
return exitCode;
}