EthicsComputerCourses
Join training +91 90532 10052

Frequencies & Date Ranges

Time Series · Lesson 4 of 31 Intermediate 6 min read Updated

By the end of this lesson you will be able to create any regular calendar in pandas: every day, every Monday, every month start, every quarter of the Indian financial year. You will also check whether a series really is regular and count working days around holidays.

What a frequency is

A frequency is the regular gap between the rows of a time series. Daily milk collection at a dairy in Anand has a daily frequency. GST returns filed every month have a monthly frequency. Many forecasting tools need to know the frequency, because "one step ahead" means one day for daily data and one month for monthly data.

pandas describes frequencies with short codes called offset aliases. You met "D" and "MS" already.

Step 1. Run the code to see five common codes side by side.

PythonRun it yourself
import pandas as pd

for code, meaning in [("D", "every day"), ("W-MON", "every Monday"), ("MS", "month start"),
                      ("ME", "month end"), ("QS", "quarter start")]:
    dates = pd.date_range("2025-01-01", periods=4, freq=code)
    print(f"{code:<6} {meaning:<14}", [d.strftime("%d %b") for d in dates])
Output
D      every day      ['01 Jan', '02 Jan', '03 Jan', '04 Jan']
W-MON  every Monday   ['06 Jan', '13 Jan', '20 Jan', '27 Jan']
MS     month start    ['01 Jan', '01 Feb', '01 Mar', '01 Apr']
ME     month end      ['31 Jan', '28 Feb', '31 Mar', '30 Apr']
QS     quarter start  ['01 Jan', '01 Apr', '01 Jul', '01 Oct']

You should notice two things. W-MON skips ahead to the first Monday, 6 January, because 1 January 2025 was a Wednesday. And ME lands on the true last day of each month, including 28 February.

pd.date_range needs any two of start, end and periods, plus freq. Here we gave start and periods.

CodeMeaningTypical use
hhourlyelectricity load, website visits
Dcalendar dayshop sales, rainfall
Bbusiness day (Monday to Friday)stock prices, bank work
W-SUN, W-MONweekly, ending or anchored on that dayweekly reports
MS, MEmonth start, month endmonthly sales, bills
QS, QEquarter start, quarter endquarterly results
YS, YEyear start, year endannual totals

Checking the frequency of a series

A series built with date_range remembers its frequency in index.freq. A series read from a file does not, even when the dates are perfectly regular. pd.infer_freq looks at the dates and tells you the pattern, if there is one.

Step 2. Check four weekly readings of a Pune housing society's water meter.

PythonRun it yourself
import pandas as pd

idx = pd.DatetimeIndex(["2025-01-06", "2025-01-13", "2025-01-20", "2025-01-27"])
print("freq attribute:", idx.freq)
print("inferred:", pd.infer_freq(idx))

s = pd.Series([410, 395, 430, 445], index=idx)
s = s.asfreq("W-MON")
print(s.index.freq)

broken = pd.DatetimeIndex(["2025-01-06", "2025-01-13", "2025-01-27"])
print("inferred with a gap:", pd.infer_freq(broken))
Output
freq attribute: None
inferred: W-MON
<Week: weekday=0>
inferred with a gap: None

The index first has no stored frequency (None), but infer_freq sees a Monday pattern. asfreq("W-MON") sets it. With one week missing, infer_freq returns None: the series is no longer regular. This is a quick health check. If you expect daily data and infer_freq says None, some days are missing or repeated. The next lesson fixes that.

Periods and the Indian financial year

A Timestamp is a moment, such as 15 June 2025 at midnight. A Period is a whole span, such as "June 2025" or "the first quarter". Monthly sales are really about periods: the total for June, not a value at one instant.

India's financial year runs from 1 April to 31 March. pandas handles this with a quarterly frequency that ends in March, Q-MAR.

Step 3. Find which month and which financial-year quarter a sale on 15 June 2025 belongs to.

PythonRun it yourself
import pandas as pd

