Skip to main content

Vali-Calendar

IValiCalendar is a workday-aware calendar engine that supports pluggable holiday providers. It can calculate workdays between dates, add business days, detect month/week boundaries, and enumerate days of a month.

Installation

dotnet add package Vali-Calendar

Registration

builder.Services.AddValiCalendar();
// or via the meta-package:
builder.Services.AddValiTempo();

CalendarWeek Struct

CalendarWeek represents a single ISO 8601 calendar week:

PropertyTypeDescription
YearintYear the week belongs to
WeekNumberintISO week number (1–53)
StartDateTimeMonday of the week
EndDateTimeSunday of the week
DaysIEnumerable<DateTime>All 7 days of the week

IValiCalendar API

WeekOf

Get the CalendarWeek that contains a given date:

CalendarWeek week = calendar.WeekOf(new DateTime(2025, 3, 15));
Console.WriteLine(week.WeekNumber); // → ISO week number
Console.WriteLine(week.Start); // → Monday of that week
Console.WriteLine(week.End); // → Sunday of that week

Signature: CalendarWeek WeekOf(DateTime date)

CurrentWeek

Get the CalendarWeek for the current date:

CalendarWeek thisWeek = calendar.CurrentWeek();

Signature: CalendarWeek CurrentWeek()

WeeksInMonth

Get all calendar weeks that overlap with the month of the given date:

IEnumerable<CalendarWeek> weeks = calendar.WeeksInMonth(new DateTime(2025, 3, 1));
// → All weeks overlapping March 2025

Signature: IEnumerable<CalendarWeek> WeeksInMonth(DateTime date)

WeekCountInMonth

Return the number of (partial or full) calendar weeks in the month of the given date:

int count = calendar.WeekCountInMonth(new DateTime(2025, 3, 1));
// → 5 (March 2025 spans 5 weeks)

Signature: int WeekCountInMonth(DateTime date)

IsFirstDayOfMonth

Return true if the date is the first day of its calendar month:

bool first = calendar.IsFirstDayOfMonth(new DateTime(2025, 5, 1));
// → true

Signature: bool IsFirstDayOfMonth(DateTime date)

IsLastDayOfMonth

Return true if the date is the last day of its calendar month:

bool last = calendar.IsLastDayOfMonth(new DateTime(2025, 1, 31));
// → true

Signature: bool IsLastDayOfMonth(DateTime date)

DaysInMonth

Return the number of days in the month of the given date:

int days = calendar.DaysInMonth(new DateTime(2024, 2, 10));
// → 29 (leap year)

Signature: int DaysInMonth(DateTime date)

DaysOfMonth

Enumerate all calendar days in the month of the given date:

IEnumerable<DateTime> days = calendar.DaysOfMonth(new DateTime(2025, 3, 1));
foreach (var day in days)
Console.WriteLine(day.ToString("dd ddd"));

Signature: IEnumerable<DateTime> DaysOfMonth(DateTime date)

IsWorkday

Return true if the date is a workday (Monday–Friday and not a registered holiday):

bool isWork = calendar.IsWorkday(new DateTime(2025, 12, 25));
// → depends on registered holidays

Optionally pass a country code to check against that country's holidays:

bool isWork = calendar.IsWorkday(new DateTime(2025, 12, 25), "PE");

Signature: bool IsWorkday(DateTime date, string? country = null)

WorkdaysBetween

Count the number of workdays between two dates (exclusive of the end date):

int workdays = calendar.WorkdaysBetween(
new DateTime(2025, 3, 3), // Monday
new DateTime(2025, 3, 14), // Friday
"US");
// → 10 (two weeks of Mon–Fri)

Signature: int WorkdaysBetween(DateTime from, DateTime to, string? country = null)

AddWorkdays

Add a number of business days to a date, skipping weekends and holidays:

DateTime result = calendar.AddWorkdays(new DateTime(2025, 3, 28), 5, "PE");
// → Moves 5 workdays forward, skipping weekends and Peruvian holidays

Signature: DateTime AddWorkdays(DateTime date, int count, string? country = null)

WorkdaysInMonth

Return the count of workdays in the month of the given date:

int count = calendar.WorkdaysInMonth(new DateTime(2025, 3, 1), "US");
// → ~21 (March 2025 has 21 workdays in the US)

Signature: int WorkdaysInMonth(DateTime date, string? country = null)

WorkdaysInYear

Return the count of workdays in the year of the given date:

int count = calendar.WorkdaysInYear(new DateTime(2025, 1, 1), "US");
// → ~261

Signature: int WorkdaysInYear(DateTime date, string? country = null)

NextWorkday

Return the next workday after the given date:

DateTime next = calendar.NextWorkday(new DateTime(2025, 3, 28)); // Friday
// → 2025-03-31 (Monday)

Signature: DateTime NextWorkday(DateTime date, string? country = null)

PreviousWorkday

Return the workday immediately before the given date:

DateTime prev = calendar.PreviousWorkday(new DateTime(2025, 3, 31)); // Monday
// → 2025-03-28 (Friday)

Signature: DateTime PreviousWorkday(DateTime date, string? country = null)

HasHolidayProvider

Return true if a holiday provider is registered for the given country code:

bool has = calendar.HasHolidayProvider("PE");

Signature: bool HasHolidayProvider(string country)

HolidaysInMonth

Return all registered holidays in the month of the given date for a country:

IEnumerable<HolidayInfo> holidays = calendar.HolidaysInMonth(new DateTime(2025, 12, 1), "PE");

Signature: IEnumerable<HolidayInfo> HolidaysInMonth(DateTime date, string country)

HolidaysInYear

Return all registered holidays in the year of the given date for a country:

IEnumerable<HolidayInfo> holidays = calendar.HolidaysInYear(new DateTime(2025, 1, 1), "US");

Signature: IEnumerable<HolidayInfo> HolidaysInYear(DateTime date, string country)

IsLeapYear

Return true if the year of the given date is a leap year:

bool leap = calendar.IsLeapYear(new DateTime(2024, 1, 1));
// → true

Signature: bool IsLeapYear(DateTime date)

DaysInYear

Return the number of days in the year of the given date (365 or 366):

int days = calendar.DaysInYear(new DateTime(2024, 6, 1));
// → 366

Signature: int DaysInYear(DateTime date)

Complete Example

public class HRCalendar(IValiCalendar calendar, IValiHoliday holiday)
{
public void Setup()
{
// Register holiday providers
foreach (var p in HolidayProviderFactory.CreateLatinAmerica())
holiday.Register(p);
}

public void PrintMonthSummary(DateTime date, string country)
{
Console.WriteLine($"Days in month: {calendar.DaysInMonth(date)}");
Console.WriteLine($"Workdays in month: {calendar.WorkdaysInMonth(date, country)}");
Console.WriteLine($"Weeks in month: {calendar.WeekCountInMonth(date)}");

Console.WriteLine("Holidays this month:");
foreach (var h in calendar.HolidaysInMonth(date, country))
Console.WriteLine($" {h.Date:MMM dd}{h.Name}");
}

public DateTime ComputePaymentDate(DateTime issueDate, string country)
{
// Payment due 5 business days after invoice date
return calendar.AddWorkdays(issueDate, 5, country);
}
}