The Email That Broke Me

From: CFO To: Me Subject: Q2 Numbers Look Wrong Message: “Why does Q2 show January-March? Our fiscal year starts in July.”

My Internal Monologue: Because Excel thinks January is Q1 like a NORMAL PERSON.

My Actual Response: “I’ll fix it right away.”


The Problem: Excel Was Built for Calendar Years

Excel’s QUARTER() function assumes:

  • Q1 = January-March
  • Q2 = April-June
  • Q3 = July-September
  • Q4 = October-December

Great for most businesses!

Terrible for:

  • Government agencies (July 1 year-end)
  • Schools & universities (June 30 year-end)
  • Nonprofits (various year-ends)
  • International companies (April 1 year-end in Japan/UK)
  • Any organization that doesn’t follow the calendar year

Translation: Excel assumes you’re “normal.”

If you’re not? Good luck.


The Excel “Solution” (I Use That Term Loosely)

Attempt #1: Nested IF Statements

=IF(MONTH(A2)>=7, "Q"&ROUNDUP((MONTH(A2)-6)/3,0), "Q"&ROUNDUP((MONTH(A2)+6)/3,0))

What This Does:

  • If month ≥ July: Calculate quarter from July
  • If month < July: Add 6 months, then calculate

Problems:

  • Unreadable
  • Error-prone
  • Slow to write
  • Impossible to audit 6 months later

Maintenance: “What does this formula do again?” ¯\_(ツ)_/¯


Attempt #2: Lookup Table

| Month | Fiscal_Quarter |
|-------|----------------|
| 1 | Q3 |
| 2 | Q3 |
| 3 | Q3 |
| 4 | Q4 |
| 5 | Q4 |
| 6 | Q4 |
| 7 | Q1 |
| 8 | Q1 |
| 9 | Q1 |
| 10 | Q2 |
| 11 | Q2 |
| 12 | Q2 |

Then: =VLOOKUP(MONTH(A2), Lookup_Table, 2, FALSE)

Problems:

  • Extra worksheet/table required
  • Another thing that can break
  • Needs documentation
  • Different fiscal years = different lookup tables

Scalability: “We need to support 5 different fiscal calendars…” cries in Excel


Attempt #3: Power Query (For the Brave)

Power Query can handle custom fiscal years!

Steps:

  1. Import data into Power Query
  2. Add custom column
  3. Write M language code:
= Date.QuarterOfYear(
 Date.AddMonths([Date], -6)
 )

Problems:

  • Power Query learning curve
  • Locked in Excel (can’t easily share logic)
  • M language debugging = nightmare
  • Refresh delays on large datasets

Collaboration: “Can you send me the Power Query code?” sends 500-line M script


Why Fiscal Years Are Actually Hard

It’s not just quarters. It’s everything:

Problem #1: Fiscal Year Calculation

Calendar Year: Easy

  • Date: January 15, 2025
  • Year: 2025

Fiscal Year (July 1 year-end): Confusing

  • Date: January 15, 2025
  • Fiscal Year: 2025 or 2024?

Answer: FY 2025 (because it’s July 2024 - June 2025)

But if the date was June 15, 2025:

  • Fiscal Year: Still FY 2025

And if the date was July 15, 2025:

  • Fiscal Year: FY 2026

My Brain:


Problem #2: Fiscal Quarter Calculation

July 1 Fiscal Year:

  • Q1 = July, August, September
  • Q2 = October, November, December
  • Q3 = January, February, March
  • Q4 = April, May, June

Excel: “January is Q1. Fight me.”


Problem #3: Year-Over-Year Comparisons

Task: Compare Q2 FY2025 vs Q2 FY2024

Excel Thinks:

  • Q2 2025 = Apr-Jun 2025
  • Q2 2024 = Apr-Jun 2024

Reality:

  • Q2 FY2025 = Oct-Dec 2024
  • Q2 FY2024 = Oct-Dec 2023

Result: Your comparison is completely wrong.


Enter Python: Fiscal Years Done Right

One Line. That’s It.

import pandas as pd

df['Date'] = pd.to_datetime(df['Date'])

# Calculate fiscal quarter (July 1 year-end)
df['Fiscal_Quarter'] = pd.PeriodIndex(df['Date'], freq='Q-JUN').strftime('Q%q')

# Done. 

Result:

