Cat Toolbox
Help CatBlog About Partnership 中文

BMI, Age and Date Calculators: Which Numbers to Trust, and When

CalculatorUpdated 2026-09-29

These three pages all look like single-purpose calculators, and they are, but each one answers a narrower question than its heading suggests. The BMI page answers "how does this ratio round"; the age page answers "how much UTC time has passed since midnight UTC on your birth date"; the date page answers "how many whole local days fit between two local midnights". Those are not the questions most people ask, and the difference is visible whenever you land near a boundary, near midnight, or in a timezone the page was not written for.

Everything below was read out of each page's own script and confirmed by driving the page itself. Where a number appears, it is the number the page actually shows.

Three pages, three ideas of "now"

  • The BMI calculator is stateless. It recomputes on every keystroke, stores nothing, and has no time dimension at all.
  • The age calculator starts a one-second clock when it loads and keeps recalculating against the current moment, so its output changes while you look at it.
  • The date calculator has two independent tabs — a difference between two dates and an offset from one date — and neither of them ever looks at the current time except to prefill the boxes.

BMI: the rounding happens before the label

The page computes the ratio, rounds it to one decimal, and only then decides which of the four bands it falls into. That order matters. At 170 cm:

Weight True BMI Displayed Band
53.32 kg 18.4498 18.4 Underweight
53.33 kg 18.4533 18.5 Normal
69.21 kg 23.9481 23.9 Normal
69.22 kg 23.9516 24.0 Overweight

Ten grams of input flips the label, and it flips in a way the true value does not support: 18.4533 is still below 18.5, and 23.9516 is still below 24, yet both are labelled as if they had crossed. The rounding is Math.round(bmi * 10) / 10 followed by a display of toFixed(1), so the classification uses the same number you see — there is no hidden precision behind it. If a reading sits within 0.05 of a boundary, treat the band as undecided rather than as an answer.

BMI: the unit toggle replaces your numbers, it does not convert them

Switching to Imperial does not convert what you typed. It writes a fixed pair — 67 inches and 143 pounds — into the two boxes, and switching back writes 170 and 65. Anything you had entered is discarded, in both directions.

The fixed pair is also not quite the same body as the metric default. 65 kg is 143.3005 lb and 170 cm is 66.9291 in, so the Imperial default is a rounded stand-in: it evaluates to 22.4 where the metric default evaluates to 22.5. Both are labelled Normal, so the difference is invisible in the band, but the page's claim that the two defaults show "the same" body type is off by a tenth of a BMI point.

If you need a real conversion, convert the numbers yourself and enter them — the page will happily compute 66.93 in and 143.3 lb and return 22.5.

BMI: what the formula tolerates

The two boxes carry min="1", which constrains the spinner arrows and nothing else. The script reads whatever is in them and guards only against zero:

  • A negative height is squared, so −170 cm gives exactly the same answer as +170 cm: 22.5, Normal.
  • A negative weight is not caught. −65 kg produces a BMI of −22.5, which is below 18.5 and therefore labelled Underweight, with the marker pinned to the left end of the scale.
  • There is no upper bound and no sanity range. 1 cm with 65 kg returns 650,000.0 and the Obese band.
  • Empty or zero input shows a dash in the big number, and nothing else changes: the band text, the advice line and the marker keep whatever they last displayed. The page's own copy says this out loud, which is more than most pages do.

The marker position is computed from the value and clamped to 5–95%, so the extremes never leave the track. The markup ships a hard-coded left: 42% on that marker; the script overwrites it with 39.5455% for the 22.5 default as soon as the page loads.

BMI: the "703" shortcut, and one overstated claim

The English page states that the imperial path is "mathematically identical to the 703 × lb ÷ in² shortcut". The code's factor is not 703 — it is 1 ÷ 0.0254² × 0.453592, or 703.0696 per pound per square inch. At 5 ft 9 in and 160 lb the page returns 23.6276 while the 703 shortcut gives 23.6253. That is a difference of about 0.002 BMI: real, and far too small to change the displayed tenth in ordinary use, but "mathematically identical" is not what is happening.

The same page calls its factors "the exact defined ones (1 inch = 0.0254 m, 1 pound = 0.453592 kg)". The inch figure is exact by definition; the pound figure is not. The defined value is 0.45359237 kg, and 0.453592 is a truncated version of it. The truncation shifts an imperial result in the seventh decimal place, which the one-decimal display erases — but the sentence is describing exactness the code does not have.

