Start here. This is the direct spoken answer to practice first.
Why this question matters
Time bugs usually come from mixing an instant on the global timeline with a local business date or future wall-clock schedule. The type and stored data must preserve the meaning the product actually needs.
For an event that happened at a precise instant, I prefer DateTimeOffset at boundaries because the value includes an offset and maps unambiguously to UTC. A UTC DateTime can also represent an instant when its Kind is handled consistently, but an unspecified or local value is easy to misinterpret. TimeZoneInfo applies named time-zone rules when converting for users. A date-only business value such as a birthday uses DateOnly, while a local opening time may use TimeOnly plus the location's zone and business rules.