Indian Financial Year (April–March) ending logic in Oracle SQL.

Indian Financial Year (April–March) ending logic in Oracle SQL.


🇮🇳 Financial Year (April–March)

Financial Year:

  • Starts → 01-APR

  • Ends → 31-MAR (next year)


✅ 1. Get Financial Year End Date for a Given Date

Example: '15-DEC-2025'

SELECT CASE
         WHEN TO_CHAR(TO_DATE('15-DEC-2025','DD-MON-YYYY'),'MM') >= '04'
         THEN TO_DATE('31-MAR-' || (TO_CHAR(TO_DATE('15-DEC-2025','DD-MON-YYYY'),'YYYY') + 1),'DD-MON-YYYY')
         ELSE TO_DATE('31-MAR-' || TO_CHAR(TO_DATE('15-DEC-2025','DD-MON-YYYY'),'YYYY'),'DD-MON-YYYY')
       END AS FIN_YEAR_END
FROM dual;

Result:

31-MAR-2026

✅ 2. Optimized & Cleaner Method (Recommended)

This is simpler and better for production code:

SELECT ADD_MONTHS(
         TRUNC(TO_DATE('15-DEC-2025','DD-MON-YYYY'),'YYYY') + INTERVAL '3' MONTH,
         12
       ) - 1 AS FIN_YEAR_END
FROM dual;

✅ 3. Dynamic Version (Using SYSDATE)

SELECT CASE
         WHEN EXTRACT(MONTH FROM SYSDATE) >= 4
         THEN TO_DATE('31-MAR-' || (EXTRACT(YEAR FROM SYSDATE) + 1),'DD-MON-YYYY')
         ELSE TO_DATE('31-MAR-' || EXTRACT(YEAR FROM SYSDATE),'DD-MON-YYYY')
       END AS FIN_YEAR_END
FROM dual;

✅ 4. Financial Year Start Date

SELECT ADD_MONTHS(
         TRUNC(TO_DATE('15-DEC-2025','DD-MON-YYYY'),'YYYY'),
         3
       ) AS FIN_YEAR_START
FROM dual;

✅ 5. Financial Year Label (Useful for SLA Reports)

SELECT CASE
         WHEN EXTRACT(MONTH FROM SYSDATE) >= 4
         THEN EXTRACT(YEAR FROM SYSDATE) || '-' || (EXTRACT(YEAR FROM SYSDATE)+1)
         ELSE (EXTRACT(YEAR FROM SYSDATE)-1) || '-' || EXTRACT(YEAR FROM SYSDATE)
       END AS FIN_YEAR
FROM dual;

Example Output:

2025-2026

🎯 Practical Use in SLA / Revenue Reports

You can filter data like this:

WHERE fault_date BETWEEN fin_year_start AND fin_year_end

or directly:

WHERE fault_date BETWEEN
      ADD_MONTHS(TRUNC(SYSDATE,'YYYY'),3)
  AND ADD_MONTHS(TRUNC(SYSDATE,'YYYY'),15)-1


Here is a combined reusable package for Indian Financial Year (April–March), suitable for SLA / Revenue / MTTR reporting.

This is optimized, clean, and production-ready.


✅ Package Specification

CREATE OR REPLACE PACKAGE pkg_fin_year_util AS

    -- Returns Financial Year Start Date (01-APR-YYYY)
    FUNCTION get_fin_year_start (p_date DATE)
        RETURN DATE;

    -- Returns Financial Year End Date (31-MAR-YYYY)
    FUNCTION get_fin_year_end (p_date DATE)
        RETURN DATE;

    -- Returns Financial Year Label (e.g. 2025-26)
    FUNCTION get_fin_year_label (p_date DATE)
        RETURN VARCHAR2;

    -- Returns Financial Quarter (Q1–Q4, Apr–Mar basis)
    FUNCTION get_fin_quarter (p_date DATE)
        RETURN VARCHAR2;

