Replacing Parts of a Datetime in Python

Dates And Time Mar 19, 2026

Replacing Parts of a Datetime in Python

Replacing specific parts of a datetime object (year, month, day, hour, minute, etc.) is a common and powerful operation in data science. It allows you to normalize timestamps, set all records to the start of the day, align events to specific times, or adjust timezones without recreating the entire object. The .replace() method makes this task clean, readable, and efficient.

TL;DR — How to Replace Datetime Parts

  • dt.replace(year=..., month=..., hour=..., etc.)
  • Works on both datetime and date objects
  • Creates a new object (immutable-style behavior)
  • Pandas equivalent with .dt accessor or pd.to_datetime

1. Basic .replace() Usage

from datetime import datetime
from zoneinfo import ZoneInfo

dt = datetime(2026, 3, 19, 14, 30, 0, tzinfo=ZoneInfo("UTC"))

# Replace specific parts
dt_midnight = dt.replace(hour=0, minute=0, second=0, microsecond=0)
dt_new_year = dt.replace(year=2027)
dt_new_month = dt.replace(month=12)

print(dt_midnight)      # 2026-03-19 00:00:00+00:00

2. Real-World Data Science Examples

import pandas as pd

# Create a small demo file so this example runs as-is
# (in your project, sales_data.csv is your real export)
import numpy as np
rng = np.random.default_rng(42)
n = 60
pd.DataFrame({
    "order_id": range(1001, 1001 + n),
    "order_date": pd.date_range("2026-01-01", periods=n, freq="3D"),
    "customer_id": rng.integers(101, 121, n),
    "customer_name": rng.choice([" ana", "ben ", "chen", "dana"], n),
    "product_id": rng.integers(1, 9, n),
    "region": rng.choice(["North", "South", "East", "West"], n),
    "category": rng.choice(["Electronics", "Computers", "Books", "Home"], n),
    "payment_method": rng.choice(["card", "cash", "wallet"], n),
    "segment": rng.choice(["consumer", "business"], n),
    "quantity": rng.integers(1, 6, n),
    "amount": rng.uniform(50, 2500, n).round(2),
    "discount": rng.choice([0.0, 0.05, 0.1, 0.2], n),
}).assign(
    price=lambda d: (d["amount"] / d["quantity"]).round(2),
    profit=lambda d: (d["amount"] * rng.uniform(0.05, 0.3, n)).round(2),
).assign(
    ship_date=lambda d: d["order_date"] + pd.Timedelta(days=2),
    status=lambda d: np.where(d["amount"] > 2000, "priority", "standard"),
).to_csv("sales_data.csv", index=False)

df = pd.read_csv("sales_data.csv", parse_dates=["order_date"])

# Example 1: Normalize all timestamps to midnight (start of day)
df["order_date_start"] = df["order_date"].apply(
    lambda x: x.replace(hour=0, minute=0, second=0, microsecond=0)
)

# Example 2: Set all events to the same hour for comparison
df["order_date_hour"] = df["order_date"].apply(lambda x: x.replace(minute=0, second=0))

# Example 3: Move all records to the first day of the month
df["first_of_month"] = df["order_date"].apply(lambda x: x.replace(day=1))

3. Replacing Timezone Information

dt = datetime.now(ZoneInfo("UTC"))

# Change timezone without changing the instant in time
dt_ny = dt.replace(tzinfo=ZoneInfo("America/New_York"))   # wrong way
# Correct way:
dt_ny = dt.astimezone(ZoneInfo("America/New_York"))

4. Best Practices in 2026

  • Use .replace() for simple component changes on individual datetime objects
  • For large DataFrames, prefer vectorized pandas methods or .apply() with lambda
  • Always work with timezone-aware objects before replacing parts
  • Keep original datetime column and create new derived columns for replaced values
  • Use replace() to normalize times (e.g., set to midnight or hour start)

How replace Works on Datetimes

datetime.replace returns a new datetime with selected fields changed, such as replace(day=1) for the first of the month or replace(hour=0, minute=0, second=0, microsecond=0) for midnight. The original object is unchanged, because datetimes are immutable.

replace does not move a timestamp in time; it simply overwrites fields. Using it to change tzinfo therefore relabels the time zone without converting the clock time, which is usually a bug.

In pandas, .dt.to_period("M").dt.start_time and .dt.normalize() cover common replace use cases for whole columns.

Worked Example: Month Starts and Invalid Dates

We compute month starts and see what happens with an impossible day.

from datetime import datetime
import pandas as pd

dt = datetime(2026, 3, 19, 14, 30, 45)
print(dt.replace(day=1, hour=0, minute=0, second=0))
print(dt)

try:
    datetime(2026, 1, 31).replace(month=2)
except ValueError as err:
    print("ValueError:", err)

s = pd.Series(pd.to_datetime(["2026-03-19 14:30", "2026-04-02 08:00"]))
print(s.dt.to_period("M").dt.start_time.tolist())

replace returns the month start while dt itself is unchanged. Changing 31 January to February fails with a ValueError, because February has no 31st. pandas returns month starts for the whole column.

Common Mistakes

  • Using replace to convert time zones.
  • Expecting replace to modify the original object.
  • Replacing the month without checking the day.
  • Looping over rows instead of using .dt methods.

Quick Summary

  • replace overwrites fields in a new object.
  • It does not convert time zones.
  • Invalid dates raise ValueError.
  • Use .dt methods for columns.

Conclusion

Replacing parts of a datetime object with .replace() is a simple yet powerful technique that every data scientist should master. In 2026, it is commonly used for normalizing timestamps, creating start-of-day/hour features, aligning data, and preparing clean time-based features for modeling and reporting.

Next steps:

  • Go through one of your datasets and create new columns by replacing specific parts of the datetime (e.g., start of day, first of month, etc.)

Related Tutorials

Share:
Last updated: March 2026
Built-in Functions in Python 2026 str() in Python 2026: String Conversion + Modern Formatting & Best Practices memoryview with JAX in Python 2026: Zero-Copy NumPy → JAX Array Interop + Efficient ML Examples memoryview with TensorFlow in Python 2026: Zero-Copy NumPy → Tensor Interop + GPU Pinning & ML Examples memoryview with TensorFlow in Python 2026: Zero-Copy NumPy → Tensor Interop + ML Examples memoryview with NumPy & PyTorch in Python 2026: Zero-Copy Views, Efficient Slicing & ML Interop Examples memoryview with NumPy in Python 2026: Zero-Copy Views, Efficient Slicing & Real ML Examples memoryview() in Python 2026: Zero-Copy Magic for Large Binary Data + Real Examples import() in Python 2026: How It Works, Security Risks & Modern Alternatives (importlib) zip() in Python 2026: How to Use It, strict=True Behavior & Real-World Examples vars() in Python 2026: Accessing Object Namespace + Modern Introspection Patterns type() in Python 2026: Dynamic Type Inspection & Object Creation + Modern Patterns tuple() in Python 2026: Immutable Sequences + Modern Patterns & Best Practices super() in Python 2026: Method Resolution & Modern Inheritance Patterns sum() in Python 2026: Summing Iterables + Modern Numeric Patterns & Best Practices staticmethod() in Python 2026: Static Methods, Utility Functions & Modern Best Practices sorted() in Python 2026: Sorting Iterables + Modern Patterns & Best Practices slice() in Python 2026: Creating Slice Objects + Modern Patterns & Best Practices setattr() in Python 2026: Dynamic Attribute Setting + Modern Patterns & Safety set() in Python 2026: Mutable Sets Creation + Modern Patterns & Best Practices