As pointed out your time calculations are incorrect.
Avoid mixing units
Your function is basically just calculating the months between two dates but you are working in both years and months.
Rather than calculate the years then the months convert both dates to the same unit. In this case that would be months.
Converting to months and back.
With both dates in months you can just use simple math on the months.
Example What year will I be when twice my age.
int birth = 1967 * 12 + 8 - 1;
int now = 2021 * 12 + 10 - 1;
int yearTwiceAge = (birth + (now - birth) * 2) / 12;
Rather than check for negatives use abs (see example A).
The little things
Format the output
It is also always nice to ensure the output is clean and that the wording matches the values. EG its "1 year" not "1 years" and if there are 0 months or years we never write "0 years" or "0 months"(see example A)
Help the user
People write dates in many ways so rather than force them to use a particular format, get a string and try various date formats to parse the string into a date. If you can not parse the date then ask again and show an example of a correct format. (see example B)
You can also use the C style time libraries to help.
Example A
Using Months as the units and formatting the result
#include <iostream>
void MonthsBetween(int yearA, int monthA, int yearB, int monthB) { // months from 1 to 12
int dif = abs((yearA * 12 + monthA - 1) - (yearB * 12 + monthB - 1));
int years = dif / 12;
int months = dif % 12;
std::cout << "Between " << monthA << "/" << yearA << " and ";
std::cout << monthB << "/" << yearB;
if (years) { std::cout << " there " << (years == 1 ? "is " : "are "); }
else if (months) { std::cout << " there " << (months == 1 ? "is " : "are "); }
else {
std::cout << " there is no difference.\n";
return;
}
if (years) { std::cout << years << " year" << (years > 1 ? "s" : ""); }
if (years && months) { std::cout << " and "; }
if (months) { std::cout << months << " month" << (months > 1 ? "s" : ""); }
std::cout << ".\n";
}
Usage examples...
int main() {
MonthsBetween(1921, 10, 2021, 10);
MonthsBetween(1921, 1, 2021, 10);
MonthsBetween(2023, 4, 2020, 3);
MonthsBetween(2020, 4, 2022, 3);
MonthsBetween(2020, 8, 2021, 1);
return 0;
}
/* Output
Between 10/1921 and 10/2021 there are 100 years.
Between 1/1921 and 10/2021 there are 100 years and 9 months.
Between 4/2023 and 3/2020 there are 3 years and 1 month.
Between 4/2020 and 3/2022 there is 1 year and 11 months.
Between 8/2020 and 1/2021 there are 5 months.
*/
Example B
The code below will try and parse the dateStr
using several formats returning true
and setting the time object when successful. It will also understand "now"
to mean "now"
#include <sstream>
#include <iomanip>
const std::string formats[] {"%Y-%m", "%m-%Y", "%m/%Y", "%Y/%m"};
bool ParseDate(std::string dateStr, std::tm *date) {
if (dateStr.compare("now") == 0) {
std::time_t t = std::time(nullptr);
*date = *std::localtime(&t);
return true;
}
for (auto f : formats) {
std::istringstream ss(dateStr);
ss >> std::get_time(date, (char *)&f[0]);
if (!ss.fail()) { return true; }
}
std::cout << "Invalid date. Use format eg Jan 1960 as YYYY/MM is 1960/01\n";
return false;
}
Usage example...
// using the MonthsBetween function from prev example
int main() {
std::tm birth, now;
ParseDate("10/2002", &birth);
ParseDate("now", &now);
MonthsBetween(birth.tm_year + 1900, birth.tm_mon + 1, now.tm_year + 1900, now.tm_mon + 1);
}
/* Outputs
Between 3/2002 and 10/2021 there are 19 years and 7 months.
*/