END pkg_fin_year_util;
/

✅ Package Body

CREATE OR REPLACE PACKAGE BODY pkg_fin_year_util AS

    ---------------------------------------------------------
    -- Financial Year Start (01-APR-YYYY)
    ---------------------------------------------------------
    FUNCTION get_fin_year_start (p_date DATE)
        RETURN DATE
    IS
    BEGIN
        RETURN ADD_MONTHS(
                   TRUNC(p_date, 'YYYY'),
                   CASE
                       WHEN EXTRACT(MONTH FROM p_date) >= 4 THEN 3
                       ELSE -9
                   END
               );
    END get_fin_year_start;


    ---------------------------------------------------------
    -- Financial Year End (31-MAR-YYYY)
    ---------------------------------------------------------
    FUNCTION get_fin_year_end (p_date DATE)
        RETURN DATE
    IS
    BEGIN
        RETURN ADD_MONTHS(
                   TRUNC(p_date, 'YYYY'),
                   CASE
                       WHEN EXTRACT(MONTH FROM p_date) >= 4 THEN 15
                       ELSE 3
                   END
               ) - 1;
    END get_fin_year_end;


    ---------------------------------------------------------
    -- Financial Year Label (e.g. 2025-26)
    ---------------------------------------------------------
    FUNCTION get_fin_year_label (p_date DATE)
        RETURN VARCHAR2
    IS
        v_start_year NUMBER;
        v_end_year   NUMBER;
    BEGIN
        IF EXTRACT(MONTH FROM p_date) >= 4 THEN
            v_start_year := EXTRACT(YEAR FROM p_date);
            v_end_year   := v_start_year + 1;
        ELSE
            v_end_year   := EXTRACT(YEAR FROM p_date);
            v_start_year := v_end_year - 1;
        END IF;

        RETURN v_start_year || '-' || SUBSTR(v_end_year, 3, 2);
    END get_fin_year_label;


    ---------------------------------------------------------
    -- Financial Quarter (Apr–Mar)
    ---------------------------------------------------------
    FUNCTION get_fin_quarter (p_date DATE)
        RETURN VARCHAR2
    IS
        v_month NUMBER := EXTRACT(MONTH FROM p_date);
    BEGIN
        RETURN CASE
                   WHEN v_month BETWEEN 4 AND 6  THEN 'Q1'
                   WHEN v_month BETWEEN 7 AND 9  THEN 'Q2'
                   WHEN v_month BETWEEN 10 AND 12 THEN 'Q3'
                   ELSE 'Q4'
               END;
    END get_fin_quarter;

END pkg_fin_year_util;
/

✅ Example Usage

SELECT pkg_fin_year_util.get_fin_year_start(DATE '2025-12-15') AS FY_START,
       pkg_fin_year_util.get_fin_year_end(DATE '2025-12-15')   AS FY_END,
       pkg_fin_year_util.get_fin_year_label(DATE '2025-12-15') AS FY_LABEL,
       pkg_fin_year_util.get_fin_quarter(DATE '2025-12-15')    AS FY_QTR
FROM dual;

Output:

01-APR-2025
31-MAR-2026
2025-26
Q3

🚀 SLA / Revenue Example (Index Friendly Filtering)

⚠ Instead of:

WHERE pkg_fin_year_util.get_fin_year_label(fault_date) = '2025-26'

Use:

WHERE fault_date BETWEEN
      pkg_fin_year_util.get_fin_year_start(DATE '2025-12-15')
  AND pkg_fin_year_util.get_fin_year_end(DATE '2025-12-15')

This keeps index usage intact for large FMS / SLA tables.



Post a Comment

And that's all there is to it!

If anyone has any other questions or requests for future How To posts, you can either ask them in the comments or email me. Please don't feel shy at all!

I'm certainly not an expert, but I'll try my hardest to explain what I do know and research what I don't know.

Previous Post Next Post