Periods and Period Arithmetic
Timestamps vs periods
A TimestampTimestamp is an instant — one exact point in time. A PeriodPeriod is a span —
“the whole month of March 2024” or “fiscal Q4 2024.” Payroll, budgeting, and
reporting usually think in periods, not instants, so pandas gives PeriodPeriod its own
type instead of forcing you to fake spans with pairs of timestamps.
import pandas as pd
p = pd.Period("2024", freq="Y-DEC")
print(p) # the whole year 2024import pandas as pd
p = pd.Period("2024", freq="Y-DEC")
print(p) # the whole year 2024Period arithmetic
Adding or subtracting an integer shifts the period by that many units of its own frequency — no need to think in days:
print(p + 5) # 2029
print(p - 2) # 2022
q1 = pd.Period("2024", freq="Y-DEC")
q2 = pd.Period("2027", freq="Y-DEC")
print(q2 - q1) # <3 * YearEnds: month=12>print(p + 5) # 2029
print(p - 2) # 2022
q1 = pd.Period("2024", freq="Y-DEC")
q2 = pd.Period("2027", freq="Y-DEC")
print(q2 - q1) # <3 * YearEnds: month=12>Subtracting two periods of the same frequency gives you the number of periods
between them — like subtracting two dates gives you a timedeltatimedelta.
PeriodIndex and period_range
periods = pd.period_range("2024-01", "2024-06", freq="M")
print(periods)
ts = pd.Series(range(6), index=periods)
print(ts)periods = pd.period_range("2024-01", "2024-06", freq="M")
print(periods)
ts = pd.Series(range(6), index=periods)
print(ts)Converting frequency with asfreq
asfreqasfreq re-expresses a period at a different granularity. Since a year contains
months, you must say whether you want the start or end sub-period:
p = pd.Period("2024", freq="Y-JUN") # fiscal year ending in June
print(p.asfreq("M", how="start")) # 2023-07 — the fiscal year begins in July
print(p.asfreq("M", how="end")) # 2024-06 — and ends in Junep = pd.Period("2024", freq="Y-JUN") # fiscal year ending in June
print(p.asfreq("M", how="start")) # 2023-07 — the fiscal year begins in July
print(p.asfreq("M", how="end")) # 2024-06 — and ends in JuneQuarterly periods
Quarterly reporting is usually anchored to a fiscal year end. Q-DECQ-DEC means quarters
line up with a December year end (a normal calendar quarter):
q = pd.Period("2024Q4", freq="Q-DEC")
print(q)
print(q.asfreq("D", how="start")) # first day of the quarter
print(q.asfreq("D", how="end")) # last day of the quarterq = pd.Period("2024Q4", freq="Q-DEC")
print(q)
print(q.asfreq("D", how="start")) # first day of the quarter
print(q.asfreq("D", how="end")) # last day of the quarterConverting timestamps to periods (and back)
dates = pd.date_range("2024-01-01", periods=3, freq="ME")
ts = pd.Series(range(3), index=dates)
pts = ts.to_period() # timestamps -> periods
print(pts)
print(pts.to_timestamp()) # periods -> timestamps (start of period, by default)dates = pd.date_range("2024-01-01", periods=3, freq="ME")
ts = pd.Series(range(3), index=dates)
pts = ts.to_period() # timestamps -> periods
print(pts)
print(pts.to_timestamp()) # periods -> timestamps (start of period, by default)Common pitfalls
- A timestamp belongs to exactly one period for a given frequency — but the same
period can repeat (e.g. two dates in January both map to
2024-012024-01). Period("Aug-2011", "M").asfreq("A-JUN")Period("Aug-2011", "M").asfreq("A-JUN")maps August into the next fiscal year — frequency conversion depends on where the fiscal year boundary falls, not just the date.to_timestamp()to_timestamp()returns the start of the period unless you passhow="end"how="end".
Visualize it
flowchart LR A["Timestamp
'2024-03-15 10:00'"] -->|"to_period()"| B["Period('2024-03', 'M')
the whole month"] B -->|"asfreq('D', how='start')"| C["First day: 2024-03-01"] B -->|"asfreq('D', how='end')"| D["Last day: 2024-03-31"] B -->|"asfreq('Y-DEC')"| E["Period('2024', 'Y-DEC')
the whole year"]
🧪 Try It Yourself
Exercise 1 – Shift a Period by Integer Arithmetic
Exercise 2 – Build a Monthly PeriodIndex
Exercise 3 – Convert a Year Period Down to Its Start Month
Next
Periods describe fixed spans — Resampling and Frequency Conversion shows how to actually convert an irregular or high-frequency series into those spans, with real aggregation.
If this helped you, consider buying me a coffee ☕
Buy me a coffeeWas this page helpful?
Let us know how we did
