A date shown in a report needs a format readers can interpret, while calculations need the underlying date or time value. Python’s datetime module provides objects for representing those values.
I’ll show how to get today’s date or the current time and format it for display, including a value in an explicit time zone.
TL;DR: Get the Current Date and Time in Python
Use date.today() for today’s local date, datetime.now() for local date and time, and pass a time zone to datetime.now() when the result must identify a specific zone.
- Import date or datetime from the built-in datetime module.
- Use strftime() to format fields as text, or isoformat() for an ISO-style value.
- Use ZoneInfo for an IANA time zone such as America/New_York.
What Does a Python Date and Time Object Represent?
Python’s datetime module has separate objects for a calendar date and a date combined with a clock time. A date has calendar fields. A datetime adds clock fields and optional time-zone information.
A datetime is called aware when it has enough time-zone information to identify a specific moment. A naive datetime has no such information, so code must agree on whether it means local time, UTC, or something else.
How to Get and Format the Current Date and Time
The datetime module and zoneinfo module provide the APIs used below. The captured example prints local, UTC, and New York values.
Step 1: Get today’s local date
Import date when the clock time is not part of the value. date.today() returns the current date according to the machine’s local date configuration.
Write from datetime import date, then assign date.today() to a variable. The combined program in Step 2 prints this same date-only result on its first line.
The captured program prints the date-only value on its first output line.
Step 2: Get local date and time or an explicit time zone
datetime.now() without an argument returns local date and time as a naive datetime. Pass timezone.utc for an aware UTC value, or a ZoneInfo object for an IANA named zone.
from datetime import date, datetime, timezone
from zoneinfo import ZoneInfo
today = date.today()
print("date:", today)
local_now = datetime.now()
print("local:", local_now.strftime("%Y-%m-%d %H:%M:%S"))
utc_now = datetime.now(timezone.utc)
new_york_now = datetime.now(ZoneInfo("America/New_York"))
print("UTC:", utc_now.isoformat(timespec="seconds"))
print("New York:", new_york_now.strftime("%Y-%m-%d %H:%M:%S %z"))
The output from the captured run was:
date: 2026-10-16
local: 2026-10-16 20:30:06
year: 2026
month: 10
day: 16
hour: 20
minute: 30
second: 6
UTC: 2026-10-16T20:30:06+00:00
New York: 2026-10-16 16:30:06 -0400
The date line is a date object, while the local, UTC, and New York lines are datetime values rendered as text. Keeping those types distinct helps prevent a time-only requirement from turning into an ambiguous timestamp.
Step 3: Format the value for display
Use strftime() when an application needs a particular display string.
Common directives include:
| Directive | Meaning | Example |
|---|---|---|
| %Y | Four-digit year | 2026 |
| %m | Zero-padded month | 10 |
| %d | Zero-padded day | 16 |
| %H:%M:%S | 24-hour time | 19:59:30 |
| %z | UTC offset | -0400 |
For example, now.strftime(“%d/%m/%Y %H:%M:%S”) produces a day-first string with a 24-hour clock. A value such as 03/04/2026 remains ambiguous without an agreed format.
For a readable label in a report, use strftime() and select directives that match the format contract.
Step 4: Read fields or serialize a timestamp
A datetime exposes its components as integer attributes, including year, month, day, hour, minute, and second. Use those attributes when program logic needs one component, and use strftime() when the goal is a string for a person to read.
The example’s local value is printed with a format that includes the four-digit year and zero-padded month and day. Its time is displayed with a 24-hour clock. The separate integer fields show the same parts without parsing a string back into numbers.
Microseconds are available through the microsecond attribute and can be included with the %f directive. Add them when the consumer needs that precision, but omit them from a display where seconds are enough.
The format codes that include a clock depend on a datetime value. A date-only value has no hour or minute to display, so use date directives on it rather than expecting a missing time to appear.
When the timestamp is used for sorting or comparing events across regions, normalize to UTC at the system boundary. Convert to a person’s regional time only for display, using the named zone whose civil-time rules apply there.
The now() method returns a datetime built from the current clock reading. Its attributes let code use the value without first turning it into text, which avoids parsing a display string back into numbers.
Read the date and clock attributes
Use year, month, and day for calendar decisions, and hour, minute, second, and microsecond for clock-level decisions. These attributes are integers, so compare them numerically rather than comparing strings whose padding may differ.
The weekday() method returns an integer where Monday is 0 and Sunday is 6. The isoweekday() method uses Monday as 1 and Sunday as 7, so choose one convention and keep it consistent when mapping the result to names.
The date() method extracts the calendar date from a datetime. The time() method extracts a time without its date or zone, while timetz() preserves the time-zone information when present. Choose date() for a calendar grouping and retain the complete datetime when the event’s position on a timeline matters.
To get a timestamp representing an event, preserve an aware datetime rather than saving only separate fields. A numeric Unix timestamp can be produced with timestamp(), but its interpretation and precision need to match the receiving system. A formatted string is usually better for logs and human inspection, while a typed datetime is better for calculations within Python.
Microseconds are part of a datetime even when strftime() omits them. Datetime values that print to the same second can still differ internally, so do not use a seconds-only display string as a unique event key. Use the datetime value itself or serialize with enough precision for the application.
datetime.now() reads the system clock. The result is a snapshot, not a continuously updating clock, so call it again when a later reading is needed. For measuring elapsed time inside one process, use time.perf_counter() instead because wall-clock adjustments can change the result of subtracting two readings.
Format text without losing the value’s meaning
strftime() converts date and time fields into a string according to format directives. The resulting text is for display or a defined interchange format. Keep the original datetime for arithmetic, because a string no longer carries the object’s type or zone behavior.
Use isoformat() when an ISO-style representation is useful. An aware datetime includes its UTC offset in that output, while a naive value has no offset to serialize. An offset identifies a relationship to UTC at that instant, but it does not preserve the named region that supplied the civil-time rules.
For a date, ISO order places the year first, followed by month and day. That order avoids the day-first versus month-first ambiguity found in strings such as 04/05/2026. If an external system requires another layout, document the exact format at the boundary where the string is exchanged.
Use a locale-aware format only when the output is intended for a particular audience. Locale affects names and conventions, while a machine-facing format should remain stable regardless of the host’s language settings.
Calling now() with a tz argument changes the result from a naive local reading to an aware value in the requested zone. The argument must be a tzinfo object, such as timezone.utc or ZoneInfo(“Europe/Paris”). Passing a string by itself is not enough, because Python needs an object that can supply the zone’s offset rules.
The returned fields describe the local clock in that zone. The hour attribute is the hour after conversion.
Use astimezone() to convert an existing aware datetime for display. Calling now() again makes a new clock reading, so the values can differ by elapsed time.
Repeated or skipped wall-clock times can occur when regional clocks change. An aware datetime retains its offset and fold information for an ambiguous local time, while a naive datetime cannot express which occurrence was meant. For logs that must order events, preserve the aware timestamp and convert only when presenting it to a person.
Time Zone and Formatting Details to Check
I chose the standard-library route here because the task needs current values and named-zone handling, not date-string parsing or a third-party API. The datetime and zoneinfo modules cover those choices without an additional package in the example.
| Situation | Recommended value | Reason |
|---|---|---|
| Date on this machine | date.today() | Returns a date without clock fields |
| Local wall-clock display | datetime.now() | Uses the machine’s local time setting |
| Shared timestamp | datetime.now(timezone.utc) | Returns an aware UTC datetime |
| Region-specific clock | datetime.now(ZoneInfo(“America/New_York”)) | Uses named-zone rules, including offset changes |
For a local display, the host configuration determines the zone and its offset may not be carried. Store an aware value when another machine must interpret the same event.
UTC has a single offset and works well as a shared reference. The value from datetime.now(timezone.utc) is aware, which means its time-zone information is part of the datetime itself rather than an assumption held elsewhere in the application.
A fixed offset and a named region are different choices. An offset says how far a clock is from UTC at one point, while a name such as America/New_York lets ZoneInfo apply the region’s date-dependent offset rules.
Named zones require IANA time-zone data. Python looks for that data in the system database and can fall back to the tzdata package. Some environments, including Windows installations without a configured database, may need the package declared as an application dependency.
If ZoneInfo(“America/New_York”) raises ZoneInfoNotFoundError, check whether the runtime can access the IANA database or the tzdata distribution. Do not silently substitute a guessed UTC offset, because it can be wrong for another date in that region.
Formatting also has platform details. The Python documentation notes that available strftime() directives can vary with the platform’s C library, so use documented common directives when code must run on different operating systems.
For a date-only display, %Y-%m-%d has a clear year-month-day order.
Naive and aware datetimes should not be mixed casually. Comparisons between them raise TypeError, and a naive value does not say which offset applies. Use aware values consistently when timestamps cross time zones.
Common Time and Formatting Errors
Check the environment and the datetime types before relying on a named-zone timestamp.
- Missing zone data: ZoneInfo raises ZoneInfoNotFoundError. Provide the IANA database or the tzdata package before constructing the zone.
- Mixed awareness: Comparing naive and aware values raises TypeError. Convert both values to a consistent zone first.
- Unclear local zone: A stored local clock may lack a reliable offset. Store aware UTC and convert for display.
- Ambiguous display: A day-first string can be read as month-first. Use an agreed format such as %Y-%m-%d.
Conclusion: Choose the Right Date and Time Value
Use a date when the clock does not matter, and choose an aware datetime when the time zone matters. Format only at the display or interchange boundary so calculations keep their date and time semantics.
For the exact behavior and available format directives, consult the Python datetime documentation and the zoneinfo documentation. AskPython also explains the Python datetime module and how to create a range of dates.
FAQ
These answers cover common choices when retrieving a current date or timestamp in Python.
How do I get only today’s date in Python?
Import date from datetime and call date.today(). It returns the current local calendar date without a time.
How do I get the current date and time in UTC?
Call datetime.now(timezone.utc), after importing datetime and timezone from the datetime module. The result is an aware UTC datetime.
How do I display a date in a custom format?
Call strftime() on a date or datetime object with directives such as %Y, %m, and %d. The method returns formatted text.
Why does ZoneInfo raise ZoneInfoNotFoundError?
The system may not have IANA time-zone data and the tzdata package may not be available. Provide time-zone data in that environment before constructing the named zone.

