Date Ranges, Frequencies and Shifting
Why fixed frequencies matter
Section titled “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 spacedDatetimeIndex..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
Section titled “Generating date ranges with date_range”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
Section titled “Frequency strings and multiples”Frequencies combine a base alias with an optional multiplier:
| Alias | Means | Alias | Means |
|---|---|---|---|
D | Calendar day | ME | Month end |
B | Business day | MS | Month start |
h | Hour | QE | Quarter end |
min | Minute | YE | Year end |
s | Second | W-MON | Weekly on Monday |
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 monthShifting data: leading and lagging
Section titled “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:
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 upA very common use of shift is computing period-over-period percent change:
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:
print(ts.shift(2, freq="ME")) # every date pushed forward by 2 monthsRolling dates forward with offsets
Section titled “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:
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
Section titled “Common pitfalls”- Naive
shift()(nofreq) introducesNaNat 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_rangeneeds exactly two ofstart/end/periods— passing all three (when inconsistent) or only one raises an error.
Visualize it
Section titled “Visualize it”flowchart LR A["pd.date_range(start, periods, freq)"] --> B["Fixed-frequency DatetimeIndex"] B --> C["Series/DataFrame on that index"] C --> D["ts.shift(1)
values slide down, NaN at top"] C --> E["ts.shift(1, freq='ME')
timestamps slide, no NaN"]
🧪 Try It Yourself
Section titled “🧪 Try It Yourself”Exercise 1 – Build a Fixed-Frequency Range
Section titled “Exercise 1 – Build a Fixed-Frequency Range”Exercise 2 – Lag a Series With shift
Section titled “Exercise 2 – Lag a Series With shift”Exercise 3 – Roll a Date Forward to Month End
Section titled “Exercise 3 – Roll a Date Forward to Month End”Fixed-frequency ranges become tricky once you cross regions — see Time Zone Handling for how to localize and convert timestamps safely.
pch.coffeeTagline
pch.coffeeCtapch.feedbackHeading
pch.feedbackSubheading