“9시 5분부터 10시 2분까지 몇 분?”을 시와 분으로 따로 빼면 받아내림 때문에 헷갈린다. 모든 시각을 “0시 0분부터 몇 분째”처럼 가장 작은 단위 하나로 바꾸면, 더하기·빼기·비교가 그냥 숫자 계산이 된다. 계산을 다 끝낸 뒤에만 “시:분” 모양으로 되돌린다. 되돌릴 때 5를 05로 두 자리 맞추는 것을 잊으면 틀린다.
예시로 보기
“09:05”부터 “10:02”까지 몇 분인지 구한다.
| 시각 | 분으로 바꾸기 | 값 |
|---|---|---|
| 09:05 | 9 × 60 + 5 | 545 |
| 10:02 | 10 × 60 + 2 | 602 |
602 − 545 = 57분이다. 시와 분을 따로 빼면 “1시간 −3분”이 나와서 받아내림을 해야 한다. 한 단위로 바꾸면 그럴 일이 없다.
바꾸기와 되돌리기
문자열 → 분. 자른 뒤 곱해서 더한다.
def to_min(t): # "09:05" → 545
h, m = map(int, t.split(":")) # map(int, …): 조각마다 int를 적용
return h * 60 + m
초까지 있으면 h * 3600 + m * 60 + s, 밀리초까지 있으면 한 번 더 1,000을 곱한다.
분 → 문자열. 60으로 나눈 몫이 시, 나머지가 분이다. divmod(a, b)는 (a // b, a % b)를 한 번에 돌려준다1.
def to_str(x): # 545 → "09:05"
h, m = divmod(x, 60)
return f"{h:02d}:{m:02d}" # 02d: 두 자리로, 모자라면 앞에 0
f"{h:02d}"의 02d는 “정수를 최소 두 자리로 쓰고, 모자란 자리는 0으로 채운다”는 뜻이다2. h = 9면 "09"가 된다.
flowchart LR
A["문자열 09:05"] -->|"split과 int"| B["시 9, 분 5"]
B -->|"9 × 60 + 5"| C["545분"]
C -->|"빼기, 더하기, 비교"| D["새 분 값"]
D -->|"divmod로 60씩 나누기"| E["시와 분"]
E -->|"두 자리로 맞추기"| F["문자열 HH:MM"]
계산은 가운데의 분 값에서만 한다. 왼쪽 두 화살표가 to_min, 오른쪽 두 화살표가 to_str이다3.
날짜. 날짜도 같은 생각이다. “모든 달이 28일”이라는 문제라면 날짜를 “첫날부터 며칠째”로 바꾼다.
def to_day(date): # "2022.05.19"
y, m, d = map(int, date.split("."))
return y * 12 * 28 + (m - 1) * 28 + d
달과 날이 1부터 시작하므로 m - 1을 곱한다. 실제 달력(달마다 날 수가 다름)이면 파이썬의 datetime.date로 날짜끼리 빼면 된다.
올림. “10분마다 요금” 같은 규칙에서 15분이면 2번을 매긴다. 나누어떨어지지 않으면 올리는 올림 나눗셈은 (a + b - 1) // b 또는 -(-a // b)다. math.ceil(a / b)도 되지만 큰 수에서 실수 오차가 생길 수 있어 정수 계산이 안전하다.
divmod, 02d, 28일 달력, 올림 나눗셈(1~500, 1~60의 모든 쌍에서 math.ceil과 일치)을 확인했다 — 07_time-conversion_verify.py활용
- 주차 요금, 영상 재생 위치, 방송 시간, 유효기간, 셔틀버스 시간표처럼 시각이 나오는 모든 문제에 쓴다.
- 자주 하는 실수:
- 되돌릴 때 두 자리를 맞추지 않아
"9:5"를 돌려준다. - 구간 끝을 넣을지 뺄지 헷갈린다. “~까지 보관 가능”과 “~부터 파기”처럼 문제가 어느 쪽을 포함하는지 먼저 적어 둔다.
- 문자열끼리 크기를 비교한다.
"09:05" < "10:02"는 두 자리가 맞으면 우연히 맞지만,"9:05" < "10:02"는 틀린다. 수로 바꿔서 비교한다.
- 되돌릴 때 두 자리를 맞추지 않아
연결
- 선수: 파이썬 기본 문법의 몫과 나머지, 수학적 바탕은 나눗셈과 합동
- 올림 나눗셈
(a + b - 1) // b가 맞는 까닭도 나눗셈 정리에서 나온다. \(a = bq + r\)(\(0 \le r < b\))이면 \(a + b - 1 = bq + (r + b - 1)\)이다. \(r = 0\)이면 \(r + b - 1 < b\)라 몫은 \(q\) 그대로다. \(r \ge 1\)이면 \(b \le r + b - 1 < 2b\)라 몫은 \(q + 1\)이다.
- 올림 나눗셈
- 연습: 개인정보 수집 유효기간, 동영상 재생기
h * 60 + m은 60진법 두 자리 수 (h, m)을 보통 수로 읽는 계산이다(진법과 자릿수).divmod(x, 60)은 거꾸로 그 수를 다시 두 자리로 나눈다. 28일 달력의to_day도 같은 모양이다. 날 자리는 28마다, 달 자리는 12마다 받아올린다.to_min과to_str는 서로 역함수다. 단, “09:05”처럼 두 자리로 맞추고 분이 60 미만인 문자열에서만 그렇다. “9:05”도 545가 되지만, 되돌리면 “09:05”가 되어 제자리로 오지 않는다.
확인 문제
C1 “23:40”부터 “00:15”(다음 날)까지는 몇 분인가? 하루를 넘는 경우를 분 단위로 어떻게 처리하는가?
답: 35분. “00:15”는 15분이지만 다음 날이라 24 × 60 = 1,440을 더해 1,455분이다. 1,455 − 1,420 = 35다. 차이가 음수로 나오면 하루(1,440분)를 더하면 된다.
C2 시와 분을 따로 계산하지 않고 전부 분으로 바꿔 계산하는 까닭은?
답: 시·분은 60마다 받아올림·받아내림이 생기는 두 자리 숫자다. 따로 계산하면 이 처리를 매번 직접 해야 해서 실수하기 쉽다. 분 하나로 바꾸면 보통 정수의 더하기·빼기·비교라서 받아올림이 저절로 처리되고, 마지막에 divmod로 한 번만 되돌리면 된다.
C3 h, m = divmod(125, 60) 다음 f"{h:02d}:{m:02d}"의 값은?
답: "02:05". 125 = 2 × 60 + 5라서 h = 2, m = 5다. 02d가 둘 다 두 자리로 맞춘다.