简体   繁体   中英

How do you get the correct ISO week number from a date using Oracle Sql

I have tried using the following piece of code to extract the correct iso weeknumber for this year, eg 07/01/2019 using the following code but it is still returning a week number that is a calendar rather than iso based, ie week 1 rather tha week 2. Bit stumped to be honest. NLS_TERRITORY set to UK if that makes any difference?

to_number(to_char(to_date(date_created,'DD/MM/YYYY'),'IW')) as WEEK_PRODUCED

Thanks in advance for any help provided.

This appears to be because of implicit date conversion - assuming that date_created is actually a DATE column not a string. If your NLS settings are set to show dates with 2-digit years, eg the still-default 'DD-Mon-RR' format, then your conversion of the date value to a string and back again is losing the century. As a demo, providing your date value via a CTE:

alter session set nls_date_format = 'DD-Mon-RR';

with your_table (date_created) as (
  select date '2019-01-07' from dual
)
select
  to_char(date_created) as nls_date,
  to_char(date_created, 'YYYY-MM-DD') as iso_date,
  to_char(to_date(to_char(date_created), 'DD/MM/YYYY'), 'YYYY-MM-DD') as conv_date,
  to_number(to_char(to_date(date_created,'DD/MM/YYYY'),'IW')) as WEEK_PRODUCED
from your_table;

NLS_DATE  ISO_DATE   CONV_DATE  WEEK_PRODUCED
--------- ---------- ---------- -------------
07-Jan-19 2019-01-07 0019-01-07             1

Notice that the conv_date , which has been converted to a string using the NLS 2-digit year model, and then back to a date using a 4-digit year model, has lost it's century; you seem the same with literals:

select to_char(to_date('01/07/19', 'DD/MM/YYYY'), 'YYYY-MM-DD') from dual;

TO_CHAR(TO
----------
0019-07-01

because 19 is, well, year 19; there's no hint or mechanism here to assume you meant this century. (That's what the RRRR format model is for.)

So, you're getting the ISO week number for January 7th in the year 19, not the year 2019, and in that year it was ISO week 1.

If your session had a 4-digit year model then it would work:

alter session set nls_date_format = 'DD/MM/YYYY';

with your_table (date_created) as (
  select date '2019-01-07' from dual
)
select
  to_char(date_created) as nls_date,
  to_char(date_created, 'YYYY-MM-DD') as iso_date,
  to_char(to_date(to_char(date_created), 'DD/MM/YYYY'), 'YYYY-MM-DD') as conv_date,
  to_number(to_char(to_date(date_created,'DD/MM/YYYY'),'IW')) as WEEK_PRODUCED
from your_table;

NLS_DATE   ISO_DATE   CONV_DATE  WEEK_PRODUCED
---------- ---------- ---------- -------------
07/01/2019 2019-01-07 2019-01-07             2

The implicitly-generated string now has a 4-digit year, so converting it back preserves the original century. (You'd still have issues with BCE dates, of course...)

But you shouldn't be converting the original date at all. Just do:

to_number(to_char(date_created,'IW')) as WEEK_PRODUCED

as in, with the same CTE:

with your_table (date_created) as (
  select date '2019-01-07' from dual
)
select
  to_number(to_char(date_created,'IW')) as WEEK_PRODUCED
from your_table;

WEEK_PRODUCED
-------------
            2

which will work whatever your NLS settings are, as there is no longer any implicit conversion going on.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM