달력을 출력하는 알고리즘

달력 알고리즘

심플한 달력 프로그램을 만드려고 고민하는 도중, 최소한 달력을 자동으로 출력해서 토요일과 일요일은 다른색으로 표시하는 기능을 만들어 보려고했다. 하지만 딱히 달력이라는 개념에 대해서 생각하며 살아온 건 아니었기 때문에 기능을 구현하다가 막히게 되었다.

처음에는 시스템의 요일과 해당 일(3월 2일 금)을 가져와서 1일의 요일을 찾아가는 방식을 사용하려고 했지만 이미 만들어진 기능으로 사용하는게 못마땅했고 어떻게 만들어진지 모르는 상태에서 해당 일이 30일인 경우 뭔가 불안한 느낌이 들었기 때문에 좀 더 기초적인 방법으로 접근하고자 하였다.


매월 1일의 요일

달력의 기초는 1년 1월 1일이 월요일 이라는 설정이다.

1년 1월 7일이 일요일이 될 것이라는 가정하에

1%7 == 1(월요일) ㅡ 7%7 == 0(일요일) 이므로

case 0 : '일요일' case 1 : '월요일'... case 6 : '토요일'이 된다.

따라서 1월 1일부터 지금까지의 모든 일 수를 구하여 7로 나눈 나머지가 요일이 된다. 매월 1일이든 현재의 일이든 간단하게 요일을 구할 수 있다. 하지만 윤년이라는 걸림돌을 고려해야 한다.


윤년

if(Year%4==0 && Year%100!=0 || Year%400==0)
{
    printf("윤년입니다.");
}

프로그래밍에 가장 기초적인 단계에서 나오는 윤년 구하기, 이 식을 활용하면 생각보다 간단하게 구현할 수 있다, 윤년은 365일 보다 하루가 더 많은 366일이다. 이번해가 2018년이고 2017년 까지의 모든 일 수를 구하면

2017*365 + {(2017/4 - 2017/100) + 2017/400}

= 736,205 + 504 - 20 + 5 = 736,694

4로 나누어지는 윤년이었던 해의 일 수를 더해주고 100으로 나누어지는 해의 일 수를 빼주고 400으로 나누어지는 윤년의 일 수를 더해준다. 이번 해는 2018년이고 윤년이 아니므로, 현재 2018년 3월 2일 기준

736,694 + 31 + 28 + 1 = 736,754

736,754 % 7 == 4 이므로 목요일

3월 1일은 목요일부터 시작이다.


이번 달의 일 수

switch (month)
{
    case 1:
        day = 31;
        break;
    case 2:
        day = 28;
        if(year%4==0 && year%100!=0 || year%400==0)
            day++;
        break;
    case 3:
        day = 31;
        break;
    case 4:
        day = 30;
        break;
    case 5:
        day = 31;
        break;
    case 6:
        day = 30;
        break;
    case 7:
        day = 31;
        break;
    case 8:
        day = 31;
        break;
    case 9:
        day = 30;
        break;
    case 10:
        day = 31;
        break;
    case 11:
        day = 30;
        break;
    case 12:
        day = 31;
        break;
}

매 월 일수는 윤년을 제외하면 모두 일정하다. case를 반대로 뒤집고 break를 빼면 좀 더 수월하게 매 월 1일의 요일을 구할 수 있다.

아래는 파이썬으로 구현한 알고리즘이다.

def get_month_day(year, month):
    if month == 4 or month == 6 or month == 9 or month == 11:
        return 30
    elif month == 2:
        if year % 4 == 0 and year % 100 != 0 or year % 400 == 0:
            return 29
        else:
            return 28
    else:
        return 31

def get_total_day(year, month, day):
    year_days = (year-1)*365 + ((int((year-1)/4) - int((year-1)/100)) + int((year-1)/400))

    month_days = 0
    for i in range(1, month):
        month_days += get_month_day(year, i)

    return year_days + month_days + day

def get_weekday(day):
    day %= 7
    if day == 0:
        return 'SUN'
    if day == 1:
        return 'MON'
    if day == 2:
        return 'TUE'
    if day == 3:
        return 'WED'
    if day == 4:
        return 'THU'
    if day == 5:
        return 'FRI'
    if day == 6:
        return 'SAT'

print(get_weekday(get_total_day(2020, 1, 30)))

이 글이 도움이 되었나요?

신고하기
0분 전
작성된 댓글이 없습니다. 첫 댓글을 달아보세요!
    댓글을 작성하려면 로그인이 필요합니다.