Age Calculator in OCaml: Calculate Age from Date of Birth
11 min read

Age Calculator in OCaml: Calculate Age from Date of Birth

Building an age calculator in OCaml is a useful way to learn how a functional programming language handles calendar dates, validation, leap years, and date arithmetic. For a reliable result, calculate completed calendar years rather than dividing a day count by 365. OCaml’s CalendarLib.Date provides constructors, today’s date, validation, date subtraction, and a precise years-months-days period representation that fit this problem well.

OCaml programming language logo for age calculator
OCaml programming language logo. Image source: Wikimedia Commons; the Commons page identifies the logo as public domain.

This guide shows how to calculate current age, age on a fixed date, years-months-days, elapsed days and weeks, and how to validate dates such as February 29. It also explains when a date-only calculation is preferable to a timestamp calculation.

Quick Answer: Age Calculator in OCaml

The basic approach is:

  • Represent the date of birth as a CalendarLib.Date.t.
  • Use Date.today () when the target is today.
  • Check that the date is valid before calculating.
  • Subtract the birth date from the target date.
  • For completed age, compare the target month/day with the birthday.
  • For an exact calendar breakdown, use Date.precise_sub and convert the resulting period to years, months and days.

The calendar package is designed for handling dates and times, and its current 3.0.0 documentation exposes these operations through CalendarLib. The package documentation also distinguishes date arithmetic from POSIX timestamp handling, which is important when building a birthday calculator.

Why Use Calendar Dates for Age?

Age is a calendar concept. A person born on 15 March 2000 turns 26 on 15 March 2026. It would be incorrect to define the result simply as the number of elapsed days divided by 365 because leap years make calendar years different lengths.

OCaml Date Libraries for Age Calculation

For a date-only age calculator, CalendarLib.Date is especially convenient. Its API includes make, today, is_valid_date, is_leap_day, add, sub, and precise_sub. The package also provides period constructors for years, months, weeks, and days.

OCaml featurePurpose
Date.makeCreate a date from year, month and day.
Date.today ()Get the current local calendar date.
Date.is_valid_dateCheck whether a year-month-day combination is valid.
Date.subCalculate a date period for elapsed-date calculations.
Date.precise_subRepresent the difference using years, months and days.
Date.Period.ymdExtract years, months and days from a calendar period.

Install the OCaml Calendar Package

With opam, the package can be installed with:

opam install calendar

A Dune project can then depend on the calendar library. Check the package documentation for the current installation and build configuration for your project.

Create a Date of Birth

The Date.make function takes a year, month and day. For example, 15 March 2000 can be represented as follows:

open CalendarLib

let dob = Date.make 2000 3 15

The constructor can raise an exception when a date is outside the supported calendar range or falls into a period that the library marks as undefined. For user-entered input, validation should happen before construction when you need controlled error handling.

Validate a Date of Birth

A robust calculator should reject impossible dates such as 30 February. The CalendarLib API provides Date.is_valid_date specifically for checking a year-month-day combination.

let valid_dob year month day =
  Date.is_valid_date year month day

For example, 2008-02-29 is valid, while 2007-02-29 is not. This validation is preferable to silently allowing malformed input into later age calculations.

Calculate Current Age in Completed Years

The simplest birthday-aware algorithm is to subtract the birth year from the target year and then reduce the result by one when the birthday has not occurred yet in the target year.

let completed_age dob target =
  let birth_year = Date.year dob in
  let birth_month = Date.month dob in
  let birth_day = Date.day_of_month dob in
  let target_year = Date.year target in
  let target_month = Date.month target in
  let target_day = Date.day_of_month target in
  let years = target_year - birth_year in
  if (target_month, target_day) < (birth_month, birth_day)
  then years - 1
  else years

This returns the person’s completed calendar years. For today’s age, pass Date.today () as the target.

Use Today’s Date Automatically

let age_today dob =
  completed_age dob (Date.today ())

