티스토리 뷰

수영 기록을 위해 해당 월에 대한 주(weekOfMonth)를 알아야 했다.

calendar Table DDL

그러기 위해 날짜와 주를 가지는 Calendar 테이블을 생성하였다.

create table calendar
(
    id         int auto_increment
        primary key,
    date       date                                not null comment '날짜(YYYY-MM-DD)',
    week       int                                 not null comment '해당 달의 주차',
    created_at timestamp default CURRENT_TIMESTAMP not null
)
    comment '달력 테이블';

위 테이블에 마이그레이션을 위해 python script를 작성하였다.

규칙

해당 월에 주를 구하기 위해서는 다음과 같은 규칙을 알아야 한다.

  1. 주의 시작은 일요일이 아닌 월요일이다.
  2. 두 개의 월이 겹치는 월초, 월말에서의 주를 구하는 규칙은 다음과 같다.
    1. 7일 중 더 많은 일수를 가지는 월에 맞춘다.
    2. 즉, 4/27(월), 4/28(화), 4/29(수), 4/30(목), 5/1(금), 5/2(토), 5/3(일) 같은 경우 4월에 마지막 주로 인식한다

코드

위 규칙을 염두하여 다음 코드를 살펴보자.

from datetime import datetime
from datetime import timedelta
import datetime;
import calendar
import numpy as np

last_day_of_month = [31,28,31,30,31,30,31,31,30,31,30,31]
leap_year_last_day_of_month = [31,29,31,30,31,30,31,31,30,31,30,31]

def get_week_of_month(year, month, day):
    x = np.array(calendar.monthcalendar(year, month))
    week_of_month = np.where(x==day)[0][0] + 1
    first_day_of_month = datetime.date(year,month,1).weekday()
    flag = 0
    if first_day_of_month > 3:
        flag = 1
    week_of_month -= flag
    if week_of_month == 0:
        day_of_week = datetime.date(year,month,day).weekday()
        if day_of_week > 3: # 목요일
            if month == 1:
                year -= 1
                month = 12
            else:
                month -= 1
            if year %4 == 0:
                day = leap_year_last_day_of_month[month - 1]
            else:
                day = last_day_of_month[month - 1]

            x = np.array(calendar.monthcalendar(year, month))
            week_of_month = np.where(x==day)[0][0] + 1
            if datetime.date(year,month,1).weekday() > 3:
                week_of_month -= 1
        else:
            week_of_month = 1
    elif week_of_month == 5:

        if month == 12:
            year += 1
            month = 1
        else: 
            month += 1
        day = 1
        day_of_week = datetime.date(year,month,day).weekday()

        if day_of_week <= 3: # 목요일
            week_of_month = 1 
    return(week_of_month)

def worker():
    date = datetime.date(2022, 1, 1)
    while date != datetime.date(2023,1,1):
        year = date.year
        month = date.month
        day = date.day
        week = get_week_of_month(year,month,day)
        print(date)
        print(week)
        date = date + timedelta(days=1)


worker()

위 언급한 규칙 외에도 윤년인지 아닌지와 월초, 월말에 어떠한 월을 따를지에 대한 로직이 추가되어 있다.

 

테스트는 2021년부터 2024년까지 했는데 혹시라도 버그가 생기면 댓글 부탁드립니다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함