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

Age Calculator in SQL: Calculate Age from Date of Birth

Building an age calculator in SQL is mostly a date-arithmetic problem: you have a date of birth (DOB), an “as of” date, and you need to return the person’s completed age. The important detail is that SQL is implemented by different database systems, so the best expression depends on whether you use PostgreSQL, MySQL, SQL Server, or SQLite.

Quick answer: age calculator in SQL

SQL database logo for an age calculator in SQL tutorial
Source: Wikimedia Commons, alaa kaddour; CC BY-SA 4.0.

For a completed age in years, do not simply subtract the birth year from the current year. That can be one year too high before the birthday. Instead, use a database function or expression that accounts for the birthday.

DatabaseCompleted-age approachUseful date function
PostgreSQLEXTRACT(YEAR FROM AGE(CURRENT_DATE, dob))AGE()
MySQLTIMESTAMPDIFF(YEAR, dob, CURDATE())TIMESTAMPDIFF()
SQL ServerDATEDIFF plus a birthday checkDATEDIFF(), DATEADD()
SQLitestrftime() year/month/day comparisonstrftime()

PostgreSQL is especially convenient because its age() function returns a symbolic interval containing years and months rather than only a raw number of days. MySQL provides TIMESTAMPDIFF() for differences in a chosen unit. SQL Server’s DATEDIFF() counts datepart boundaries, so a raw DATEDIFF(year, dob, today) should not be treated as completed age without a birthday adjustment. SQLite has a smaller built-in date/time API, so its year calculation is commonly written as a text comparison.

How SQL should calculate age from DOB

Suppose a table contains date_of_birth. A correct age calculation compares that DOB with a reference date. The basic business rule is:

  • Start with the difference between the reference year and birth year.
  • Check whether the birthday has occurred in the reference year.
  • Subtract one if the birthday has not occurred yet.
  • For years-months-days output, use calendar-aware date functions rather than converting everything to an average number of days.

Using a fixed as-of date is usually better for reports and historical data than always using today. It makes the query reproducible and lets you answer questions such as “What was this customer’s age on 1 January 2026?”

PostgreSQL age calculator

PostgreSQL has a dedicated age() function. The PostgreSQL documentation describes age(timestamp, timestamp) as producing a symbolic result in years and months, and age(timestamp) as comparing a timestamp with the current date. That makes PostgreSQL a natural fit for calendar age calculations.

SELECT
    date_of_birth,
    EXTRACT(YEAR FROM AGE(CURRENT_DATE, date_of_birth))::int AS age
FROM people
WHERE date_of_birth IS NOT NULL;

The result is the number of completed years. For an explicit reference date, replace CURRENT_DATE with a date or parameter:

SELECT
    date_of_birth,
    EXTRACT(
        YEAR FROM AGE(DATE '2026-09-21', date_of_birth)
    )::int AS age_on_date
FROM people
WHERE date_of_birth IS NOT NULL;

PostgreSQL years, months and days

If you need an exact calendar breakdown instead of only completed years, return the interval itself:

SELECT
    date_of_birth,
    AGE(DATE '2026-09-21', date_of_birth) AS age_interval
FROM people
WHERE date_of_birth IS NOT NULL;

You can also extract each component:

SELECT
    EXTRACT(YEAR FROM AGE(DATE '2026-09-21', date_of_birth))::int  AS years,
    EXTRACT(MONTH FROM AGE(DATE '2026-09-21', date_of_birth))::int AS months,
    EXTRACT(DAY FROM AGE(DATE '2026-09-21', date_of_birth))::int   AS days
FROM people
WHERE date_of_birth IS NOT NULL;
SQL query result example for an age calculator in SQL
Source: Wikimedia Commons, Yourkraine; CC0.

MySQL age calculator

MySQL provides CURDATE() for the current date and TIMESTAMPDIFF() for the difference between two temporal values in a selected unit. For completed years, TIMESTAMPDIFF(YEAR, date_of_birth, CURDATE()) is a concise solution.

SELECT
    date_of_birth,
    TIMESTAMPDIFF(YEAR, date_of_birth, CURDATE()) AS age
FROM people
WHERE date_of_birth IS NOT NULL;

For a fixed reference date, pass that date instead of CURDATE():

SELECT
    date_of_birth,
    TIMESTAMPDIFF(
        YEAR,
        date_of_birth,
        '2026-09-21'
    ) AS age_on_date
