datetime.now() is how Python hands you the current date and time, in a single object:
from datetime import datetime
now = datetime.now() # 2026-09-29 10:16:12.051584
For the date on its own, date.today() is shorter. To control how it looks, pass a pattern to strftime().
One thing has changed recently and is worth knowing: datetime.utcnow() is deprecated. The replacement is covered below, along with formatting, timezones and timestamps. Output is from a real run on Python 3.12.5.

Get the current date and time with datetime.now()
One call gives you everything:
from datetime import datetime
now = datetime.now()
print("datetime.now() ->", now)
print("type ->", type(now).__name__)
print()
print("the date and the time, down to microseconds, in one object.")
print()
print("pull out the parts you want:")
print(" year ->", now.year)
print(" month ->", now.month)
print(" day ->", now.day)
print(" hour ->", now.hour)
print(" minute ->", now.minute)
print(" second ->", now.second)
Output:
datetime.now() -> 2026-09-29 10:21:28.007947
type -> datetime
the date and the time, down to microseconds, in one object.
pull out the parts you want:
year -> 2026
month -> 9
day -> 29
hour -> 10
minute -> 21
second -> 28

datetime.now() returns a single object holding both date and time.Every part is available as an attribute, so there is no parsing to do. The microseconds are real precision, not padding, though the operating system clock may not update that finely.
Note the import. datetime is both a module and a class inside it, which is why from datetime import datetime looks odd the first time you write it.
Get the current date or time on its own
Two shorter routes when you do not need both halves:
from datetime import datetime, date
print("just the date:")
print(" date.today() ->", date.today())
print(" datetime.now().date() ->", datetime.now().date())
print()
print("just the time:")
print(" datetime.now().time() ->", datetime.now().time())
print()
print("date.today() is the direct route when the time is irrelevant.")
print("There is no time.today(), so the time comes from a datetime.")
Output:
just the date:
date.today() -> 2026-09-29
datetime.now().date() -> 2026-09-29
just the time:
datetime.now().time() -> 10:21:28.088303
date.today() is the direct route when the time is irrelevant.
There is no time.today(), so the time comes from a datetime.
date.today() is the direct one. There is no matching time.today(), so the time comes from a datetime with .time() called on it.
Once you have a date object, formatting and arithmetic work exactly as they do on a datetime. Counting days between two dates builds on that.
Format the date and time with strftime
The default text is rarely the text you want:
from datetime import datetime
now = datetime.now()
print("the raw object prints in a fixed way:")
print(" ", now)
print()
print("strftime turns it into whatever text you want:")
for pattern in ("%Y-%m-%d", "%d/%m/%Y", "%H:%M:%S",
"%Y-%m-%d %H:%M:%S", "%B %d, %Y", "%I:%M %p", "%A"):
print(f" {pattern:20} -> {now.strftime(pattern)}")
print()
print("an f-string does the same without calling strftime:")
print(f' f"{{now:%Y-%m-%d %H:%M}}" -> {now:%Y-%m-%d %H:%M}')
print()
print("and the standard machine-readable form:")
print(" now.isoformat() ->", now.isoformat())
Output:
the raw object prints in a fixed way:
2026-09-29 10:21:28.159803
strftime turns it into whatever text you want:
%Y-%m-%d -> 2026-09-29
%d/%m/%Y -> 29/09/2026
%H:%M:%S -> 10:21:28
%Y-%m-%d %H:%M:%S -> 2026-09-29 10:21:28
%B %d, %Y -> September 29, 2026
%I:%M %p -> 10:21 AM
%A -> Tuesday
an f-string does the same without calling strftime:
f"{now:%Y-%m-%d %H:%M}" -> 2026-09-29 10:21
and the standard machine-readable form:
now.isoformat() -> 2026-09-29T10:21:28.159803

