Skip to main content

Vali-Age

IValiAge computes accurate ages from birthdates. It handles the Feb 29 leap-year convention (people born on Feb 29 celebrate on Feb 28 in non-leap years) and provides birthday detection, next/previous birthday calculation, and relative age descriptions.

Installation

dotnet add package Vali-Age

Registration

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

AgeResult Struct

AgeResult is a value type returned by Exact() that breaks down the age into components:

PropertyTypeDescription
YearsintComplete years elapsed
MonthsintRemaining months (0–11)
DaysintRemaining days (0–30)
TotalDaysintTotal days since birthdate
BirthdateDateTimeOriginal birthdate
AgeResult age = valiAge.Exact(new DateTime(1990, 5, 10));
Console.WriteLine($"{age.Years}y {age.Months}m {age.Days}d");
// → "35y 2m 7d" (depending on today)

IValiAge API

Years

Return the number of complete years since the birthdate:

int years = age.Years(new DateTime(1990, 5, 10));
// → e.g. 35

Signature: int Years(DateTime birthdate, DateTime? referenceDate = null)

Exact

Return a detailed AgeResult with years, months, and days breakdown:

AgeResult result = age.Exact(new DateTime(1990, 5, 10));
// result.Years → 35
// result.Months → 2
// result.Days → 7

Signature: AgeResult Exact(DateTime birthdate, DateTime? referenceDate = null)

Format

Format the age as a human-readable string:

string s1 = age.Format(new DateTime(1990, 5, 10));
// → "35 years old"

string s2 = age.Format(new DateTime(1990, 5, 10), detailed: true);
// → "35 years, 2 months, and 7 days"

Signature: string Format(DateTime birthdate, bool detailed = false, DateTime? referenceDate = null)

Relative

Return a relative age description:

string rel = age.Relative(new DateTime(2020, 1, 15));
// → "5 years ago" or "3 months ago" (for a recent date)

string relBaby = age.Relative(DateTime.Today.AddDays(-40));
// → "40 days ago" or "about 1 month ago"

Signature: string Relative(DateTime birthdate, DateTime? referenceDate = null)

IsAtLeast

Return true if the person is at least the given age in years:

bool adult = age.IsAtLeast(new DateTime(2000, 1, 1), 18);
// → true if born in 2000 and today is 2018 or later

Signature: bool IsAtLeast(DateTime birthdate, int years, DateTime? referenceDate = null)

IsBirthday

Return true if today (or the reference date) is the person's birthday:

bool today = age.IsBirthday(new DateTime(1990, 3, 23));
// → true if today is March 23

// Feb 29 convention: celebrated on Feb 28 in non-leap years
bool leapBday = age.IsBirthday(new DateTime(2000, 2, 29));
// → true on Feb 28 in non-leap years, Feb 29 in leap years

Signature: bool IsBirthday(DateTime birthdate, DateTime? referenceDate = null)

NextBirthday

Return the date of the next upcoming birthday:

DateTime next = age.NextBirthday(new DateTime(1990, 5, 10));
// → 2026-05-10 (if today is before May 10, 2026)

// If today is exactly the birthday, returns next year's date

Signature: DateTime NextBirthday(DateTime birthdate, DateTime? referenceDate = null)

PreviousBirthday

Return the date of the most recent past birthday:

DateTime prev = age.PreviousBirthday(new DateTime(1990, 5, 10));
// → 2025-05-10 (last birthday that has already passed)

Signature: DateTime PreviousBirthday(DateTime birthdate, DateTime? referenceDate = null)

Throws ArgumentOutOfRangeException when reference is before the person's first birthday.

DaysUntilBirthday

Return the number of days until the next birthday:

int days = age.DaysUntilBirthday(new DateTime(1990, 5, 10));
// → e.g. 48 (if today is March 23 and birthday is May 10)

// Returns 0 if today is the birthday
// Returns 365 (or 366) if today is the day after the birthday

Signature: int DaysUntilBirthday(DateTime birthdate, DateTime? referenceDate = null)

Feb 29 Convention

People born on February 29 are handled consistently:

  • In leap years: birthday is February 29
  • In non-leap years: birthday is treated as February 28

This convention applies to IsBirthday, NextBirthday, PreviousBirthday, and DaysUntilBirthday.

var leapBirthday = new DateTime(2000, 2, 29);

// In 2025 (non-leap):
bool isToday = age.IsBirthday(leapBirthday, new DateTime(2025, 2, 28));
// → true

// In 2024 (leap):
bool isLeapDay = age.IsBirthday(leapBirthday, new DateTime(2024, 2, 29));
// → true

Complete Example

public class UserProfileService(IValiAge age)
{
public void DisplayProfile(string name, DateTime birthdate)
{
int years = age.Years(birthdate);
AgeResult exact = age.Exact(birthdate);
bool isAdult = age.IsAtLeast(birthdate, 18);
bool birthday = age.IsBirthday(birthdate);
int daysLeft = age.DaysUntilBirthday(birthdate);

Console.WriteLine($"Name: {name}");
Console.WriteLine($"Age: {years} years");
Console.WriteLine($"Exact: {exact.Years}y {exact.Months}m {exact.Days}d");
Console.WriteLine($"Adult: {isAdult}");

if (birthday)
Console.WriteLine(" Happy Birthday!");
else
Console.WriteLine($" Next birthday in {daysLeft} days ({age.NextBirthday(birthdate):MMM dd})");

Console.WriteLine($"Relative: {age.Relative(birthdate)}");
Console.WriteLine($"Detail: {age.Format(birthdate, detailed: true)}");
}
}