Age: the counters are anchored to UTC midnight, not to your day

The birth date comes out of a date input as YYYY-MM-DD, and new Date('2000-01-01') is parsed as midnight UTC, not midnight where you live. Everything downstream is measured from that instant: total months, total days, total hours.

The visible consequence is that the counters roll over at UTC midnight, which is 08:00 in Beijing and 20:00 in New York during daylight time. Taking 1 January 2000 as the birth date:

Local clock time Months shown Days shown
06:30 in Beijing 311 9,496
20:00 in Beijing 312 9,497

Same birth date, same day, two different answers depending on what time you look. Between local midnight and the roll-over hour the day count is one short of the calendar difference; after it, it matches.

For visitors west of UTC the parse also shifts the stored date by a day, which leaks into the year count near the start of a month. Someone born 29 February 1996, opening the page on 28 February 2027: in Beijing the page says 30 years old, in New York it says 31. The page has no timezone handling at all — whatever new Date() returns in your browser is what it uses.

Age: months are 30.44 days long, so the two counters disagree

The year count is assembled from calendar fields — it subtracts years, then borrows when the month and day have not been reached yet — and that part is sound. The month count is not: it divides the elapsed milliseconds by 30.44 days and floors the result.

At exactly 30 years old the page shows 359 months, not 360. A person born on 1 January 2000, viewed on 29 September 2026, shows 26 years next to 320 months — 8 months more than 26 × 12, because 30.44 understates the real average only sometimes, and the error runs in both directions depending on the span. Read the years line and the days line; ignore the months line if you are going to quote it to anyone.

Age: 29 February, and a countdown that is never zero

The countdown builds the next birthday from the current year, the birth month and the birth day, and lets the Date object roll over. On a common year, a 29 February birthday therefore targets 1 March: with the birth date 29 February 1996 viewed on 29 September 2026, the countdown points at 1 March 2027.

On your actual birthday the countdown does not read zero either. The target is built at local midnight, that instant is already in the past by the time you look, and the code advances a year: on 29 September 2026 a 29 September birthday reads 364 days left in Beijing and 363 in New York. Both are one day more than the same countdown on the following day.

Age: the clock keeps running after you clear the box

The page installs a one-second interval the first time it sees a valid date. Clearing the input sets the big number to a dash and then returns — without stopping the interval. The still-running clock writes the previous age back on its next tick, so the dash exists for under a second and the page keeps counting from a birth date that is no longer in the box.

A future date takes a different branch: the big number becomes "Not born yet" and the function returns before touching anything else. The months, days and hours cards, and the birthday countdown, keep whatever they showed for the last valid date, frozen, while the interval fires once a second and exits each time. Both behaviours are reproducible in a few seconds: enter a valid date, clear it, wait one second.

Date: the inclusive-end checkbox, and how the lines disagree

The difference tab parses both dates at local midnight, subtracts, floors to whole days, and then adds one if "include end date" is ticked — which it is by default. So the same day against itself reads 1 day, and 1 July to 3 July reads 3 days when ticked and 2 when not. The checkbox changes the answer by exactly one and nothing on the page warns you that the headline number has a switch on it.

The four result lines then use three different arithmetic conventions:

Weeks are exact: total days divided by seven, with the remainder printed separately. Months and years are counted by walking the calendar — add a month until you pass the end date — but their remainder lines are computed by subtracting 30.44 days per month and 365.25 days per year from the day total, then rounding. Whole numbers by calendar, remainders by average.

For a span that is exactly 312 months and exactly 26 years:

1 Jan 2000 → 1 Jan 2026 Shown
Days 9,498
Weeks 1,356 weeks, remainder 6 days
Months 312 months, remainder 1 day
Years 26 years, remainder 2 days

The remainder lines contradict the integers they sit next to. The day count and the weeks line are the two that can be checked against a calendar and come back correct.

Because the month walk starts from the real start date, it can also refuse to find a whole month at all: 31 January to 1 March 2026 counts 0 months and 29 days, because adding one month to 31 January lands on 3 March, past the end.

Date: reversing the dates leaves the old numbers on screen

If the end date comes before the start date the page does not return a negative. It writes "Start date must be earlier than end date" into the days slot and returns immediately — without clearing the week, month and year lines, which keep the values from whatever you last calculated. Measured: after computing a 26-year span and then swapping the two dates, the days slot shows the error text while the three lines beside it still read 1,356 weeks / 312 months / 26 years. The page's own FAQ states that the three boxes are left empty in this case; they are not.

