Python Central HubSign in

Data Analytics with Python / Phase 3: Data Manipulation with Pandas

Date Ranges, Frequencies and Shifting

Build fixed-frequency date indexes with date_range, understand pandas frequency strings and offsets, and move data forward or backward in time with shift.

Why fixed frequencies matter

A real timestamp column (like order_time from the previous page) is often irregular — orders don't arrive exactly every hour. But for analysis you frequently want a fixed-frequency index: every day, every business day, every 15 minutes. Pandas gives you two tools for this:

  • pd.date_range — generate a clean, evenly spaced DatetimeIndex.
  • .shift() — move values (or timestamps) forward/backward along that index.

Think of date_range as drawing the ruler, and shift as sliding your data along it.

Generating date ranges with date_range

Python
import pandas as pd
 
# Start + end (daily by default)
idx = pd.date_range("2024-01-01", "2024-01-06")
print(idx)
 
# Start + number of periods
idx2 = pd.date_range(start="2024-01-01", periods=5)
print(idx2)
 
# Business days only (skips weekends)
idx3 = pd.date_range("2024-01-01", periods=5, freq="B")
print(idx3)

date_range always needs at least two of: start, end, periods. Give it any two and it works out the rest.

Frequency strings and multiples

Frequencies combine a base alias with an optional multiplier:

AliasMeansAliasMeans
DCalendar dayMEMonth end
BBusiness dayMSMonth start
hHourQEQuarter end
minMinuteYEYear end
sSecondW-MONWeekly on Monday
Python
import pandas as pd
 
print(pd.date_range("2024-01-01", periods=4, freq="4h"))    # every 4 hours
print(pd.date_range("2024-01-01", periods=4, freq="5min"))  # every 5 minutes
print(pd.date_range("2024-01-01", periods=4, freq="ME"))    # last day of each month

Shifting data: leading and lagging

shift moves the values, keeping the index fixed — this creates NaN at the start or end, which is exactly what you want for lag/lead features:

Python
import pandas as pd
 
ts = pd.Series(
    [100, 105, 102, 108],
    index=pd.date_range("2024-01-31", periods=4, freq="ME"),
)
 
print(ts.shift(1))   # lag by 1 period — value moves down
print(ts.shift(-1))  # lead by 1 period — value moves up

A very common use of shift is computing period-over-period percent change:

Python
pct_change = ts / ts.shift(1) - 1
print(pct_change)

If you pass a freq, shift moves the timestamps instead of the values, so no data is discarded:

Python
print(ts.shift(2, freq="ME"))  # every date pushed forward by 2 months

Rolling dates forward with offsets

Pandas offset objects understand calendar rules. Adding MonthEnd() to any date "rolls forward" to the next month end — handy for snapping arbitrary dates onto a frequency grid:

Python
import pandas as pd
from pandas.tseries.offsets import MonthEnd, Day
 
now = pd.Timestamp("2024-01-17")
 
print(now + 3 * Day())        # simple: 3 calendar days later
print(now + MonthEnd())       # rolls forward to 2024-01-31
print(now + MonthEnd(2))      # rolls forward 2 month-ends: 2024-02-29
 
offset = MonthEnd()
print(offset.rollforward(now))  # 2024-01-31
print(offset.rollback(now))     # 2023-12-31 (previous month end)

Common pitfalls

  • Naive shift() (no freq) introduces NaN at the start or end — that's expected, not a bug.
  • Legacy aliases "M", "T", "H", "A" are no longer accepted — use "ME", "min", "h", "YE".
  • date_range needs exactly two of start / end / periods — passing all three (when inconsistent) or only one raises an error.

Visualize it

diagram From ruler to shifted series mermaid
date_range lays down a fixed-frequency ruler; shift then slides data along that ruler, leaving gaps at the edges.
sketch Shifting a timestamp series p5.js
The amber dots are the original values on the ruler; the blue dots show the same values shifted one step to the right.

🧪 Try It Yourself

Exercise 1 – Build a Fixed-Frequency Range

exerciseYour turn

Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.

Output
Press Run to see what your code prints.

Exercise 2 – Lag a Series With shift

exerciseYour turn

Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.

Output
Press Run to see what your code prints.

Exercise 3 – Roll a Date Forward to Month End

exerciseYour turn

Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.

Output
Press Run to see what your code prints.

Check your understanding

quizCheck yourself
  1. Which frequency string in modern pandas means month end?

    Show answer

    B — ME — Recent pandas renamed M to ME. MS is month start, and the old letters M, T, H and A now raise a ValueError.

  2. What does pd.date_range("2024-01-01", periods=5, freq="B") generate?

    Show answer

    B — Five business days, skipping weekends — B is the business day frequency. Starting on Monday 2024-01-01 it returns January 1 through 5.

  3. For ts = [100, 105, 102, 108], what does ts.shift(1) return?

    Show answer

    B — [NaN, 100, 105, 102] — shift(1) lags the values by one period, moving them down and leaving NaN at the start. shift(-1) leads them instead.

  4. For now = pd.Timestamp("2024-01-17"), what is now + MonthEnd(2)?

    Show answer

    C — 2024-02-29 — MonthEnd rolls forward to the next month end. One step gives 2024-01-31 and two steps give 2024-02-29, since 2024 is a leap year.

Next

Fixed-frequency ranges become tricky once you cross regions — see Time Zone Handling for how to localize and convert timestamps safely.

Was this page helpful?

Let us know how we did