Date Fiscal_Quarter
2025-01-15 Q3
2025-04-20 Q4
2025-07-10 Q1
2025-10-05 Q2

Perfect!


How It Works

The Magic Parameter: freq='Q-JUN'

Translation: “Quarters ending in June”

  • Q-JAN = Quarters ending in January (Feb-Apr, May-Jul, Aug-Oct, Nov-Jan)
  • Q-FEB = Quarters ending in February
  • Q-MAR = Quarters ending in March (Apr-Jun, Jul-Sep, Oct-Dec, Jan-Mar) = Calendar year!
  • Q-JUN = Quarters ending in June (Jul-Sep, Oct-Dec, Jan-Mar, Apr-Jun) = Fiscal year (July 1 start)
  • Q-DEC = Quarters ending in December = Also calendar year

Your Organization Uses Different Fiscal Year?

Just change the ending month!

# April 1 fiscal year (Japan, UK)
df['Fiscal_Quarter'] = pd.PeriodIndex(df['Date'], freq='Q-MAR').strftime('Q%q')

# October 1 fiscal year (US Federal Government)
df['Fiscal_Quarter'] = pd.PeriodIndex(df['Date'], freq='Q-SEP').strftime('Q%q')

# Custom: February 28 year-end
df['Fiscal_Quarter'] = pd.PeriodIndex(df['Date'], freq='Q-FEB').strftime('Q%q')

One parameter change. That’s it.


Bonus: Fiscal Year Calculation

# Calculate fiscal year (July 1 year-end)
df['Fiscal_Year'] = df['Date'].dt.to_period('A-JUN').dt.year

Examples:

Date Fiscal_Year
2025-01-15 2025 # In FY 2025 (Jul 2024 - Jun 2025)
2025-06-30 2025 # Last day of FY 2025
2025-07-01 2026 # First day of FY 2026
2024-12-15 2025 # Also in FY 2025

Real-World Example: Monthly Expense Report by Fiscal Quarter

The Scenario

Task: Analyze expenses by fiscal quarter for government agency (July 1 year-end)

Data:

Date Expense_Type Amount
2024-07-15 Payroll 125000
2024-08-20 Supplies 15000
2024-10-05 Payroll 125000
2024-11-12 Equipment 45000
2025-01-10 Payroll 125000
2025-02-14 Travel 8000
2025-04-18 Payroll 125000
2025-05-22 Consulting 25000

Goal: Sum expenses by fiscal quarter


The Excel Way: Pain

Step 1: Add fiscal quarter column with formula

=IF(MONTH(A2)>=7, "Q"&ROUNDUP((MONTH(A2)-6)/3,0), "Q"&ROUNDUP((MONTH(A2)+6)/3,0))

Step 2: Copy formula down

Step 3: Create pivot table

Step 4: Group by fiscal quarter and expense type

Step 5: Format results

Time: 15 minutes

Errors: “Wait, why is October showing as Q2? It should be Q2… oh wait, I messed up the formula.”


The Python Way: Joy

import pandas as pd

# Read data
df = pd.read_excel('expenses.xlsx')
df['Date'] = pd.to_datetime(df['Date'])

# Calculate fiscal periods
df['Fiscal_Quarter'] = pd.PeriodIndex(df['Date'], freq='Q-JUN').strftime('Q%q')
df['Fiscal_Year'] = df['Date'].dt.to_period('A-JUN').dt.year

# Summarize by fiscal quarter
summary = df.groupby(['Fiscal_Year', 'Fiscal_Quarter', 'Expense_Type'])['Amount'].sum()

print(summary)

Output:

Fiscal_Year Fiscal_Quarter Expense_Type
2025 Q1 Payroll 125000
 Supplies 15000
 Q2 Equipment 45000
 Payroll 125000
 Q3 Payroll 125000
 Travel 8000
 Q4 Consulting 25000
 Payroll 125000

Time: 30 seconds

Errors: Zero

Accuracy: Perfect


Advanced: Handling Partial Fiscal Years

Scenario: You started tracking expenses mid-year (October 2024)

Question: How much did we spend in Q1 and Q2 so far this fiscal year?

import pandas as pd
from datetime import datetime

# Read data
df = pd.read_excel('expenses.xlsx')
df['Date'] = pd.to_datetime(df['Date'])

# Current fiscal year
current_fy = pd.Period(datetime.now(), freq='A-JUN').year

