You already know how to shift a date with addDays() and how to measure a gap with daysBetween(). Apex also ships a small set of helpers that answer calendar questions days alone cannot.
monthsBetween() measures the gap in months instead of days:
Date signed = Date.newInstance(2024, 1, 15); Date renewed = Date.newInstance(2024, 7, 15); System.debug(signed.monthsBetween(renewed)); // 6
Like daysBetween(), the answer is negative when the second date comes first.
Date.daysInMonth() is a static method that takes a year and a month and reports how many days that month actually has:
System.debug(Date.daysInMonth(2024, 2)); // 29 System.debug(Date.daysInMonth(2023, 2)); // 28
Date.isLeapYear() answers the same question more directly:
System.debug(Date.isLeapYear(2024)); // true
toStartOfMonth() returns the first day of the month a date falls in, and toStartOfWeek() returns the first day of its week:
Date anyDay = Date.newInstance(2024, 3, 22); System.debug(anyDay.toStartOfMonth()); // 2024-03-01
These are how you group records into monthly or weekly buckets without doing the arithmetic yourself.
monthsBetween() IGNORES the day of the month. March 1 to March 31 is 0 months, not 1, because both dates sit in the same calendar month. If you need the fractional part, measure in days instead.
Reporting almost always groups by month. Knowing how many months two records are apart, and how to snap a date to the start of its month, turns a pile of records into a clean monthly summary.