FROM people
WHERE date_of_birth IS NOT NULL;

For total elapsed days, MySQL’s DATEDIFF() works with the date parts of its arguments:

SELECT
    date_of_birth,
    DATEDIFF(CURDATE(), date_of_birth) AS total_days
FROM people
WHERE date_of_birth IS NOT NULL;

SQL Server age calculator

SQL Server needs a little more care. Microsoft documents DATEDIFF() as counting the specified datepart boundaries crossed between two dates. That means DATEDIFF(year, date_of_birth, GETDATE()) counts New Year boundaries, not birthdays. A birthday adjustment is therefore needed for completed age.

SELECT
    date_of_birth,
    DATEDIFF(year, date_of_birth, CAST(GETDATE() AS date))
      - CASE
          WHEN DATEADD(
                   year,
                   DATEDIFF(year, date_of_birth, CAST(GETDATE() AS date)),
                   date_of_birth
               ) > CAST(GETDATE() AS date)
          THEN 1
          ELSE 0
        END AS age
FROM people
WHERE date_of_birth IS NOT NULL;

The same pattern can use a fixed as-of date. This is useful for an eligibility report or historical snapshot.

DECLARE @as_of date = '2026-09-21';

SELECT
    date_of_birth,
    DATEDIFF(year, date_of_birth, @as_of)
      - CASE
          WHEN DATEADD(
                   year,
                   DATEDIFF(year, date_of_birth, @as_of),
                   date_of_birth
               ) > @as_of
          THEN 1
          ELSE 0
        END AS age_on_date
FROM people
WHERE date_of_birth IS NOT NULL;

Why SQL Server needs the birthday check

Consider a person born on 15 December 2000 and an as-of date of 1 October 2026. A raw year difference is 26 because the calculation crosses the 2025-to-2026 year boundary, but the person has not reached the 15 December birthday yet. The completed age is therefore 25. The DATEADD() comparison catches that case.

SQLite age calculator

SQLite’s date/time functions use text representations and modifiers rather than a dedicated AGE() function. For a DOB stored as ISO-style YYYY-MM-DD, a compact completed-age expression compares the month/day portion of the DOB with today’s month/day.

SELECT
    date_of_birth,
    CAST(strftime('%Y', 'now') AS INTEGER)
      - CAST(strftime('%Y', date_of_birth) AS INTEGER)
      - (
          strftime('%m-%d', 'now') < strftime('%m-%d', date_of_birth)
        ) AS age
FROM people
WHERE date_of_birth IS NOT NULL;

SQLite stores dates in flexible forms, so this expression assumes the DOB values are consistently stored in a format that strftime() can parse, such as YYYY-MM-DD. Validate or normalize imported data before relying on it in production.

SQL age calculator with an as-of date

An as-of date makes age calculations deterministic. It is especially useful when the same query is run later and you need the result to remain tied to a business event, report date, application deadline, or historical snapshot.

Use caseReference dateWhy it matters
Current ageToday’s dateChanges each day
Recruitment eligibilityNotification cutoff dateMatches the official rule
Historical reportReport dateKeeps results reproducible
Birthday calculationTarget dateSupports future or past age

How to calculate exact age in years, months and days

“Age in years” and “elapsed days” are different measurements. A calendar age such as 25 years, 3 months and 6 days cannot be reconstructed reliably by dividing a day count by 365 because leap years and month lengths vary.

OutputRecommended method
Completed yearsCalendar birthday logic or a database’s year-aware function
Years, months, daysPostgreSQL AGE() or equivalent calendar-aware logic
Total daysDate subtraction such as MySQL DATEDIFF()
Historical ageUse an explicit as-of date

If your application needs an exact years-months-days result in MySQL, SQL Server, or SQLite, define the calendar policy explicitly and test boundary dates. Do not silently substitute an average-year calculation for a calendar age.

Leap years and February 29 birthdays

Leap-day birthdays are an important edge case. A person born on 29 February has a valid birthday only in leap years, but their completed age still advances according to the calendar-age policy used by the application. Database functions can handle some of the date arithmetic, but your product or legal requirement may define how a 29 February birthday is treated in a non-leap year.

For eligibility systems, use the rule in the relevant policy or notification rather than inventing a leap-day convention. For ordinary age displays, document the convention used by your application and cover it with tests.

Validate the DOB before calculating age

