Hello Sri,
Your question should be more specific. What are you looking for? Do you have several dates in a table, and you want a query that - for each date - calculates the week number and week-based year (not necessarily the same as calendar year)? Or do you need a function (PL/SQL) that takes a date as input, and returns a string in the format WW-YYYY showing the week number and week-based year? Or do you need to create a lookup table, having week number, "year", starting Saturday date and ending Friday date? Or anything else?
You should also give a complete definition of "first week of week-based year". You gave two examples, which is good, but not a complete definition. From the examples, we can see already that your definition is not similar to the ISO definition of "week of the year". In the ISO definition, a week at the end of one year and beginning of next year always belongs to the year that has more of the days in that week (four or more days). This is the same as saying "if the Thursday of that week - a week is always from Monday to Sunday, with Thursday the middle day - falls in 2023 then the whole week is considered as part of 2023, as the last week of that year; but if the Thursday is in 2024, then the whole week becomes the first week of 2024." In your example, even if a week has four days in the "old" year and only three in the "new" year, it is still considered as part of the "new" year.
Below I will assume you have several dates in a single column in an input table, and you need a query that will show, in the output, the date, the week-based year, and the week number in that year. I show the "year" and the "week number" in separate columns - concatenating isn't the issue. To mimic the input table, I use a subquery in the WITH clause (the first one); in your case you wouldn't have that there, and instead of selecting from SAMPLE_INPUTS in PREP you would select from your actual table.
For each date, the query finds January 1st for that date's calendar year, and also January 1st of the following year. From these, a computation using ISO week (so that the computation is independent of locale) finds the beginning of the first week of the "current" year as well as that of the "next" year; this is done by shifting forward by two days, finding the Monday of the week and then shifting back two days. Then we compare the input date to the "first Saturday of the next week-based year" (which may still be in the current CALENDAR year!) to decide in which week-based year the data falls. And then the week number is either 1 (if the date falls in the next week-based year), or it is computed by comparing to the "first Saturday of the current year".
Note that in my example the dates don't have a time-of-day component (actually they do, but it's always 00:00:00); but the computation works without changes even if you have non-zero time of day in your input dates.
alter session set nls_territory='America';
alter session set nls_date_format='dd-MON-yyyy Dy';
with
sample_inputs (dt) as (
select date '2024-12-24' + level
from dual
connect by level <= 12
UNION ALL
select date '2025-12-24' + level
from dual
connect by level <= 12
)
, prep (dt, cal_yr, fsoy_crt, fsoy_next) as (
select dt,
extract (year from dt),
trunc(trunc(dt, 'year') + 2, 'iw') - 2,
trunc(add_months(trunc(dt, 'year'), 12) + 2, 'iw') - 2
from sample_inputs
)
select dt,
case when dt < fsoy_next then cal_yr else cal_yr + 1 end as wby, -- wby for week-based year
case when dt < fsoy_next then 1 + trunc((dt - fsoy_crt)/7) else 1 end as wk
from prep
;
Output:
DT WBY WK
--------------- ---- --
25-DEC-2024 Wed 2024 52
26-DEC-2024 Thu 2024 52
27-DEC-2024 Fri 2024 52
28-DEC-2024 Sat 2025 1
29-DEC-2024 Sun 2025 1
30-DEC-2024 Mon 2025 1
31-DEC-2024 Tue 2025 1
01-JAN-2025 Wed 2025 1
02-JAN-2025 Thu 2025 1
03-JAN-2025 Fri 2025 1
04-JAN-2025 Sat 2025 2
05-JAN-2025 Sun 2025 2
25-DEC-2025 Thu 2025 52
26-DEC-2025 Fri 2025 52
27-DEC-2025 Sat 2026 1
28-DEC-2025 Sun 2026 1
29-DEC-2025 Mon 2026 1
30-DEC-2025 Tue 2026 1
31-DEC-2025 Wed 2026 1
01-JAN-2026 Thu 2026 1
02-JAN-2026 Fri 2026 1
03-JAN-2026 Sat 2026 2
04-JAN-2026 Sun 2026 2
05-JAN-2026 Mon 2026 2