sale_day = pd.Timestamp("2025-06-15")
month = sale_day.to_period("M")
fy_quarter = sale_day.to_period("Q-MAR")       # Indian financial year: April to March

print("Month period:", month, " starts", month.start_time.date(), " ends", month.end_time.date())
print("FY quarter:", fy_quarter, " starts", fy_quarter.start_time.date())
print("FY quarters:", list(pd.period_range("2025-04", "2026-03", freq="Q-MAR").astype(str)))
Output
Month period: 2025-06  starts 2025-06-01  ends 2025-06-30
FY quarter: 2026Q1  starts 2025-04-01
FY quarters: ['2026Q1', '2026Q2', '2026Q3', '2026Q4']

2026Q1 can look odd at first. pandas names a fiscal year by the year in which it ends. FY 2025-26 ends in March 2026, so its first quarter (April to June 2025) is 2026Q1. That matches how Indian companies say "Q1 FY26". To group sales by financial quarter, use df.groupby(df.index.to_period("Q-MAR")).sum().

Working days and holidays

Offices, banks and schools do not work every day. A courier company in Kochi planning staff needs the number of working days in each month. CustomBusinessDay is a frequency for Monday to Friday that also skips the holidays you list.

Step 4. Count working days in January 2026 with two example holidays.

PythonRun it yourself
import pandas as pd
from pandas.tseries.offsets import CustomBusinessDay

holidays = ["2026-01-01", "2026-01-26"]           # example list: confirm with your office calendar
working = CustomBusinessDay(holidays=holidays)    # Monday to Friday, minus the holidays

days = pd.date_range("2026-01-01", "2026-01-31", freq=working)
print("Working days in January 2026:", len(days))
print("First three:", [d.strftime("%a %d") for d in days[:3]])
print("Plain weekdays:", len(pd.bdate_range("2026-01-01", "2026-01-31")))
Output
Working days in January 2026: 20
First three: ['Fri 02', 'Mon 05', 'Tue 06']
Plain weekdays: 22

January 2026 has 22 weekdays. New Year's Day (a Thursday) and Republic Day (a Monday) remove two, leaving 20. The number of working days changes every month, and it often explains a large part of monthly sales or output. You will use this idea again in the festivals lesson.

Common mistakes

  • Using "M" or "H". pandas 3.0 wants "ME" and "h".
  • Mixing month start and month end. Sales labelled MS and targets labelled ME will not line up when joined.
  • Assuming a file is regular. Run pd.infer_freq on the index; None means gaps or repeats.
  • Using calendar quarters for Indian accounts. Use Q-MAR for the April to March financial year.

Key points

  • Frequency is the regular gap between rows; pandas names it with aliases such as D, W-MON, MS, ME.
  • pd.date_range builds a regular calendar from two of start, end and periods.
  • pd.infer_freq checks regularity; asfreq sets a frequency.
  • Periods describe spans; Q-MAR gives Indian financial-year quarters.
  • CustomBusinessDay(holidays=...) counts real working days.

Exercise

Ananya's bakery in Kochi files a report every quarter of the financial year. Build a monthly date range (month start) from April 2025 to March 2026, convert each date to its Q-MAR period, and print how many months fall in each quarter.

Show solution
Python
import pandas as pd

months = pd.date_range("2025-04-01", "2026-03-01", freq="MS")
quarters = months.to_period("Q-MAR")
print(pd.Series(1, index=quarters).groupby(level=0).sum())
Output
2026Q1    3
2026Q2    3
2026Q3    3
2026Q4    3
Freq: Q-MAR, dtype: int64

Every financial quarter holds three months, and all four belong to FY 2025-26, which pandas labels 2026.

Quick Quiz

1. Which alias gives the last day of each month in pandas 3.0?

2. pd.infer_freq returns None for a daily sales index. What does this suggest?

3. In pandas, which period is the quarter April to June 2025 with freq="Q-MAR"?

Learn Time Series with a mentor

Free lessons get you started. Our Data Science & Machine Learning training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call