은행 현장의 언어 · 타임존·영업일·마감시각 · 실습
결제일을 계산하는 엔진 만들기
목표
접수 순간과 달력 날짜를 갈라 놓고, 휴장일 달력과 마감시각으로 결제일을 계산하는 엔진을 만든다. 상대 기관의 표준시와 1987·1988년 서울의 서머타임 구간까지 맞게 다루고, 잘못 매겨진 결제일을 원장을 덮어쓰지 않고 전 건 재계산한다.
왜 중요한가
순간은 하나지만 그 순간이 며칠인지는 표준시를 정해야 답이 나온다. 은행에서는 여기에 마감시각과 영업일 달력이 더 붙어서, 돈이 실제로 오가는 날짜는 저장된 사실이 아니라 규칙의 산출물이 된다. 이 계산이 코드 여러 곳에 흩어지면 "어제 거래" 의 정의가 시스템마다 달라지고, 그 어긋남은 장애로 보이지 않아 정산 대사까지 살아남는다.
휴장일과 마감시각은 해마다 바뀌므로 코드가 아니라 데이터에 둔다. 그래서 이 실습의 엔진은 달력과 설정을 --db 로 받은 SQLite 에서 읽는다.
채점기는 여러분이 적어 낸 문구를 믿지 않는다. 자기가 만든 휴장일 달력과 마감시각을 담은 임시 DB 를 물려 여러분의 엔진을 실행하고, 판정을 자기가 계산한 값과 대조한다. 답을 박아 넣은 엔진은 통과하지 못한다.
단계
1. /root/bizday/gen_bizday.py 를 만들어 실행해 /root/bizday/txn.db 를 만든다. 이체 접수 300건, 이관 거래 48건, 휴장일 6일, 설정 3줄이 들어간다.
2. UTC 날짜와 KST 날짜가 갈라지는 거래를 /root/bizday/kst_shift.csv 에, 세 숫자를 /root/bizday/bucket.txt 에 적는다.
3. /root/bizday/bizday.py 에 is-bizday, next-bizday, add-bizdays 를 구현한다. 달력은 --db 의 holiday 표에서 읽는다.
4. bizday.py 에 value-date 를 더한다. 마감시각과 표준시는 sys_param 에서 읽는다.
5. bizday.py 에 localize 를 더하고, 서울과 런던에서 날짜가 갈라지는 거래를 /root/bizday/counterparty.csv 에 적는다.
6. 이관 거래 48건을 /root/bizday/legacy_offsets.csv 에 지역시각과 오프셋까지 적고, 세 숫자를 /root/bizday/dst_seoul.txt 에 적는다.
7. 원장의 value_date 를 덮어쓰지 말고 txn.db 에 value_date 표를 만들어 300건을 재계산하고, 바뀌는 거래만 /root/bizday/redate.csv 에 적는다.
8. 재계산한 결제일별 집계를 /root/bizday/valuedate_summary.csv 에, 보고서를 /root/bizday/bizday_report.md 에 쓴다.
참고
- 실행 계약: 엔진은
python3 /root/bizday/bizday.py [--db 경로] <하위명령> …으로 부르고 JSON 객체 한 줄을 표준출력에 냅니다.--db의 기본값은/root/bizday/txn.db입니다. is-bizday --date 2026-07-06→{"date":…, "is_bizday": true|false, "reason": "bizday"|"weekend"|"holiday"}next-bizday --date 2026-07-03→{"date":…, "next_bizday": "YYYY-MM-DD"}(그 날 자신은 세지 않습니다)add-bizdays --date 2026-07-03 --n -2→{"date":…, "n":…, "result": "YYYY-MM-DD"}(양수는 앞으로, 음수는 뒤로, 0 은 그 날짜가 영업일이 아닐 때만 다음 영업일로 밉니다)value-date --at 2026-07-02T07:30:00Z→{"at":…, "local":…, "cutoff":…, "after_cutoff": true|false, "value_date": "YYYY-MM-DD"}localize --at 1987-05-15T03:00:00Z --tz Asia/Seoul→{"at":…, "tz":…, "local":…, "local_date":…, "utc_offset": "+10:00"}- 결제일 규칙: 접수 순간을
sys_param.value_date_tz의 지역시각으로 옮기고, 그 시각이sys_param.value_date_cutoff이상이면 하루를 더한 뒤, 그 날짜부터 영업일을 찾아 앞으로 밉니다. - 직접 시험:
python3 /root/bizday/bizday.py value-date --at 2026-07-02T07:30:00Z - 다른 달력으로 시험: 임시 DB 에 holiday·sys_param 두 표만 만들어
--db로 물려 보세요. 채점기가 하는 일이 그것입니다. datetime.fromisoformat은 파이썬 3.11 부터Z접미사를 그대로 읽습니다. 이 이미지의 파이썬은 3.12.3 입니다.- 흔한 실수: 고정 9시간을 더하기, 마감시각을 UTC 시각과 비교하기, 휴장일을 코드에 박기,
.date()를astimezone()앞에서 부르기. - 이 실습의 휴장일 달력은 합성입니다. 실제 기관의 휴장일이 아닙니다.
단계 8개
- 접수 원장 스냅샷 만들기
- 순간과 달력 날짜 갈라 놓기
- 영업일 달력을 엔진으로 옮기기
- 마감시각 뒤의 요청을 익영업일로
- 상대 기관의 달력으로 옮기기
- 1987년 여름의 한 시간 찾아내기
- 결제일을 원장을 덮어쓰지 않고 다시 계산하기
- 집계와 보고서로 옮기기