A Date in Apex holds a calendar day: a year, a month, and a day of the month. It carries no time of day and no time zone, which makes it the right type for a birthday, a close date, or a renewal date.
Date.today() gives the current day, and Date.newInstance() builds any day you name:
Date todayValue = Date.today(); Date launchDay = Date.newInstance(2024, 3, 15);
The arguments are year, month, day, in that order. Months count from 1, so March is 3 and not 2.
Each part of a date has its own method:
System.debug(launchDay.year()); // 2024 System.debug(launchDay.month()); // 3 System.debug(launchDay.day()); // 15
The add methods return a NEW date and leave the original alone, exactly the way string methods do:
System.debug(launchDay.addDays(10)); // 2024-03-25 System.debug(launchDay.addMonths(3)); // 2024-06-15 System.debug(launchDay.addYears(1)); // 2025-03-15
A negative argument moves backward, so addDays(-7) is one week earlier.
daysBetween() returns how many days you would have to add to the first date to reach the second. The answer is negative when the second date is in the past:
Date endDay = Date.newInstance(2024, 3, 25); System.debug(launchDay.daysBetween(endDay)); // 10
addMonths() never spills over into the following month. Adding one month to January 31 gives February 29 in a leap year and February 28 otherwise, because those are the last valid days of that month.
Almost every record in Salesforce carries a date. Building one, reading its parts, and shifting it forward or backward is the foundation of every renewal, deadline, and age calculation you will write.