Skip to main content

Birthday maths

· 9 min read
Filip Tammergård
Software Engineer at Frilans Finans

Have you ever wondered how old you are…in milliseconds? Or exactly how many weeks there are between two dates? Don't worry, in this post you can get the answer to all your "How many [unit] is it between [date] and [date]?" questions!

For example your birthday

For example today's date
Years

31.790120436136

Months

381.496579328704

Weeks

1658.770565599

Days

11611.393959190

Hours

278673.455021

Minutes

16720407.301233

Seconds

1003224438.074

Milliseconds

1003224438074

Date calculations

Pick a start date and an end date above and get answers to everything you have ever wondered about! Before you change anything, the start date is my birthday and the end date is today's date. As you can see, the values keep updating, and they will as long as the end date is today's date. If you pick a different end date, the updates will stop.

How do the calculations work?

There are many services on the internet that can help you compute how many days it is between two dates. However, the services I have come across count days in whole integers — which doesn't reflect that the current day is continuously approaching the next one. We need decimals! I also haven't found a service that shows how many years, months or weeks it is between two dates with many decimals of precision. Of course it has to exist!

When you pick the start date, you can also enter the time of day by ticking "Include time". That way, you can specify your birthday with a precise time of day to find out exactly how many minutes you are. The calculations for seconds and milliseconds were fun to include, but obviously aren't very relevant since milliseconds and seconds can't be picked in the start or end date. When "Include time" is unticked, the time defaults to 00:00:00:00, and when it's ticked, the seconds value defaults to 00. If you click "Today", the exact current millisecond is picked. When the end date is set to "Today", the values keep counting up to the current millisecond so you can watch yourself age in real time.

In JavaScript, the built-in Date object holds a lot of useful information and is therefore a great fit for this kind of calculation. With new Date() a new Date object is created with information about the current millisecond, which can be extracted with a number of functions belonging to the Date object. Here are a few examples for the date 2020-10-12.

Some of the functions on the JavaScript Date object
const now = new Date()

const currentYear = now.getFullYear()
// currentYear = 2020

const currentMonth = now.getMonth()
// currentMonth = 9

const currentDate = now.getDate()
// currentDate = 12

const currentTime = now.getTime()
// currentTime = 1602486314645

Two of these that might look strange are getMonth and getTime. Even though it is 2020-10-12, currentMonth is 9. That's because months are counted from 0. So January is 0, all the way to December which is month 11. You might assume getTime returns a time of day like "09:05", but instead it returns something as odd as the number of milliseconds since midnight 1970-01-01. That is JavaScript's way of expressing an exact point in time. Any time before 1970-01-01 is therefore represented as a negative number when using getTime.

The functions for computing milliseconds, seconds, minutes, hours, days and weeks between two Date objects are all trivial. Here's how they can be computed in JavaScript:

Compute milliseconds between two Date objects
function getMillisecondsDiff(startDate, endDate) {
return endDate.getTime() - startDate.getTime()
}

To compute the number of seconds between two Date objects, the getMillisecondsDiff function can be reused, like this:

Compute seconds between two Date objects
function getSecondsDiff(startDate, endDate) {
const milliseconds = getMillisecondsDiff(startDate, endDate)
const seconds = milliseconds / 1000
return seconds
}

Then we keep going in the same fashion, reusing the previous function each time:

Compute minutes between two Date objects
function getMinutesDiff(startDate, endDate) {
const seconds = getSecondsDiff(startDate, endDate)
const minutes = seconds / 60
return minutes
}

Compute hours between two Date objects
function getHoursDiff(startDate, endDate) {
const minutes = getMinutesDiff(startDate, endDate)
const hours = minutes / 60
return hours
}

Compute days between two Date objects
function getDaysDiff(startDate, endDate) {
const hours = getHoursDiff(startDate, endDate)
const days = hours / 24
return days
}

Compute weeks between two Date objects
function getWeeksDiff(startDate, endDate) {
const days = getDaysDiff(startDate, endDate)
const weeks = days / 7
return weeks
}

These functions are all built on simple math. Computing exactly how many months or years it is between two Date objects is going to turn out to be a lot harder.

Computing months between dates

Before we get into computing in code, we have to consider how one month is defined. Since the length of a month varies — unlike days per week or minutes per hour — it isn't obvious how many months 10 days is. Should the average length of a month be used? Probably not — both because it's awkward to compute given the complexity around leap years, and because it would lead to oddities like February 1–15 being counted as less than a month even though more than half of the current month has passed.

I land on using the length of the current month to compute the decimals. Let me explain with a few examples.

Example 1

Start date: 2018-01-01 at 00:00
End date: 2020-02-01 at 00:00

To compute the number of months between the start date and end date in Example 1, we can begin by counting how many whole months there are between the dates. All of 2018 and 2019 give 24 months, and January gives one more, which results in 25 whole months. But what if the start month is, say, April in the example above? Let's try it as a new example.

Example 2

Start date: 2018-04-01 at 00:00
End date: 2020-02-01 at 00:00

This can be computed in the same way as Example 1 with the addition that the start month is subtracted from the result. So 12 + 12 + 2 - 4 = 22 months. The computation looks like this in JavaScript:

Compute the number of whole months between two Date objects
const fullMonths =
(endDate.getFullYear() - startDate.getFullYear()) * 12 +
endDate.getMonth() -
startDate.getMonth()

