Reputation: 1192
In Oracle we get week number from following query:
select to_char(TO_DATE(SYSDATE,'DD-MM-YY'),'IW') from dual
I want to get date range of given week number,
for example for week no:1 date range is 01-01-2017 to 08-01-2017.
is there any way to get the date range for given week number?
Upvotes: 0
Views: 15392
Reputation: 21
Here's a query to list all ISO weeks from 2001 to 2099
SELECT TO_CHAR(TRUNC(dt, 'IW') + 6, 'IYYY-IW') AS week,
TRUNC(dt, 'IW') AS start_date,
TRUNC(dt, 'IW') + 6 AS end_date
FROM (SELECT DATE '2001-01-01' + ((LEVEL - 1) * 7) dt
FROM DUAL
CONNECT BY LEVEL <= 5165);
Upvotes: 1
Reputation: 12833
These kinds of problems are easy to solve with calendar tables.
The following query builds on the assumption (ISO 8601) that the 4th of January is present in the first week in a year. Therefore I can generate a valid date in the first week of any year by constructing the 4th of January like: to_date(year || '-01-04', 'yyyy-mm-dd')
. Oracle will tell me the day of week (sun=1, sat=7) for any date using to_char(date, 'D')
. The 4th of JAN 2017 happens to be a wednesday (day 4). Subtracting 3 days will give me the first day (sunday) of the first week of the year.
Now it is easy to find the start day in any given week in the year by simply adding 7 days for each week (not counting the first week).
with weeks as(
select 2017 as year, 39 as week from dual union all
select 2017 as year, 40 as week from dual union all
select 2018 as year, 35 as week from dual
)
select a.*
,to_date(year || '-01-04', 'yyyy-mm-dd') - to_number(to_char(to_date(year || '-01-04', 'yyyy-mm-dd'), 'D')) + 1 + (7 * (week-1)) as start_day
,to_date(year || '-01-04', 'yyyy-mm-dd') + 7 - to_number(to_char(to_date(year || '-01-04', 'yyyy-mm-dd'), 'D')) + (7 * (week-1)) as end_day
from weeks a;
Edit: These are the "convert" expressions you need to convert from week to date range. Note that 2017 and 39 are variable...
start date = to_date(2017 || '-01-04', 'yyyy-mm-dd') - to_number(to_char(to_date(2017 || '-01-04', 'yyyy-mm-dd'), 'D')) + 1 + (7 * (39-1))
end date = to_date(2017 || '-01-04', 'yyyy-mm-dd') + 7 - to_number(to_char(to_date(2017 || '-01-04', 'yyyy-mm-dd'), 'D')) + (7 * (39-1))
Upvotes: 4
Reputation: 59456
I use this function:
FUNCTION ISOWeekDate(WEEK INTEGER, YEAR INTEGER) RETURN DATE DETERMINISTIC IS
res DATE;
BEGIN
IF WEEK > 53 OR WEEK < 1 THEN
RAISE VALUE_ERROR;
END IF;
res := NEXT_DAY(TO_DATE( YEAR || '0104', 'YYYYMMDD' ) - 7, 'MONDAY') + ( WEEK - 1 ) * 7;
IF TO_CHAR(res, 'fmIYYY') = YEAR THEN
RETURN res;
ELSE
RAISE VALUE_ERROR;
END IF;
END ISOWeekDate;
Please note, according to my comment it is ambiguous if you only provide a week number without a year. The function returns the first day of given ISO Week.
Upvotes: 0
Reputation: 206
For the first and last week of year this query needs some CASE logic, but for other weeks works good. This solution use current NLS settings.
select to_char( start_of_week, 'day dd.mm.yyyy' ) start_of_week,
to_char( start_of_week + 6, 'day dd.mm.yyyy' ) end_of_week
from
(
select trunc( date '2017-01-01' + 38*7 , 'day') start_of_week
from dual
)
1) date '2017-01-01' - in what year we look for weeks or it may be trunc (sysdate, 'YEAR') to take first day of current year
2) date '2017-01-01' + 38*7 - jump to 38th week
3) trunc ( ... , 'day' ) - gives date of first day of the week
https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions201.htm https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions230.htm
Upvotes: 0
Reputation: 146219
"week no:1 date range is 01-01-2017 to 08-01-2017"
No it isn't. You're confusing 'IW'
(which runs MON - SUN) with 'WW'
which runs from the first day of the year:
SQL> with dts as (
2 select date '2017-01-01' + (level-1) as dt
3 from dual
4 connect by level <= 8
5 )
6 select dt
7 , to_char(dt, 'DY') as dy_dt
8 , to_char(dt, 'IW') as iw_dt
9 , to_char(dt, 'WW') as ww_dt
10 from dts
11 order by 1;
DT DY_DT IW WW
--------- ------------ -- --
01-JAN-17 SUN 52 01
02-JAN-17 MON 01 01
03-JAN-17 TUE 01 01
04-JAN-17 WED 01 01
05-JAN-17 THU 01 01
06-JAN-17 FRI 01 01
07-JAN-17 SAT 01 01
08-JAN-17 SUN 01 02
8 rows selected.
SQL>
However, it's easy enough to generate a range for the the IW week number. You need to multiple the IW number by 7 which you can convert to a date with the day of year mask. Then you can use next_day()
function to get the previous Monday and the next Sunday relative to that date:
SQL> with tgt as (
2 select to_date( &iw *7, 'DDD') as dt from dual
3 )
4 select next_day(dt-8, 'mon') as start_date
5 , next_day(dt, 'sun') as end_date
6* from tgt;
Enter value for iw: 23
old 2: select to_date( &iw *7, 'DDD') as dt from dual
new 2: select to_date( 23 *7, 'DDD') as dt from dual
START_DAT END_DATE
--------- ---------
05-JUN-17 11-JUN-17
SQL>
Obvious this solution uses my NLS Settings (English): you may need to tweak the solution if you use different settings.
Upvotes: 8