A good SQL age calculator should not treat every value in the DOB column as trustworthy. At minimum, consider null values, future birth dates, malformed imported dates, and unexpected time components.

-- Example validation idea
SELECT *
FROM people
WHERE date_of_birth IS NULL
   OR date_of_birth > CURRENT_DATE;

The exact syntax for “today” differs by database. More importantly, validation should happen at the data-entry boundary when possible, not only inside reporting queries.

Age calculator SQL examples with a people table

Suppose your table is:

CREATE TABLE people (
    id INTEGER PRIMARY KEY,
    name VARCHAR(100),
    date_of_birth DATE
);

For production systems, choose the date type recommended by your database and schema. A dedicated date value is generally preferable when the business concept is a birthday rather than a timestamp of an event.

RequirementPostgreSQLMySQLSQL Server
Current dateCURRENT_DATECURDATE()CAST(GETDATE() AS date)
Calendar ageAGE()TIMESTAMPDIFF(YEAR,...)Birthday-adjusted DATEDIFF()
Elapsed daysDate subtractionDATEDIFF()DATEDIFF(day,...)

Common SQL age-calculation mistakes

  • Subtracting years only: YEAR(today) - YEAR(dob) ignores whether the birthday has happened.
  • Using SQL Server DATEDIFF(year) as age: it counts year boundaries, not completed birthdays.
  • Dividing days by 365: leap years make this unsuitable for calendar age.
  • Ignoring null and future DOBs: bad input can create misleading reports.
  • Mixing date and timestamp semantics: a birthday is often a date, not a moment in time.
  • Hard-coding today’s date: use a parameterized as-of date when reproducibility matters.
  • Assuming every SQL database has the same functions: SQL syntax is dialect-specific.

How to test an SQL age calculator

Use boundary-focused test data rather than checking only a few ordinary birthdays. A useful test set includes birthdays today, tomorrow, yesterday, the last day of a month, 28 February, 29 February, and dates around New Year’s Day.

TestWhat to verify
Birthday todayAge has already incremented
Birthday tomorrowAge has not incremented
Birthday yesterdayAge has incremented
29 February DOBLeap-year policy is consistent
Future DOBValidation rejects or flags it
Null DOBQuery does not report a misleading age

Which SQL approach should you use?

Use the date functions native to your database instead of forcing one SQL dialect into another. PostgreSQL’s AGE() is useful when you want a calendar-aware interval. MySQL’s TIMESTAMPDIFF() provides a compact completed-year calculation. SQL Server requires particular care because DATEDIFF(year,...) counts datepart boundaries. SQLite can calculate age with strftime() when dates are stored consistently.

If the SQL query feeds an application, keep the reference date explicit when the result must be reproducible. If it feeds an eligibility decision, use the exact cutoff and age rule specified by the governing requirement.

FAQ: age calculator in SQL

How do I calculate age from DOB in SQL?

Use a calendar-aware age expression for your database. PostgreSQL can use EXTRACT(YEAR FROM AGE(CURRENT_DATE, date_of_birth)); MySQL can use TIMESTAMPDIFF(YEAR, date_of_birth, CURDATE()). SQL Server needs a birthday adjustment around DATEDIFF().

Why is YEAR(today) – YEAR(birthdate) sometimes wrong?

Because the calculation ignores the month and day. If the birthday has not occurred yet in the current year, the completed age is one less than the simple year difference.

What is the best SQL function for age?

It depends on the database. PostgreSQL has AGE(), MySQL has TIMESTAMPDIFF(), SQL Server provides DATEDIFF() and DATEADD(), and SQLite uses its date/time functions such as strftime().

Can SQL calculate age on a specific date?

Yes. Replace the current-date expression with a parameter or literal as-of date. This is recommended for historical reports, eligibility cutoffs, and repeatable tests.

Can SQL calculate age in years, months and days?

Yes, but the implementation is database-specific. PostgreSQL’s AGE() directly returns a calendar-aware interval. Other databases require their own date arithmetic and a clearly defined policy for month lengths and leap-day birthdays.

Related age-calculator programming guides

If you are implementing the same DOB logic outside SQL, see our guides for age calculator in Python, age calculator in PHP, age calculator in Java, and age calculator in JavaScript.

Sources and documentation

Bottom line: an SQL age calculator should calculate completed birthdays, not merely subtract calendar years. Choose the expression for your database, use an explicit as-of date when reproducibility matters, validate DOB data, and test birthday and leap-year boundaries.