A Date holds a calendar day and nothing more. A Datetime holds a calendar day AND a time of day, down to the second. Use it whenever the hour matters: a meeting start, a case creation stamp, a scheduled job run.
Datetime.now() gives the current moment, and Datetime.newInstance() builds any moment you name:
Datetime rightNow = Datetime.now(); Datetime meeting = Datetime.newInstance(2024, 3, 15, 9, 30, 0);
The arguments are year, month, day, hour, minute, second. The hour uses a 24 hour clock, so 2 in the afternoon is 14 and not 2.
A Datetime has all the date methods you already know, plus three time methods:
System.debug(meeting.year()); // 2024 System.debug(meeting.day()); // 15 System.debug(meeting.hour()); // 9 System.debug(meeting.minute()); // 30 System.debug(meeting.second()); // 0
You can also pull out just the calendar day with date():
Date meetingDay = meeting.date(); // 2024-03-15
The add methods work exactly like the ones on Date, and there are extra ones for time:
System.debug(meeting.addHours(3)); // 2024-03-15 12:30:00 System.debug(meeting.addMinutes(45)); // 2024-03-15 10:15:00 System.debug(meeting.addDays(1)); // 2024-03-16 09:30:00
Adding rolls over cleanly. Adding 4 hours to 22:00 gives 02:00 on the NEXT day, so you never have to handle midnight yourself.
Datetime.newInstance() reads the numbers you pass in the time zone of the running user, and hour() reports back in that same time zone. When you need a moment that is identical for every user no matter where they sit, build it with Datetime.newInstanceGmt() instead.
Every Salesforce record carries CreatedDate and LastModifiedDate, and both are Datetime values. Reading the hour off one of them is how you answer questions like which cases arrived overnight.