Date.today () represents the current day using the library’s current time-zone rules. For an age normally stated in whole years, a date-only value avoids unnecessary complications from the exact time of day.

Calculate Age on a Specific Date

An age calculator is often more useful when it accepts a reference date. This lets you answer questions such as “How old was this person on 1 January 2025?” without changing the core algorithm.

let dob = Date.make 1995 7 20
let target = Date.make 2025 1 1

let age = completed_age dob target

For a target before the date of birth, your application should reject the input rather than return a negative age. Date comparison can be used for this check.

Calculate Years, Months and Days

Sometimes “32 years old” is not detailed enough. You may need a result such as 32 years, 4 months and 7 days. CalendarLib’s Date.precise_sub is designed for this type of calendar difference, and the resulting period can be converted with Date.Period.ymd.

let age_ymd dob target =
  let period = Date.precise_sub target dob in
  Date.Period.ymd period

The returned triple represents years, months and days. This is different from treating all dates as a fixed number of seconds or days, because months and years do not have constant lengths.

Calculate Total Elapsed Days

If your application needs the total number of days rather than calendar age, use date subtraction. A day-based period can be converted to a number of days with the period API.

let elapsed_days dob target =
  let period = Date.sub target dob in
  Date.Period.safe_nb_days period

This value answers a different question from completed age. For example, two people can have the same completed age while having different totals of elapsed days depending on their exact birth dates.

Calculate Completed Weeks

Once you have a day count, completed weeks can be calculated using integer division.

let completed_weeks dob target =
  let days = elapsed_days dob target in
  days / 7

Leap Years and February 29

Leap-year handling matters because 29 February exists only in leap years. CalendarLib also exposes leap-day and calendar-aware operations, so you should not hard-code February as always having 28 days.

Birth dateTarget dateAge logic
2000-02-292024-02-28Birthday has not reached February 29 in the usual date comparison, so completed age remains one year below the simple year difference.
2000-02-292024-02-29The birthday date is reached; the full calendar year is completed.
2000-02-292025-03-01The target is after the February birthday boundary, so the completed-year count has advanced.

Applications that need a specific legal or business rule for 28 February versus 1 March in non-leap years should define that rule explicitly rather than assuming that every context treats a February 29 birthday identically.

Years, Months and Days vs Total Days

ResultMeaningTypical use
Completed yearsWhole birthdays reached.Age shown on forms and profiles.
Years, months, daysCalendar period between two dates.Detailed age displays.
Total daysElapsed calendar days.Durations and analytics.
Total weeksCompleted groups of seven days.Milestones and duration reports.

Build a Reusable OCaml Age Calculator

open CalendarLib

type age = {
  years : int;
  months : int;
  days : int;
  total_days : int;
}

let calculate dob target =
  if target < dob then
    invalid_arg "target date is before date of birth";

  let years = completed_age dob target in
  let period = Date.precise_sub target dob in
  let y, m, d = Date.Period.ymd period in
  let total_days =
    Date.Period.safe_nb_days (Date.sub target dob)
  in
  { years; months = m; days = d; total_days }

In production code, you can choose whether the returned record should expose both the birthday-aware completed years and the calendar period breakdown. Keeping these concepts separate makes the API easier to understand and test.

Parse Dates from User Input

User input commonly arrives as text such as 2000-03-15. Your parsing layer should convert the text into a validated Date.t and return a clear error when the input does not follow the expected format. Do not let malformed dates reach the calculation layer.

Date vs DateTime in OCaml

For ordinary birthday calculations, Date is usually the simpler abstraction because age is normally expressed from calendar dates. If the application needs birth time, exact elapsed hours, or time-zone-sensitive timestamps, a date-time or POSIX-time library may be more appropriate.

OCaml’s Ptime package provides platform-independent POSIX time and RFC 3339 conversions, while the separate clock support exposes the system clock and current time-zone offset. Ptime itself is not a calendar library, so it should not be confused with the calendar operations used for a birthday calculation.

