날짜 차이 계산 알고리즘 - naljja chai gyesan algolijeum

날짜 구하기

문제

우리 천일 후에 만나자!
사랑했던 그녀가 그렇게 말하고 던전 속으로 사라져 버렸다. 홀로 남은 나는 생각했다. 어디 보자, 천일 후면 날짜가...

  • 문제의 정의
    년, 월, 일이 주어졌을 때, n일 이후의 날짜를 계산하라!

  • 문제의 분석

    • 1달은 28일, 29일(윤년), 30일, 31일 중의 하나다.
    • [1,3,5,7,8,10,12월]은 31일, [4,6,9,11월]은 30일, 2월은 28일 또는 29일(윤년)
    • 1년은 365일이기도 하고 366일이기도 하다.(윤년)
    • 윤년은 연도가 4의 배수이면서, 100의 배수가 아닐 때 또는 400의 배수일 때이다.
    • 즉, 날짜를 받아 날짜가 해당 월의 마지막 날을 넘었는 지 확인하고, 윤년인지 확인하고, n일 이후의 날짜를 계산한다.

윤년 확인 함수

def leapyear(y):
    if (y % 4 == 0 and y % 100 != 0) or y % 400 == 0:   # 연도가 4의 배수이면서, 100의 배수가 아닐 때 또는 400의 배수일 때
        return True
    
    else:
        return False

해당 월의 날짜 확인 함수

def invalidDay(y, m, d):    # 해당 월의 마지막 날을 넘겼는지 확인
    days = 31    # 마지막 날이 31일 까지인 월이 가장 많다.
    
    if m in [4, 6, 9, 11]:   # 마지막 날이 30인 월
        days = 30
        
    if m == 2:               # 2월인지 확인
        if leapyear(y):      # 윤년 확인
            days = 29
        else:
            days = 28
            
    if d > days:             # 받은 날이 해당 월의 마지막 날보다 큰 지 확인
        return True
    else:
        return False

n일 후의 날짜 구하기

# n일 후의 날짜 구하기
year = 2021
month = 5
day = 13
n = 1000

for _ in range(n):
    day += 1       # n일 후의 날 까지 하루씩 추가   
    
    if invalidDay(year, month, day):   # 하루씩 추가 된 날이 해당 월의 마지막 날을 넘었는지 확인
        day = 1                        # 추가된 날짜가 해당 월의 마지막 날을 넘으면 일을 1일로 변경하고 월 추가
        month += 1         
        
        if month > 12:     # 월이 12월을 넘으면 다시 1월로 변경하고 년도를 추가
            month = 1
            year += 1
            
print(year, month, day)

** datetime 패키지를 사용하면 훨씬 간단하게 n일 후의 날짜를 구할 수 있다.

import datetime

year = 2021
month = 5
day = 13
n = 1000

day = datetime.date(year, month, day)
theday = day + datetime.timedelta(n)

print(theday)

** 출처

  • 주니온TV 아무거나연구소 - 코린아, 코딩하자 (with 파이썬)

일단 방식은 시작일부터 종료일까지 하루씩 세는 방식입니다. 계산할 일자의 범위와 사용하는 달력이 정해지지 않은 부분이 좀 애매하네요. 일단 그레고리력으로 계산했고, 그레고리력에서 윤년은

  • 4로 나눠지는 해는 윤년
  • 근데 100으로 나눠지면 윤년아님
  • 그럼에도 400으로 나눠지면 또 윤년임

으로 계산합니다.

그런데, 그레고리력으로 계산하는 경우 1582년 10월 5일 ~ 1582년 10월 14일의 10일은 그레고리력상 없는 날짜이기 때문에 이 부분에 대한 보정을 넣어봤습니다.

파이썬입니다.

days1 = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
days2 = (31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)

def leap(y):
    if y % 400 == 0:
        return True
    if y % 100 == 0:
        return False
    if y % 4 == 0:
        return True
    return False

def nextday(data):
    y, m, d = (int(x) for x in (data[:4], data[4:6], data[6:]))
    if y == 1582 and m == 10 and d == 4:
        d += 11
    else:
        d += 1

    md = days2 if leap(y) else days1
    if d == md[m - 1] + 1:
        d = 1
        m += 1
        if m == 13:
            m = 1
            y += 1

    return ''.join(("{:02d}".format(x) for x in (y, m, d)))

def do(xs):
    s, e = sorted(xs.split()[:2])
    d = 0
    while e != s:
        s = nextday(s)
        d += 1
    return "{} sub {} => {}".format(e, s, d)

samples =\
"""20070501 20070515
20070301 20070515""".split('\n')
for v in samples:
    print(do(v))

```