# Filter to current fiscal year
df_fy = df[
 df['Date'].dt.to_period('A-JUN').dt.year == current_fy
].copy()

# Calculate fiscal quarter
df_fy['Fiscal_Quarter'] = pd.PeriodIndex(df_fy['Date'], freq='Q-JUN').strftime('Q%q')

# Summary by quarter
quarterly_summary = df_fy.groupby('Fiscal_Quarter')['Amount'].sum()

print(f"Expenses for FY {current_fy}:")
print(quarterly_summary)
print(f"\nTotal FY {current_fy} to date: ${df_fy['Amount'].sum():,.2f}")

Output:

Expenses for FY 2025:
Fiscal_Quarter
Q1 140000
Q2 170000
Q3 133000
Q4 25000 # Partial (not complete yet)

Total FY 2025 to date: $468,000.00

Bonus: Month Numbers in Fiscal Calendar

Problem: I need month 1 = July, month 2 = August, …, month 12 = June

Solution:

# Calculate fiscal month (1-12, starting in July)
df['Fiscal_Month'] = ((df['Date'].dt.month - 7) % 12) + 1

Result:

Date Calendar_Month Fiscal_Month
2024-07-15 7 (July) 1
2024-08-20 8 (August) 2
2024-12-05 12 (December) 6
2025-01-10 1 (January) 7
2025-06-20 6 (June) 12

Perfect for:

  • Budget vs. actual reporting (“We’re in month 8 of 12”)
  • Fiscal month-over-month comparisons
  • “Months remaining in fiscal year” calculations

The “Aha!” Moment

My director walked by my desk:

Director: “How long will the Q2 analysis take?”

Me (Old Way): “A few hours. Need to fix the fiscal quarter formulas, rebuild the pivot tables…”

Me (Python Way): “Already done. Sent it 5 minutes ago.”

Director: checks email “This is… really detailed. How did you do this so fast?”

Me: “Python handles fiscal years natively. One line of code.”

Director: “Can you show the rest of the team?”

Me: “Already scheduled a brown bag lunch session for next week.”

Director: “You’re getting a raise.”

(Okay, that last part didn’t happen, but a guy can dream!)


Common Fiscal Year Scenarios

Scenario #1: Government Agency (July 1 year-end)

df['Fiscal_Quarter'] = pd.PeriodIndex(df['Date'], freq='Q-JUN').strftime('Q%q')
df['Fiscal_Year'] = df['Date'].dt.to_period('A-JUN').dt.year

Scenario #2: UK/Japan (April 1 year-end)

df['Fiscal_Quarter'] = pd.PeriodIndex(df['Date'], freq='Q-MAR').strftime('Q%q')
df['Fiscal_Year'] = df['Date'].dt.to_period('A-MAR').dt.year

Scenario #3: US Federal Government (October 1 year-end)

df['Fiscal_Quarter'] = pd.PeriodIndex(df['Date'], freq='Q-SEP').strftime('Q%q')
df['Fiscal_Year'] = df['Date'].dt.to_period('A-SEP').dt.year

Scenario #4: Retail (February 1 year-end - avoids holiday season)

df['Fiscal_Quarter'] = pd.PeriodIndex(df['Date'], freq='Q-JAN').strftime('Q%q')
df['Fiscal_Year'] = df['Date'].dt.to_period('A-JAN').dt.year

The Bottom Line

Excel:

  • Complex nested formulas
  • Lookup tables
  • Power Query learning curve
  • Error-prone
  • Hard to maintain

Python:

  • One line of code
  • Works for ANY fiscal year
  • Easy to read
  • Zero maintenance
  • Portable (works across organizations)

Your Turn

Next time you need fiscal quarters:

df['Fiscal_Quarter'] = pd.PeriodIndex(df['Date'], freq='Q-JUN').strftime('Q%q')

That’s it. You’re done.

No more Excel gymnastics. No more nested IFs. No more lookup tables.

Just one line that actually works.


Try It Yourself

Want the complete working example with sample data? Download from GitHub

Have a fiscal year horror story? Share it in the comments! Let’s commiserate together.


Join the Discussion on Discord! -

Stuck with a weird fiscal calendar? Need help with date calculations? Join our Discord community!

Join PANDAUDIT Discord Server


Next time: “The Case of the Missing Millions: Tracking Down Rounding Errors” →