strftime() turns a datetime into whatever text you need.| Code | Means | Example |
|---|---|---|
%Y | Four digit year | 2026 |
%m | Month as a number | 09 |
%B | Month name | September |
%d | Day of the month | 29 |
%A | Weekday name | Tuesday |
%H / %I | Hour, 24 or 12 clock | 10 |
%M / %S | Minute and second | 16 / 12 |
%p | AM or PM | AM |
An f-string accepts the same codes directly, which saves a method call in the middle of a message. Going the other way, turning text back into a date uses the matching codes.
Why datetime.utcnow() is deprecated
This one has changed, and older tutorials have not caught up:
import warnings
from datetime import datetime, timezone
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
value = datetime.utcnow()
print("datetime.utcnow() ->", value)
print("its tzinfo ->", value.tzinfo, " <- no timezone attached")
for w in caught:
print()
print(f"{w.category.__name__}:")
print(str(w.message))
print()
print("the replacement keeps the timezone:")
modern = datetime.now(timezone.utc)
print(" datetime.now(timezone.utc) ->", modern)
print(" its tzinfo ->", modern.tzinfo)
Output:
datetime.utcnow() -> 2026-09-29 04:51:28.223799
its tzinfo -> None <- no timezone attached
DeprecationWarning:
datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).
the replacement keeps the timezone:
datetime.now(timezone.utc) -> 2026-09-29 04:51:28.223799+00:00
its tzinfo -> UTC

utcnow() warns, and the value it returns carries no timezone.The problem is visible in the output. utcnow() hands back a datetime holding UTC values with tzinfo=None, so nothing in the object records that it is UTC. Anything that reads it later has to be told separately.
datetime.now(timezone.utc) returns the same instant with the timezone attached, so the value carries its own meaning. Switch to it now rather than waiting for the removal.
Naive and aware datetimes
The distinction the deprecation is pushing you towards:
from datetime import datetime, timezone
naive = datetime.now()
aware = datetime.now(timezone.utc)
print("naive ->", naive, " tzinfo:", naive.tzinfo)
print("aware ->", aware, "tzinfo:", aware.tzinfo)
print()
try:
naive - aware
except TypeError as err:
print("naive - aware -> TypeError:", err)
print()
print("a naive datetime does not know what it means. Two of them from")
print("different machines cannot be compared safely.")
print()
print("attaching a timezone to a naive value you KNOW is UTC:")
print(" ", naive.replace(tzinfo=timezone.utc))
Output:
naive -> 2026-09-29 10:21:28.293028 tzinfo: None
aware -> 2026-09-29 04:51:28.293028+00:00 tzinfo: UTC
naive - aware -> TypeError: can't subtract offset-naive and offset-aware datetimes
a naive datetime does not know what it means. Two of them from
different machines cannot be compared safely.
attaching a timezone to a naive value you KNOW is UTC:
2026-09-29 10:21:28.293028+00:00

A naive datetime has no timezone, so it means whatever the machine that produced it happened to mean. Two of them from different servers cannot be compared safely.
Python refuses to mix the two rather than guessing. When you know a naive value is UTC, .replace(tzinfo=timezone.utc) labels it without shifting the clock.
Current time in a specific timezone
zoneinfo has been in the standard library since Python 3.9:
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
print("the same instant, shown in three places:")
print(" UTC ->", datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S %Z"))
print(" New York ->", datetime.now(ZoneInfo("America/New_York")).strftime("%Y-%m-%d %H:%M:%S %Z%z"))
print(" Tokyo ->", datetime.now(ZoneInfo("Asia/Tokyo")).strftime("%Y-%m-%d %H:%M:%S %Z%z"))
print()
print("zoneinfo ships with Python and handles daylight saving for you,")
print("which a fixed offset such as timezone(timedelta(hours=-5)) cannot.")
print()
print("converting rather than re-reading the clock:")
utc_now = datetime.now(timezone.utc)
print(" UTC ->", utc_now.strftime("%H:%M:%S %Z"))
print(" as Tokyo ->", utc_now.astimezone(ZoneInfo("Asia/Tokyo")).strftime("%H:%M:%S %Z"))
Output:
the same instant, shown in three places:
UTC -> 2026-09-29 04:51:28 UTC
New York -> 2026-09-29 00:51:28 EDT-0400
Tokyo -> 2026-09-29 13:51:28 JST+0900
zoneinfo ships with Python and handles daylight saving for you,
which a fixed offset such as timezone(timedelta(hours=-5)) cannot.
converting rather than re-reading the clock:
UTC -> 04:51:28 UTC
as Tokyo -> 13:51:28 JST