For this to truly be whole months, we assume it's the first day of each month. We need to account for the fact that it isn't always. Let's take a third example:

Example 3

Start date: 2018-04-24 at 00:00
End date: 2020-02-06 at 00:00

My thinking is that the calculation should start from there being 22 months between 2018-04-24 at 00:00 and 2020-02-24 at 00:00, then use the length of February to add or remove the remainder. To make it as exact as possible, we can compute the number of milliseconds between the end date and 2020-02-24 at 00:00 and divide it by the number of milliseconds in the end date's month. Like this:

Compute the exact number of months with decimals between two Date objects

const daysInEndDateMonth = new Date(
endDate.getFullYear(),
endDate.getMonth() + 1,
0,
).getDate()
const millisecondsInEndDateMonth = daysInEndDateMonth * 24 * 60 * 60 * 1000
const startDateInEndDateMonth = new Date(
endDate.getFullYear(),
endDate.getMonth(),
startDate.getDate(),
startDate.getHours(),
startDate.getMinutes(),
startDate.getSeconds(),
startDate.getMilliseconds(),
)
const millisecondsDiffInEndDateMonth =
endDate.getTime() - startDateInEndDateMonth.getTime()
const fractionalMonth =
millisecondsDiffInEndDateMonth / millisecondsInEndDateMonth
const months = fullMonths + fractionalMonth

Pulled out into functions, getMonthsDiff looks like this:

Compute months between two Date objects
function getMonthsDiff(startDate, endDate) {
const fullMonths = getFullMonth(startDate, endDate)
const daysInEndDateMonth = getDaysInMonth(endDate)
const millisecondsInEndDateMonth =
convertDaysToMilliseconds(daysInEndDateMonth)
const startDateInEndDateMonth = getStartDateInEndDateMonth(startDate, endDate)
const millisecondsDiffInEndDateMonth =
endDate.getTime() - startDateInEndDateMonth.getTime()
const fractionalMonth =
millisecondsDiffInEndDateMonth / millisecondsInEndDateMonth
const months = fullMonths + fractionalMonth
return months
}

function getFullMonth(startDate, endDate) {
return (
(endDate.getFullYear() - startDate.getFullYear()) * 12 +
endDate.getMonth() -
startDate.getMonth()
)
}

function getDaysInMonth(date) {
return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate()
}

function convertDaysToMilliseconds(days) {
return days * 24 * 60 * 60 * 1000
}

function getStartDateInEndDateMonth(startDate, endDate) {
return new Date(
endDate.getFullYear(),
endDate.getMonth(),
startDate.getDate(),
startDate.getHours(),
startDate.getMinutes(),
startDate.getSeconds(),
startDate.getMilliseconds(),
)
}

We can now test getMonthsDiff by passing in the start and end date from Example 3:

Number of months between two Date objects
const startDate = new Date("2018-04-24 00:00")
const endDate = new Date("2020-02-06 00:00")
const monthsDiff = getMonthsDiff(startDate, endDate)

// monthsDiff = 21.379310344827587

A bit of mental math shows it looks correct. Instead of computing in milliseconds, we can do a check using whole days, which should still match since the time of day is the same for the start and end date in the example.

Whole months are still 22 (per above). Then we need to subtract 24 - 6 = 18 days divided by the number of days in February 2020, which is 29 since 2020 is a leap year. 18/29 = 0.62068966. Finally, we get the number of months as 22 - 0.62068966 = 21.3793103, which matches the answer from getMonthsDiff exactly.

Computing years between dates

Exactly the same computation principle can be used for computing years between two dates:

Compute years between two Date objects
function getYearsDiff(startDate, endDate) {
const fullYears = endDate.getFullYear() - startDate.getFullYear()
const millisecondsInEndDateYear = getMillisecondsInYear(startDate)
const startMonthInEndDateYear = getStartMonthInEndDateYear(startDate, endDate)
const millisecondsDiffInEndDateYear =
endDate.getTime() - startMonthInEndDateYear.getTime()
const fractionalYears =
millisecondsDiffInEndDateYear / millisecondsInEndDateYear
const years = fullYears + fractionalYears
return years
}

function getMillisecondsInYear(date) {
return (
new Date(date.getFullYear(), 12, 0).getTime() -
new Date(date.getFullYear(), 0, 1).getTime()
)
}

function getStartMonthInEndDateYear(startDate, endDate) {
return new Date(
endDate.getFullYear(),
startDate.getMonth(),
startDate.getDate(),
startDate.getHours(),
startDate.getMinutes(),
startDate.getSeconds(),
startDate.getMilliseconds(),
)
}

We test getYearsDiff with a couple of example dates:

Years between two Date objects
const startDate = new Date("2018-01-01")
const endDate = new Date("2020-01-01")
const yearsDiff = getYearsDiff(startDate, endDate)

// yearsDiff = 2

That it's exactly two years between 2018-01-01 and 2020-01-01 is reassuring. Let's try something a little more complicated:

Years between two new Date objects
const startDate = new Date("2018-05-03")
const endDate = new Date("2020-03-22")
const yearsDiff = getYearsDiff(startDate, endDate)

// yearsDiff = 1.8846153846153846

I won't do a manual check here, but getYearsDiff also seems to be doing what it should (and I have verified manually myself).

That's it! I can brag about being 1658.770565638 weeks old, and you can see for yourself how old you are — exactly.