티스토리 뷰

informix

주차 (Week number) 계산하기

pajama 2021. 8. 25. 17:30
반응형

안녕하세요. Informix에는 연도별 주차를 계산하는 기능이 없어서 찾아보다가 다른 코드를 보고 따라서 만들어 보았습니다. 주차에 대한 개념이 없다보니 커뮤니티와 블로그, 위키 자료들을 참고했는데요. 일반적으로 쓰이는 형태가 ISO 8601 표준이라고 합니다.

ISO 8601에 따르면 1주차에 대한 정의는 아래와 같습니다.

  • 시작 연도의 첫 번째 목요일이 포함된 주
  • 1월 4일이 있는 주
  • 시작 연도에 일의 대부분(4일 이상)이 있는 첫 번째 주
  • 12월 29일 - 1월 4일 기간의 월요일로 시작하는 주

아래와 같이 다양한 DBMS에서 함수를 사용하여 특정일자에 대한 주차를 구할 수 있습니다만.. Informix는 자체 기능이 제공되지 않아서 아쉽군요.

DBMS 제공함수 사용예시
Oracle TO_CHAR TO_CHAR(DATE '2021-08-25' , 'IW')
Db2 TO_CHAR TO_CHAR(DATE '2021-08-25' , 'IW')
MySQL WEEK WEEK('2021-08-25', 3);
MariaDB WEEK WEEK('2021-08-25', 3);
SQL Server DATEPART DATEPART(ISOWK,'2021-08-25')
PostgreSQL DATE_PART / EXTRACT DATE_PART('WEEK', '2021-08-25'::DATE)
EXTRACT('WEEK' FROM '2021-08-25'::DATE)
Sybase DATEPART DATEPART(CWK, '8/25/2021')

Informix에는 기본 내장된 함수가 없기 때문에 계산 방식에 대해서 조사를 했습니다.

위에서 상술된 조건을 만족해야하고, Informix에서 datetime 을 일자로 변환하여 계산하는 등의 몇가지 시행착오가 있었습니다.

create function weeknum ( dt varchar(10) )
returning int;

define wknum int;
select trunc(((to_date(dt, '%Y-%m-%d') - yearstart)::interval day(3) to day::varchar(12)::integer) / 7) + 1
into wknum
from
(
select case when nextyr <= to_date(dt, '%Y-%m-%d') then nextyr
            when curryr <= to_date(dt, '%Y-%m-%d') then curryr
            else prioryr 
       end yearstart
from 
(
select  
        mdy(1,1,1753) + trunc(((jan4 - 1 units year - mdy(1,1,1900) + 53690 units day)::varchar(12)::integer) / 7) * 7  units day prioryr,
        mdy(1,1,1753) + trunc(((jan4                - mdy(1,1,1900) + 53690 units day)::varchar(12)::integer) / 7) * 7  units day curryr,
        mdy(1,1,1753) + trunc(((jan4 + 1 units year - mdy(1,1,1900) + 53690 units day)::varchar(12)::integer) / 7) * 7  units day nextyr
from (
select mdy(1,1,1900) + (extend (to_date(dt, '%Y-%m-%d'), year to year) - mdy (1,1,1900))::varchar(12)::integer units year + 3 units day jan4 from dual
)
)
);
return wknum;
end function;

 

아래와 같은 방식으로 Informix에서 특정 일자에 대한 주차를 구할 수 있습니다. 위 함수를 수정하면 쿼리형태로도 사용 가능할 것 같습니다.

> select weeknum ('2021-08-25') from sysmaster:sysdual;


(expression)

          34

 

https://en.wikipedia.org/wiki/ISO_8601

https://en.wikipedia.org/wiki/ISO_week_date

https://www.toolbox.com/tech/oracle/question/how-the-week-number-is-being-derived-121815/

https://www.sqlteam.com/forums/topic.asp?TOPIC_ID=60515 

http://www.whitemiceconsulting.com/informixintervaltips201609

https://www.sqlservercentral.com/articles/a-simple-formula-to-calculate-the-iso-week-number

https://4js.com/online_documentation/fjs-fgl-3.00.05-manual-html/c_fgl_odiagmsv_005.html

 

** 2025/02/13 추가

Perplexity가 제안한 코드입니다. 전보다 가독성도 좋고 기능도 잘 동작하네요. 잘 만들어 줘서 편하긴 한데 블로그나 공개된 기술 문서가 검색이 안되어도 이정도 결과물을 만들어 줄지는 의문입니다.

CREATE FUNCTION weeknum (dt VARCHAR(10)) 
RETURNING INT;
DEFINE dt_date DATE;
DEFINE jan4 DATE;
DEFINE year_start DATE;

-- 날짜 형식 변환 및 기준일 계산
LET dt_date = TO_DATE(dt, '%Y-%m-%d');
LET jan4 = MDY(1,4,YEAR(dt_date)); -- 해당 연도 1월 4일

-- 주 시작일 계산(ISO 기준 월요일 찾기)
LET year_start = jan4 - (WEEKDAY(jan4)-1) UNITS DAY;
IF WEEKDAY(jan4) = 0 THEN  -- 1월 4일이 일요일인 경우
    LET year_start = year_start + 1 UNITS DAY;
END IF;

-- 주 번호 계산
IF dt_date < year_start THEN
    RETURN weeknum(TO_CHAR(year_start-1 UNITS YEAR,'%Y-%m-%d'));
ELSE
    RETURN ((dt_date - year_start) / 7) + 1;
END IF;
END FUNCTION;

 

특정 날짜가 해당 월의 몇번째 주인지 구하는 함수도 아래와 같이 만들어 주네요. 이젠 요구사항을 얼마나 잘 정리하고 검증하는지가 더 중요해진 것 같습니다.

CREATE FUNCTION week_of_month(d DATE)
RETURNING INT;
DEFINE first_day DATE;
DEFINE wd INT;
DEFINE days_to_add INT;
DEFINE start_week1_sunday DATE;
DEFINE week_num INT;

-- 월의 첫 날 계산
LET first_day = MDY(MONTH(d), 1, YEAR(d));
-- 첫 날의 요일(0:일요일~6:토요일)
LET wd = WEEKDAY(first_day);

IF wd = 0 THEN
    -- 첫 날이 일요일인 경우
    LET week_num = ((d - first_day) / 7) + 1;
ELSE
    -- 첫 번째 일요일 계산
    LET days_to_add = MOD(7 - wd, 7);
    LET start_week1_sunday = first_day + days_to_add UNITS DAY;
    
    IF d < start_week1_sunday THEN
        -- 첫 주 처리(월초~첫 일요일 전날)
        LET week_num = 1;
    ELSE
        -- 주차 계산(첫 일요일 이후)
        LET week_num = ((d - start_week1_sunday) / 7) + 2;
    END IF;
END IF;

RETURN week_num;
END FUNCTION;

 

반응형
댓글