오늘은 몇 주차
'주'란 무엇인가?
주란 과연 무엇일까요? 주에 대해 자세히 생각해보면 이런 저런 의문이 듭니다.
- 한 주의 시작은 월요일일까, 일요일일까?
- 365.25일을 7로 나누면 약 52.178이다. 즉 1년은 평균 52.178주이다?
- 올해(2022년)의 첫날은 토요일이다. 그렇다면 올해의 첫주는 1월 1일을 포함할까?
세상에는 혼돈을 줄이기 위하여 별에 별 것들에 대해 표준이 있습니다. 날짜와 시간과 관련된 데이터에 대한 국제 표준으로 ISO 8601이 있으며, 이에 대응하는 국내 표준으로 KS X ISO8601이 있습니다. 표준이력사항을 읽어보면 국내산업에서 개정의 요구가 없어 국제 표준과 동일한 내용으로 국내에 적용하고 있는 것을 확인할 수 있습니다.
해당 표준 내용을 정리하면 아래와 같습니다.
- 한 주는 7일로 이루어져있다.
- 한 주는 월요일로 시작하여 일요일로 끝난다.
- 1년은 52주 또는 53주이다. (즉 364일 또는 371일이다.)
- 1년의 첫번째 주는 해당 해의 첫번째 목요일이 포함된 주이다.
- 1년의 마지막 주는 해당 해의 마지막 목요일이 포함된 주이다.
- 주를 표현할 때에는 2018-W12 혹은 날짜를 포함하여 2018-W12-4처럼 한다. 이 경우 2018년의 13번째 주의 4번째 날이므로 2018년 03월 22일이 된다.
요약하면, 한 주의 시작은 월요일, 끝은 일요일이지만, 주차에 대한 판단 기준은 목요일에 있습니다.
예시를 들어보면 아래와 같다. 아래처럼 첫해의 첫 목요일이 포함된 주가 그 해의 첫번째 주가 됩니다.
Week | Mon | Tue | Wed | Thu | Fri | Sat | Sun |
---|---|---|---|---|---|---|---|
W01 | 01 | 02 | 03 | 04 | 05 | 06 | 07 |
만약 첫 목요일이 아래와 같이 되어 있다면 해당 연도의 1월 1일부터 1월 3일은 그 해의 첫주가 아니라, 그 전 해의 마지막 주가 됩니다.
Week | Mon | Tue | Wed | Thu | Fri | Sat | Sun |
---|---|---|---|---|---|---|---|
W53 | 01 | 02 | 03 | ||||
W01 | 04 | 05 | 06 | 07 | 08 | 09 | 10 |
Week Number 계산하기
주차를 직접 계산해봅시다. 깔끔하게 week_number(date: Date) -> i32
같은 함수가 나오는 것이 목표입니다. 주차란 올해의 첫번째 주로부터 몇 주가 지났는지를 의미합니다. 오늘이 올해의 몇 번째 날인지만 알면 7로 나누어 알아낼 수 있습니다. 오늘이 올해의 몇번째 날인지를 라고 하겠습니다. 이는 컴퓨터로는 오늘에서 1월 1일을 빼면 알 수 있고, 손으로는 오늘 날짜와 지나간 월들의 날을 모두 합하여 알아낼 수 있습니다.
가장 간단하게 1월 1일이 월요일인 해를 가정해봅시다. 다음은 해당 해의 첫주이므로 부터 까지의 값이 1로 같아야합니다.
Week | Mon | Tue | Wed | Thu | Fri | Sat | Sun |
---|---|---|---|---|---|---|---|
W01 | 01 | 02 | 03 | 04 | 05 | 06 | 07 |
다음과 같이 6을 더하고 버림 함수를 사용하면 이 구간에서는 의도한 대로 나옵니다.
다른 예시를 살펴봅시다. 1일이 작년으로 넘어가면 올바른 결과가 나오지 않습니다. 해가 금요일부터 시작하여 1월 1일이 W01이 아닌 예를 봅시다.
Week | Mon | Tue | Wed | Thu | Fri | Sat | Sun |
---|---|---|---|---|---|---|---|
W53 | 01 | 02 | 03 | ||||
W01 | 04 | 05 | 06 | 07 | 08 | 09 | 10 |
, 이 되어야 하지만, 위의 식을 적용하면, 둘 다 1이 되어버립니다.
주의 시작이 월~목일 때와 이를 넘어갈 때를 구분할 방법이 필요하다. 오늘 날짜에서 요일을 빼면 가능할 것 같다. ISO 8601에 요일을 수로 표현할 때는 월요일을 1로, 일요일을 7로 하여 나열한다고 나와있다. (이를 week day라고 한다.) 이렇게 하면 같은 주의 의 값은 일정해진다.
값을 명확히 보기 위해 바닥함수는 제외하고 wN = (date) => (ordinal(date) - weekday(date) + 6) / 7
이라고 하자. 1월 1일이 월요일일 때와 금요일일 때의 wN
값을 확인해보자
Week | Mon | Tue | Wed | Thu | Fri | Sat | Sun |
---|---|---|---|---|---|---|---|
요일 | 01 | 02 | 03 | 04 | 05 | 06 | 07 |
W01 | 01 | 02 | 03 | 04 | 05 | 06 | 07 |
wN | 0.86 | 0.86 | 0.86 | 0.86 | 0.86 | 0.86 | 0.86 |
W53 | 01 | 02 | 03 | ||||
wN | 0.29 | 0.29 | 0.29 | ||||
W01 | 04 | 05 | 06 | 07 | 08 | 09 | 10 |
wN | 1.29 | 1.29 | 1.29 | 1.29 | 1.29 | 1.29 | 1.29 |
wN
이 1보다 작은 경우는 전년도의 마지막 주로 처리하면 깔끔할 것 같다. 그런데 1월 1일이 월요일일 경우 wN
이 1.0을 넘지 않는다. 위에서 주었던 보정값 +6
대신 다른 상수를 더해서 해결해보자.