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.

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_suband 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 feature | Purpose |
|---|---|
Date.make | Create a date from year, month and day. |
Date.today () | Get the current local calendar date. |
Date.is_valid_date | Check whether a year-month-day combination is valid. |
Date.sub | Calculate a date period for elapsed-date calculations. |
Date.precise_sub | Represent the difference using years, months and days. |
Date.Period.ymd | Extract years, months and days from a calendar period. |
Install the OCaml Calendar Package
With opam, the package can be installed with:
opam install calendarA 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 15The 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 dayFor 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 yearsThis 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 targetFor 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 periodThe 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 periodThis 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 / 7Leap 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 date | Target date | Age logic |
|---|---|---|
| 2000-02-29 | 2024-02-28 | Birthday has not reached February 29 in the usual date comparison, so completed age remains one year below the simple year difference. |
| 2000-02-29 | 2024-02-29 | The birthday date is reached; the full calendar year is completed. |
| 2000-02-29 | 2025-03-01 | The 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
| Result | Meaning | Typical use |
|---|---|---|
| Completed years | Whole birthdays reached. | Age shown on forms and profiles. |
| Years, months, days | Calendar period between two dates. | Detailed age displays. |
| Total days | Elapsed calendar days. | Durations and analytics. |
| Total weeks | Completed 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 case | What it checks |
|---|---|
| Birthday today | Completed age increments on the correct date. |
| One day before birthday | Prevents premature birthday increments. |
| Leap-day birth | Checks February 29 handling. |
| Invalid date | Checks input validation. |
| Target before DOB | Prevents negative-age results. |
| Month-end dates | Checks 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 dThe 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.

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.
| Language | Typical date approach | Age-calculation focus |
|---|---|---|
| OCaml | CalendarLib.Date | Calendar periods and functional date operations. |
| Haskell | Data.Time | Pure date and duration operations. |
| Elixir | Date | Calendar dates and date differences. |
| Rust | Chrono or time ecosystem | Typed date arithmetic. |
| Go | time package | Time 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
- OCaml Calendar package — date and time library documentation.
- CalendarLib.Date API — date constructors, validation and arithmetic.
- CalendarLib Date.Period API — years, months, weeks, days and period conversion.
- Ptime — POSIX time and RFC 3339 support.
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.