[Key word] 날짜수, 요일, 윤년과 평년
파이썬 실습창을 열 수 있습니다.실습창 열기
달력 만들기
2024년 6월의 달력입니다.
연도와 달을 입력받아서 달력을 만들어 봅시다.
1. 프로그램 구상
한 달의 달력을 한 줄에 적어놓고 7일 단위로 줄을 바꾸어 출력하면 어떨까요?
개략적인 구상은 다음과 같습니다.
- 한 달은 최대 6주에 걸쳐 있습니다(위의 2024년 6월 달력 참조) 또한 일주일은 7일입니다.
그러므로 42열(=6주*7일)의 리스트를 준비합니다. - 그 달의 첫째 날(1일) 요일을 구해서 요일에 맞는 열부터 그 달의 날짜 수만큼 적습니다.
첫번째 열은 일요일로 생각합니다. - 리스트를 7열씩 줄을 바꾸어 출력합니다.
다음은 2024년 6월의 달력 리스트입니다(인덱스 0부터 41까지).
. | . | . | . | . | . | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ~ | 28 | 29 | 30 | . | . | . | . | . | . |
2. 입력
달력을 만들려면 반드시 알아야 하는 입력 정보는 무엇입니까?
입력 정보를 코딩하세요.
y,m=2024,6 # 임의의 연도와 월입니다. 변수 이름은 마음대로
3. 준비
이제 무엇을 할까요?
해야할 일을 생각나는 대로 코딩하여 보세요.
빠지거나 고쳐야할 부분은 다음에 수정하면 됩니다.
md=[31,28,31,30,31,30,31,31,30,31,30,31] # 각 달의 날짜 수
cal=[0]*42 # 42열의 리스트. cal은 임의의 변수, 초기값은 마음대로
y,m=2024,6
'''
나는 각 달의 날짜 수와 42열이 있는 리스트가 필요하다고 생각했습니다.
'''
4. 윤평판단
이제 2월의 날짜 수를 조정해야할 것 같습니다.
입력 연도가 윤년이면 29일, 평년이면 28일입니다.
윤평을 판단하여 2월의 날짜 수를 조정하여 보세요.
다음의 벤다이어그램이 생각나십니까?
md=[31,28,31,30,31,30,31,31,30,31,30,31] # 각 달의 날짜 수
cal=[0]*42 # 42열의 리스트. 초기값은 마음대로
y,m=2024,6
md[1]+=(y%4==0 and y%100!=0) or (y%400==0)
'''
윤년은 (4의 배수이고 100의 배수가 아니거나) 혹은 (400의 배수)인 경우입니다.
참이면(윤년이면) True, 아니면(평년이면) False.
True는 1과 같으므로 2월에 1을 더하고, 아니면 0을 더합니다(False는 0과 같음).
'''
5. 요일 구하기
y년 m월 1일(첫째 날)의 요일을 구할 차례입니다.
요일을 어떻게 구하지요?
서기 1년 1월 1일부터 y년 m월 1일까지의 날짜 수를 정확히 안다면 요일은 7일마다 반복되므로 날짜수를 7로 나눈 나머지로서 요일을 구할 수 있을 것 같습니다.
● 서기 1년 1월 1일부터 y년 m월 1일까지의 날짜 수를 구하여 봅시다.
- 서기 1년 1월 1일부터 지난해 말(y-1년 12월 31일)까지의 날짜를 구한다(그림의 1 부분)
- 서기 1년 1월 1일부터 지난해 말까지는 (y-1)년이다. 1년을 365일로 생각한다.
day=(y-1)*365
- 4년마다 윤년이 있다고 생각하고 윤년의 수만큼 날짜를 더한다.
day=(y-1)*365+(y-1)//4
- 너무 많이 더했다. 100년에 한번씩 평년이다.
day=(y-1)*365+(y-1)//4 - (y-1)//100
- 너무 많이 뺐다. 400년에 한번은 윤년이다.
day=(y-1)*365+(y-1)//4 - (y-1)//100 + y//400
- 정리하자. (y-1)이 많이 사용되므로 (y-1)을 t로 두자.
t=y-1
day=t*365+t//4-t//100+t//400 - 올해 1월 1일부터 지난달 말(m-1월 마지막 날) 까지의 날짜를 구한다(그림의 2 부분)
sum(md[:m-1]) - 이번 달(y년 m월) 1일까지이므로 1을 더한다(그림 3부분)
- 위의 3가지를 모두 더하면 된다.
t=y-1
day=t*365+t//4-t//100+t//400+sum(md[:m-1])+1
day는 서기 1년 1월 1일부터 y년 m월 1일까지의 정확한 날짜 수이다.
● 요일을 구합시다.
1년 1월 1일은 월요일입니다.
1582년에 교황 그레고리오 13세가 이 역법을 시행할 때 그렇게 정하였습니다.
날짜 | 1년 1월 1일 |
2일 | 3일 | 4일 | 5일 | 6일 | 7일 | 8일 | ..... |
요일 | 월요알 | 화요일 | 수요일 | 목요일 | 금요일 | 토요일 | 일요일 | 월요일 | ..... |
날짜를 7로 나눈 나머지가 0이면 일요일, 1이면 월요일, ..., 6이면 토요일인 것을 알 수 있습니다.
그러므로 y년 m월 1일의 요일은 wd=day % 7 입니다 (wd는 요일을 의미하는 임의의 변수).
여기서 잠깐!
날짜의 수를 구할 때, day=t*365가 있었습니다.
365=52*7+1 입니다.
그러므로 day=t*(52*7+1)
=t*52*7 + t
요일은 day를 7로 나문 나머지를 구합니다.
그런데 t*52*7은 7의 배수이므로 이 부분을 제거하여도 7로 나눈 나머지는 똑 같습니다.
t=y-1
day=t+t//4-t//100+t//400+sum(md[:m-1])+1
wd=day%7
그러므로 위와 같이 t에 365를 곱하지 않아도 됩니다.
● 요일 확인
요일이 정확하게 출력되는지 확인하여 봅시다.
연도와 월을 바꾸어 가면서 인터넷에서 찾은 달력 요일과 비교하여 보세요.
md=[31,28,31,30,31,30,31,31,30,31,30,31] # 각 달의 날짜 수
cal=0]*42 # 42열의 리스트. 초기값은 마음대로
y,m=2024,6
md[1]+=(y%4==0 and y%100!=0) or (y%400==0)
t=y-1
day=t+t//4-t//100+t//400+sum(md[:m-1])+1
wd=day%7
print(wd)
'''
y년 m월 1일의 요일이 바르게 출력됩니까?
'''
6. 리스트에 달력 기록
리스트에 달력의 날짜를 넣어봅시다.
md=[31,28,31,30,31,30,31,31,30,31,30,31] # 각 달의 날짜 수
cal=[0]*42 # 42열의 리스트. 초기값은 마음대로
y,m=2024,6
md[1]+=(y%4==0 and y%100!=0) or (y%400==0)
t=y-1
day=t+t//4-t//100+t//400+sum(md[:m-1])+1
wd=day%7
for i in range(md[m-1]): # m월의 날짜 수는 인덱스 (m-1)에 있음
cal[i+wd]=i+1 # 날짜(i+1)를 리스트에 기록
print(cal)
'''
출력 결과입니다.
[0, 0, 0, 0, 0, 0, 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, 29, 30, 0, 0, 0, 0, 0, 0]
i는 0부터 시작하므로 1을 더하여 기록합니다.
리스트의 기록 위치는 i에 요일(wd)를 더한 곳입니다.
(분석하여 이해하세요)
'''
7. 달력의 출력
● 일주일씩 출력
cal 리스트를 7열씩 출력하려고 합니다.
0~6, 7~13, 14~20 등으로 나누어 출력하면 됩니다.
md=[31,28,31,30,31,30,31,31,30,31,30,31] # 각 달의 날짜 수
cal=[0]*42 # 42열의 리스트. 초기값은 마음대로
y,m=2024,6
md[1]+=(y%4==0 and y%100!=0) or (y%400==0)
t=y-1
day=t+t//4-t//100+t//400+sum(md[:m-1])+1
wd=day%7
for i in range(md[m-1]):
cal[i+wd]=i+1
for i in range(0,42,7): # 이곳 추가
print(cal[i:i+7])
'''
출력입니다.
[0, 0, 0, 0, 0, 0, 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, 29]
[30, 0, 0, 0, 0, 0, 0]
'''
● 줄을 맞추어 출력
md=[31,28,31,30,31,30,31,31,30,31,30,31] # 각 달의 날짜 수
cal=[0]*42 # 42열의 리스트. 초기값은 마음대로
y,m=2024,6
md[1]+=(y%4==0 and y%100!=0) or (y%400==0)
t=y-1
day=t+t//4-t//100+t//400+sum(md[:m-1])+1
wd=day%7
for i in range(md[m-1]):
cal[i+wd]=i+1
for i in range(0,42,7):
for j in cal[i:i+7]:
print(f'{j:4}',end='')
print()
'''
0 0 0 0 0 0 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 29
30 0 0 0 0 0 0
'''
8. 완전한 출력
연도와 월 그리고 요일도 넣어 봅시다.
날짜의 0대신에 점으로 바꾸겠습니다.
week=' Sun Mon Tue Wed Thu Fri Sat' # 요일 준비
md=[31,28,31,30,31,30,31,31,30,31,30,31]
cal=['.']*42 # 0을 점(dot)으로 수정
y,m=2024,6
md[1]+=(y%4==0 and y%100!=0) or (y%400==0)
t=y-1
day=t+t//4-t//100+t//400+sum(md[:m-1])+1
wd=day%7
for i in range(md[m-1]):
cal[i+wd]=i+1
print(f' {y}년 {m}월') # 년과 월, 연도 앞에 한 칸 띄움
print(week) # 요일 출력
print('-'*28) # '-' 28개
for i in range(0,42,7):
for j in cal[i:i+7]:
print(f'{j:>4}',end='') # 오른쪽 정렬(점을 오른쪽으로)
print()
'''
2024년 6월
Sun Mon Tue Wed Thu Fri Sat
----------------------------
. . . . . . 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 29
30 . . . . . .
'''
프로그램을 작성하는 일련의 과정을 함께하였습니다.
즐거운 시간이 되었기를 바랍니다.
수고하셨습니다.
안녕!
'알고리듬' 카테고리의 다른 글
[알고리듬] #74 선택 정렬 (0) | 2024.04.27 |
---|---|
[알고리듬] #73 버블 정렬 (0) | 2024.04.27 |
[알고리듬] #70 3N+1 문제(1) (1) | 2024.04.26 |
[알고리듬] #69 소수 찾기 (0) | 2024.04.24 |
[알고리듬] #68 n개의 열린 문 (0) | 2024.04.22 |