Date: a clock change can cost you a day

Both dates are anchored at local midnight, so the difference in milliseconds is not always a clean multiple of 86,400,000. Where clocks move forward in spring, the gap between two midnights spanning the change is an hour short, and the floor then drops a day: in New York, 1 March 2026 to 9 March 2026 — eight calendar days — has two midnights 191 hours apart, so with "Include end date" unticked the page reports 7 days. With the box ticked, which is how the page loads, the extra day it adds happens to cover the loss and the result reads 8. The autumn change adds an hour instead, which the floor absorbs and never hands back: 1 November to 9 November 2026 is 193 hours, and prints 8 days unticked and 9 ticked — both correct.

Visitors in China never see this, because the clocks there do not move. Anyone in North America or Europe who uses the page across a spring change should either add a day to the unticked result, or leave the box ticked — the day it adds lands on the correct number, though for the wrong reason.

Date: the quick buttons write the UTC date

"Yesterday / Today / Tomorrow" take the current moment, add or subtract a day, and then format it with the UTC date. The default fill for all three date boxes does the same thing. So the value written depends on the UTC date, not your calendar:

You open the page at "Today" writes
00:05 in Beijing Yesterday's date
08:00 in Beijing Today's date
20:00 in New York (summer) Tomorrow's date

In Beijing the window where "Today" is wrong runs from midnight to 08:00; in New York it opens at 20:00 and runs to midnight. Nothing on the page indicates that the boxes were prefilled with anything other than today.

Date: months and years roll over instead of clamping

The offset tab adds to the month or year field and lets the Date object settle the result, which means a target beyond the end of the month spills into the next one:

Start Add Result
31 January 2026 1 month 3 March 2026
31 January 2024 1 month 2 March 2024
29 February 2024 1 year 1 March 2025
31 January 2026 6 months 31 July 2026

Six months from 31 January is fine because July has 31 days; one month is not, because February does not. This is the standard behaviour of the language's date type, and the page neither clamps to the month end nor warns. For contract dates, subscription renewals and anything with a 29th, 30th or 31st in it, check the result by hand or add days instead.

Which of the three to reach for

  • A screening ratio you will discuss with a professional: the BMI page. Read the band, not the tenth, and re-enter converted numbers yourself if you work in pounds and inches.
  • A count of days lived or days until a birthday, to the day: the age page, read on the same day you intend to quote it, from a timezone the page understands — its day counter is right for most of the day and one day short before the UTC roll-over.
  • A span between two dates, or a date offset: the date page. Quote the days line and the weeks line; treat the month and year remainders as rough, remember the checkbox is on, and add a day if the span crosses a spring clock change.

FAQ

Why does the BMI band change without the number changing much?

Because the band is read off the rounded value. Anything within 0.05 of 18.5, 24 or 28 sits on a boundary where the label can go either way.

Does switching units lose what I typed?

Yes. Both directions write fixed default values into both boxes. Convert and re-enter if you need your own numbers in the other unit.

Is a negative height or weight rejected?

No. A negative height squares away and gives a normal-looking result; a negative weight produces a negative BMI that the page labels Underweight.

Why do the age page's months and days not match?

The years are counted from calendar fields, the months from an average 30.44-day month, and the days from UTC midnight on the birth date. Only the years line is a calendar count.

Can I trust the age page's day count?

For most of the day, yes. It advances at UTC midnight rather than local midnight, so there is a window each day where it is one short, and the size of that window depends on where you are.

Why is my birthday countdown one day long?

The target is built at local midnight and is already in the past when you look, so the page advances to next year. On the day itself you see 364 or 363 days rather than zero.

Does the date page count the end date?

Only if the checkbox is ticked, and it is ticked by default. The same day against itself reads 1 day with it on and 0 with it off.

Why did I get 7 days for an eight-day span?

You are west of a spring clock change, the span crosses it, and "Include end date" is unticked. Between 1 March and 9 March 2026 in New York the two local midnights are 191 hours apart — seven days and 23 hours — so the floor drops a day. One day shorter tells the same story: 2 March to 9 March is seven calendar days but only 167 hours, and prints 6.

Does any of this leave my browser?

No. All three pages compute locally in JavaScript; nothing is uploaded or stored, and reloading restores the defaults.

Tools used in this guide

Advertisement