Understanding datetime.now() in Python
The datetime.now() function is one of the most frequently used tools when working with time in Python. In data science it powers logging, freshness checks, time-delta calculations, feature engineering, and real-time monitoring. In 2026, the modern, correct way to use it is always timezone-aware with the zoneinfo module.
TL;DR — Best Practice 2026
- Use
datetime.now(ZoneInfo("UTC"))or your local timezone - Avoid naive
datetime.now()in production code - Prefer
datetime.now(tz=...)over deprecatedutcnow() - Combine with pandas
.dtfor vectorized analysis
1. Basic Usage and Timezone Awareness
from datetime import datetime
from zoneinfo import ZoneInfo
# Correct modern way – timezone-aware
now_utc = datetime.now(ZoneInfo("UTC"))
now_ny = datetime.now(ZoneInfo("America/New_York"))
print(now_utc)
print(now_ny)
2. Real-World Data Science Examples
import pandas as pd
# Small inline sample so this example runs as-is.
# In a real project you would load it with pd.read_csv("sales_data.csv")
df = pd.DataFrame({
"customer_id": [101, 102, 103, 104, 105, 106],
"customer_name": ["Ana", "Ben", "Chen", "Dana", "Eli", "Fay"],
"order_date": ["2026-01-05", "2026-01-12", "2026-02-03",
"2026-02-18", "2026-03-01", "2026-03-09"],
"amount": [1250.75, 890.50, 2340.00, 1780.25, 2615.40, 450.00],
"quantity": [3, 2, 5, 4, 6, 1],
"profit": [312.69, 222.63, 585.00, 445.06, 653.85, 112.50],
"region": ["North", "South", "East", "North", "West", "South"],
"category": ["Electronics", "Books", "Electronics", "Home", "Home", "Books"],
"rating": [5, 4, None, 3, 5, 4],
"year": [2025, 2025, 2026, 2026, 2026, 2026],
"description": ["fast laptop", "python book", "noise cancelling headphones",
"desk lamp", "standing desk", "data science book"],
})
df["order_date"] = pd.to_datetime(df["order_date"]).dt.tz_localize("UTC") # make the dates UTC-aware
# Current time for freshness checks
current_time = datetime.now(ZoneInfo("UTC"))
df["hours_since_order"] = (current_time - df["order_date"]).dt.total_seconds() / 3600
df["is_fresh"] = df["hours_since_order"] < 24
# Logging with precise timestamps
log_entry = {
"timestamp": datetime.now(ZoneInfo("UTC")),
"event": "model_training_complete",
"model_version": "2026.1"
}
3. Common datetime.now() Variants
# Deprecated – avoid in new code
# utc_now_old = datetime.utcnow() # naive UTC; deprecated since Python 3.12
# Modern recommended
utc_now = datetime.now(ZoneInfo("UTC"))
# Local time
local_now = datetime.now() # system timezone (use with caution)
4. Best Practices in 2026
- Always specify a timezone with
ZoneInfo - Use UTC for logging, storage, and internal calculations
- Convert to local time only for display to users
- Store datetimes in UTC in databases and DataFrames
- Use pandas
.dt.tz_convert()for timezone conversions
now(), today(), utcnow() and Friends
datetime.now() with no argument returns the local wall-clock time as a naive value. datetime.now(tz) returns an aware value in that zone. datetime.today() behaves like now() without a zone. datetime.utcnow() returns a naive value in UTC and has been deprecated since Python 3.12, because a naive value that silently means "UTC" is easy to misuse. For measuring how long something takes, do not use now() at all: time.perf_counter() is monotonic and unaffected by clock changes.
Worked Example: Timing vs Timestamping
import time
from datetime import datetime, timezone
started_at = datetime.now(timezone.utc) # when it happened (for logs)
t0 = time.perf_counter() # how long it takes (for timing)
total = sum(i * i for i in range(200_000))
elapsed = time.perf_counter() - t0
finished_at = datetime.now(timezone.utc)
print(f"started {started_at.isoformat(timespec='seconds')}")
print(f"finished {finished_at.isoformat(timespec='seconds')}")
print(f"work took {elapsed:.4f} s")
print(started_at.tzinfo, finished_at >= started_at) # UTC True
timezone.utc from the standard library is equivalent to ZoneInfo("UTC") for this purpose and needs no time zone database.
A good pattern in data pipelines is to read the current time once at the start of a run, store it in a variable such as run_ts, and use that value for every freshness calculation and log record in the run. That way all rows share one reference point, and re-running the same job with the same run_ts gives the same results, which makes debugging much easier.
Common Mistakes
- Using
utcnow()in new code: usenow(timezone.utc) - Timing code with
now(): clock adjustments can make durations wrong or negative - Storing local naive times in a database shared across regions
Quick Summary
now(timezone.utc)for timestamps,perf_counter()for durationsutcnow()is deprecated since 3.12- Format with
isoformat()for logs and APIs
Conclusion
datetime.now() is simple but powerful when used correctly. In 2026 data science projects, always make it timezone-aware with ZoneInfo. This prevents subtle bugs, ensures consistent timestamps across environments, and makes your time-based features, logs, and freshness checks reliable and professional.
Next steps:
- Review all uses of
datetime.now()orutcnow()in your codebase and upgrade them to timezone-aware versions