If you need an age calculator in Dart, the safest approach is to treat age as a calendar calculation rather than simply dividing a duration by 365. Dart’s DateTime class gives you the year, month and day components you need to determine whether the birthday has occurred in the reference year. This approach also lets you calculate age on a fixed date, return years-months-days, validate future dates of birth, and calculate elapsed days when that is the actual requirement.
Quick answer: for completed age, calculate asOf.year - dob.year, then subtract one when the birthday has not occurred yet in the reference year. For calendar-date input, prefer an explicit date representation such as a UTC DateTime at midnight so daylight-saving clock changes do not affect whole-day calculations.
Table of Contents

Age Calculator in Dart: What You Should Calculate
An age calculator can mean several different things. Before writing the Dart function, decide whether the output is:
- Completed age: whole birthdays already reached.
- Age on a fixed date: completed age on a supplied as-of date rather than today.
- Calendar age: years, months and days since the date of birth.
- Elapsed days: the number of whole calendar-day intervals between two dates.
These definitions are not interchangeable. Dart’s DateTime.difference() returns a Duration measured from the underlying time values, so it is useful for elapsed time but should not be used as the sole definition of completed birthday age. The Dart API also warns that local-time differences across daylight-saving changes can make a pair of local midnights less than 24 hours apart. Dart DateTime documentation
Dart DateTime Basics for Age Calculations
Dart’s DateTime represents an instant in either UTC or the local time zone. Its year, month and day properties expose the calendar components needed for birthday logic. The DateTime.utc() constructor is particularly useful when you want date values that are not affected by daylight-saving transitions. Dart DateTime API
final dob = DateTime.utc(1995, 7, 14);
final asOf = DateTime.utc(2026, 9, 22);
print(dob.year); // 1995
print(dob.month); // 7
print(dob.day); // 14Calculate Completed Age in Dart
The standard birthday-aware rule is simple: start with the difference between the reference year and birth year. If the reference month/day comes before the birthday in that year, subtract one.
int calculateAge(DateTime dob, DateTime asOf) {
if (dob.isAfter(asOf)) {
throw ArgumentError('Date of birth cannot be in the future.');
}
int age = asOf.year - dob.year;
final birthdayThisYear = DateTime.utc(
asOf.year,
dob.month,
dob.day,
);
if (birthdayThisYear.isAfter(asOf)) {
age--;
}
return age;
}This works because a person whose birthday has not arrived yet in the reference year has completed one fewer year. The function also accepts an explicit asOf date, which makes it deterministic for tests and historical calculations.
| Date of birth | As-of date | Completed age |
|---|---|---|
| 14 July 1995 | 22 September 2026 | 31 |
| 14 October 1995 | 22 September 2026 | 30 |
| 22 September 1995 | 22 September 2026 | 31 |
Why Subtracting Years Alone Can Be Wrong
A formula such as asOf.year - dob.year ignores whether the birthday has happened. For example, someone born on 14 October 1995 is still 30 on 22 September 2026, not 31. The month-and-day comparison is therefore essential.
Likewise, dividing the result of difference() by 365 or 365.25 is not a reliable definition of completed age. Leap years change the number of elapsed days, and a birthday is a calendar event rather than a fixed number of seconds.
Calculate Age on a Fixed Date
A production age calculator should normally accept an explicit reference date. That makes the same function useful for eligibility cutoffs, historical records, reports and unit tests.
final dob = DateTime.utc(2000, 2, 29);
final cutoff = DateTime.utc(2026, 2, 28);
final age = calculateAge(dob, cutoff);
print(age);Whether a person born on February 29 has a birthday on February 28 or March 1 in a non-leap year is a policy question. Your application should document the rule instead of silently assuming one. A jurisdiction, contract or eligibility notice may define its own cutoff convention.
Calculate Years, Months and Days in Dart
Dart’s core DateTime API does not provide a direct Period-style calendar interval with normalized years, months and days. You can build the result by first calculating completed years, then advancing the birth date by that many years and breaking the remaining interval into months and days.
class AgeResult {
final int years;
final int months;
final int days;
const AgeResult(this.years, this.months, this.days);
}
AgeResult calculateYmdAge(DateTime dob, DateTime asOf) {
if (dob.isAfter(asOf)) {
throw ArgumentError('Date of birth cannot be in the future.');
}
var years = asOf.year - dob.year;
var anniversary = DateTime.utc(
dob.year + years,
dob.month,
dob.day,
);
if (anniversary.isAfter(asOf)) {
years--;
anniversary = DateTime.utc(
dob.year + years,
dob.month,
dob.day,
);
}
var months = 0;
var cursor = anniversary;
while (true) {
final next = DateTime.utc(cursor.year, cursor.month + 1, cursor.day);
if (next.isAfter(asOf)) {
break;
}
cursor = next;
months++;
}
final days = asOf.difference(cursor).inDays;
return AgeResult(years, months, days);
}Month-end dates need extra care because Dart normalizes out-of-range date components. For a robust application, test dates such as January 31, February 28/29 and months with 30 days. If your requirements are internationalized or depend heavily on calendar conventions, consider whether the Dart intl package or a dedicated date library is more appropriate than hand-written month arithmetic.
Calculate Total Elapsed Days
When the requirement really is elapsed days, use difference(). For date-only calculations, using UTC midnight values avoids daylight-saving transitions changing the duration between two local midnights.
int elapsedDays(DateTime start, DateTime end) {
if (end.isBefore(start)) {
throw ArgumentError('End date must not be before start date.');
}
return end.difference(start).inDays;
}
final start = DateTime.utc(2000, 1, 1);
final end = DateTime.utc(2026, 9, 22);
print(elapsedDays(start, end));Dart’s documentation specifically notes that Duration.inDays reports whole days and that local-time calculations can be affected by daylight-saving changes. For date-only age calculations, UTC values are therefore a useful defensive choice. Dart difference() documentation
Parse a Date of Birth Safely
DateTime.parse() accepts a subset of ISO 8601 and throws a FormatException for strings it cannot parse. Importantly, the parser can normalize some out-of-range component values rather than rejecting every invalid calendar date. For strict user input, validate the original components or use an appropriate strict date parser instead of assuming that successful parsing means the user entered a valid calendar date. Dart DateTime.parse documentation
DateTime? parseDob(String input) {
try {
final parsed = DateTime.parse(input);
return DateTime.utc(parsed.year, parsed.month, parsed.day);
} on FormatException {
return null;
}
}For a browser or Flutter form, it is also a good idea to reject blank values, future dates and values outside the date range your application supports before calculating age.
Complete Dart Age Calculator Example
int calculateAge(DateTime dob, DateTime asOf) {
if (dob.isAfter(asOf)) {
throw ArgumentError('Date of birth cannot be in the future.');
}
var age = asOf.year - dob.year;
final birthday = DateTime.utc(
asOf.year,
dob.month,
dob.day,
);
if (birthday.isAfter(asOf)) {
age--;
}
return age;
}
void main() {
final dob = DateTime.utc(1990, 11, 5);
final today = DateTime.utc(2026, 9, 22);
final age = calculateAge(dob, today);
print('Age: $age years');
}The important part is not the print() statement; it is the separation between date parsing, validation, the as-of date and the age rule. Keeping those responsibilities separate makes the calculator easier to test and reuse in command-line, server-side or Flutter applications.
Leap Years and February 29
Leap-day birthdays deserve an explicit test. If the birth date is February 29, the birthday comparison for a non-leap reference year needs a documented business rule. Do not assume that every application should treat February 28 and March 1 identically.
| Test case | What to verify |
|---|---|
| 29 Feb in a leap year | Birthday is a real calendar date. |
| 29 Feb to a non-leap year | Application’s birthday policy is explicit. |
| Birthday today | Age increases on the birthday. |
| Birthday tomorrow | Age remains one year lower. |
Time Zones: DateTime.now() vs UTC
DateTime.now() returns the current date and time in the computer’s local time zone. That may be exactly what a local application needs, but a server that serves users in several time zones should define which calendar date is authoritative. For date-only records such as birthdays, converting user input into a consistent date representation can prevent an age from changing unexpectedly around midnight.
Dart’s DateTime.utc() constructor creates UTC values, and the official API recommends UTC for historic or date-oriented calculations where daylight-saving changes should not affect the result. Dart UTC DateTime documentation
Testing a Dart Age Calculator
Use fixed dates in tests instead of relying on DateTime.now(). That makes the expected answer stable and lets you cover boundary cases.
| Scenario | Expected behavior |
|---|---|
| DOB before birthday | Subtract one from the raw year difference. |
| DOB on birthday | Use the raw year difference. |
| Future DOB | Reject the input. |
| 29 February DOB | Apply the documented non-leap-year policy. |
| Month-end DOB | Verify years-months-days normalization. |
| Different time zones | Confirm the application’s authoritative calendar date. |
void main() {
final asOf = DateTime.utc(2026, 9, 22);
assert(
calculateAge(DateTime.utc(1995, 9, 22), asOf) == 31,
);
assert(
calculateAge(DateTime.utc(1995, 10, 14), asOf) == 30,
);
}Common Mistakes in a Dart Age Calculator
- Using only
asOf.year - dob.yearand ignoring the birthday. - Dividing elapsed days by 365 and calling the result a completed age.
- Using local midnight durations without considering daylight-saving changes.
- Accepting a future date of birth.
- Assuming
DateTime.parse()rejects every out-of-range calendar component. - Leaving the February 29 rule undocumented.
- Using
DateTime.now()directly in tests, which makes results change over time.
Dart DateTime vs Other Age-Calculator Implementations
| Implementation | Core date approach | Useful when |
|---|---|---|
| Dart | DateTime | Flutter, Dart CLI and Dart server applications. |
| JavaScript | Date / calendar logic | Browser-based calculators. |
| TypeScript | Typed Date | Typed JavaScript applications. |
| Java | LocalDate and Period | JVM applications needing richer calendar types. |
| Swift | Foundation Calendar | Apple-platform applications. |
If you are comparing implementation patterns, see our related guides on JavaScript, TypeScript, Java and Swift.
Frequently Asked Questions
How do I calculate age from DOB in Dart?
Subtract the birth year from the as-of year, then subtract one if the birthday in the as-of year has not occurred yet. Compare the month and day rather than relying only on elapsed seconds.
Can I use DateTime.difference() for age?
Use difference() for elapsed durations and elapsed days. It is not, by itself, a birthday-aware completed-age calculation because age is based on calendar birthdays.
Does Dart DateTime support UTC?
Yes. Dart provides DateTime.utc(), an isUtc property, and toUtc()/toLocal() conversions.
How should a Dart app handle February 29 birthdays?
Choose and document the business rule for non-leap years. The correct policy depends on the purpose of the calculator and any applicable rules.
Key Takeaway
A reliable age calculator in Dart separates calendar age from elapsed duration. Use DateTime year/month/day components for completed age, accept an explicit as-of date for reproducible results, use UTC values when date-only calculations should be insulated from daylight-saving changes, and test birthday boundaries, leap years, future DOBs and month-end dates. Dart’s official API documentation supports these distinctions and provides the underlying DateTime, Duration, parsing and comparison tools. Dart DateTime API
