Python Tutorial: Datetime Module - How to work with Dates, Times, Timedeltas, and Timezones
Based on Corey Schafer's video on YouTube. If you like this content, support the original creators by watching, liking and subscribing to their content.
Use naive datetimes for simple calculations, but switch to aware datetimes when time zones or daylight saving time matter.
Briefing
Python’s datetime module is the backbone for working with dates, times, time deltas, and time zones—but the biggest practical hurdle is knowing when to use “naive” versus “aware” datetimes. Naive datetimes lack enough information to resolve time zones or daylight saving time, making them simpler to manipulate but risky for anything that depends on real-world offsets. Aware datetimes carry time zone (and DST) context, preventing silent mistakes when converting between regions.
The tutorial starts with the basics: importing the module and creating a date using year, month, and day. It highlights a common pitfall—passing leading zeros for integers like 07 triggers a syntax error, so single-digit months and days must be provided as plain integers. From there, it demonstrates convenience constructors such as date.today() for the current local date, plus attribute accessors like year, month, and day. It also compares weekday() and isoweekday(), noting the different numbering schemes: weekday uses Monday=0 through Sunday=6, while ISO weekday uses Monday=1 through Sunday=7.
Time deltas then take center stage as the difference between two dates or times. A timedelta representing seven days can be added to a date to compute “one week from now,” or subtracted to compute “one week ago.” The tutorial also draws a crucial type distinction: adding or subtracting a timedelta from a date yields another date, while subtracting one date from another yields a timedelta. That distinction is used to calculate time until a birthday by subtracting the current date from a fixed birthday date, then extracting results via timedelta.days and timedelta.total_seconds() (to get a seconds-based measure rather than just whole days).
For time-of-day handling, datetime.time focuses on hours, minutes, seconds, and microseconds, while datetime.datetime combines both date and time. The tutorial shows how to access components (like dt.date() and dt.time()) and how to shift datetimes by adding timedelta objects. It further compares constructors like datetime.today(), datetime.now(), and datetime.utcnow(), clarifying that “UTC” in the method name doesn’t automatically make the object time zone aware—TZ info still matters.
Time zones are handled with the third-party pytz package, installed via pip, because Python’s documentation recommends it for using the time zone database. The workflow emphasizes best practice: build time zone aware datetimes in UTC (using tzinfo=pytz.UTC), then convert to other zones with astimezone(pytz.timezone(...)). The tutorial demonstrates converting from UTC to US Mountain time using the correct pytz zone string (e.g., us_Mountain) and explains how to discover valid zone names by iterating over pytz.all_timezones.
Finally, it addresses the conversion problem that naive datetimes can’t be directly converted with astimezone—pytz raises an error when tzinfo is missing. The fix is to “attach” time zone context using localize(): create a naive local datetime, then localize it with the appropriate pytz time zone (like us_Mountain) to make it aware before converting to US Eastern time. The tutorial closes with practical formatting tools: ISO output via isoformat(), custom string formatting using strftime format codes, and parsing strings back into datetimes with strptime (via datetime.strptime).
Cornell Notes
The core lesson is how to manage Python datetimes safely: naive datetimes lack time zone/DST context, while aware datetimes include tzinfo so conversions are reliable. The datetime module supports dates (year-month-day), times (hour-minute-second-microsecond), and combined datetimes, plus timedelta for differences and arithmetic. Date arithmetic works differently depending on what’s subtracted or added: date ± timedelta → date, while date − date → timedelta. For time zones, pytz is used to create UTC-aware datetimes and convert them with astimezone; naive datetimes must first be made aware using localize(). Formatting and parsing complete the workflow with isoformat(), strftime, and strptime.
What’s the practical difference between naive and aware datetimes in Python?
How do weekday() and isoweekday() differ, and why does it matter?
What does timedelta represent, and how do results differ when adding/subtracting it versus subtracting two dates?
Why does datetime.utcnow() not automatically produce a time zone aware datetime?
How do you convert between time zones with pytz, and what’s the fix when starting from a naive datetime?
What are the main formatting and parsing tools shown for datetimes?
Review Questions
- When would you choose a naive datetime over an aware one, and what risk does the naive choice introduce?
- If you subtract two dates in datetime, what type do you get back, and how would you extract “days until” from it?
- Why must localize() be used before astimezone() when the datetime starts as naive?
Key Points
- 1
Use naive datetimes for simple calculations, but switch to aware datetimes when time zones or daylight saving time matter.
- 2
Create dates with datetime.date(year, month, day) using plain integers—leading zeros like 07 cause syntax errors.
- 3
Use timedelta for duration arithmetic: date ± timedelta yields a date, while date − date yields a timedelta.
- 4
Prefer UTC as the baseline for time zone aware work, then convert with astimezone() to the target zone.
- 5
With pytz, convert aware datetimes directly using astimezone(pytz.timezone(...)), but make naive datetimes aware first using localize().
- 6
Format datetimes for output with isoformat() or strftime, and parse strings back with datetime.strptime() using matching format codes.