Time Zones and Birth Time

If you calculate age from only a date of birth, the time zone generally does not change the completed-year result. If you include a birth time, however, the definition of “now” becomes important. A timestamp near midnight can represent different local dates in different time zones.

Common OCaml Age Calculator Mistakes

  • Dividing elapsed days by 365 and calling the result age.
  • Ignoring whether the birthday has already occurred in the target year.
  • Accepting invalid dates such as February 30.
  • Forgetting leap-year and February 29 cases.
  • Mixing date-only age with timestamp duration without defining the intended semantics.
  • Returning negative ages when the target date precedes the date of birth.
  • Using an approximate month length when an exact calendar period is required.

Testing an OCaml Age Calculator

Age calculations benefit from boundary-focused tests. At minimum, test the day before a birthday, the birthday itself, the day after the birthday, dates around month boundaries, leap days, and targets before the date of birth.

Test caseWhat it checks
Birthday todayCompleted age increments on the correct date.
One day before birthdayPrevents premature birthday increments.
Leap-day birthChecks February 29 handling.
Invalid dateChecks input validation.
Target before DOBPrevents negative-age results.
Month-end datesChecks calendar-month arithmetic.

OCaml Age Calculator Example

open CalendarLib

let () =
  let dob = Date.make 1990 11 24 in
  let today = Date.today () in
  let years = completed_age dob today in
  let y, m, d = age_ymd dob today in

  Printf.printf
    "Completed age: %d years\nCalendar age: %d years, %d months, %d days\n"
    years y m d

The example separates the two common outputs: a simple completed-year age and a detailed calendar period. This makes the program useful for both ordinary age displays and more detailed reports.

OCaml development team receiving an award at POPL 2024
OCaml development team receiving an award at POPL 2024. Photo by David.Monniaux, Wikimedia Commons, CC BY-SA 4.0.

How OCaml Compares with Other Age Calculator Implementations

The same calendar problem can be implemented in many languages, but each ecosystem exposes different date abstractions. See the related tutorials for Haskell, Elixir, Erlang, Julia, Rust, Go, Java, and Perl.

LanguageTypical date approachAge-calculation focus
OCamlCalendarLib.DateCalendar periods and functional date operations.
HaskellData.TimePure date and duration operations.
ElixirDateCalendar dates and date differences.
RustChrono or time ecosystemTyped date arithmetic.
Gotime packageTime values and birthday-aware logic.

Frequently Asked Questions

Can OCaml calculate age without an external library?

It is possible to write calendar logic yourself, but a date library avoids reinventing month lengths, leap-year rules, calendar arithmetic, and validation. CalendarLib provides these operations in a reusable API.

What is the best OCaml type for a date of birth?

For a date-only birthday, CalendarLib.Date.t is a natural choice. If you need an exact timestamp and time-zone-aware operations, use a suitable date-time or POSIX-time abstraction instead.

How do I calculate age on a future date?

Create the future target date with Date.make and pass it to the same birthday-aware function used for today’s age.

How do I calculate age in years, months and days?

Use Date.precise_sub target dob and then Date.Period.ymd. This gives a calendar period rather than an approximation based on a fixed number of days per month.

Does OCaml handle leap years?

CalendarLib provides leap-day and calendar-aware functionality, so leap-year cases can be handled through the date library rather than hard-coded assumptions.

Official OCaml References

Image Credits

The OCaml logo is from Wikimedia Commons and is released to the public domain according to its Commons file page. The POPL 2024 photograph is by David.Monniaux and is licensed under CC BY-SA 4.0. Attribution and license information are included in the image captions.

Final Takeaway

An age calculator in OCaml is a compact example of reliable calendar programming. Use CalendarLib.Date for date representation, validate input before calculation, count completed birthdays for ordinary age, and use precise calendar periods when you need years, months and days. For applications involving exact birth times or time zones, choose a date-time abstraction that matches those requirements instead of treating timestamps and calendar age as the same problem.