P08 CSV 날짜에서 불가능한 날짜와 애매한 표기를 구분하기 실습
버전 1.0.0

1. 목표와 입력
받은 날짜 문자열을 고치지 않고 네 상태로 분류합니다.
허용 날짜 표기는 ASCII YYYY-MM-DD이며 날짜만 검사합니다.
시간·시간대·거래일·업무상 진위는 추정하지 않습니다.
모든 ID와 입력은 설명용 가상 자료입니다.

압축을 새 연습 폴더에 풀고 그 폴더에서 아래 명령을 실행하세요.
이 예제는 Linux의 CPython 3.12.14에서 검수했습니다. 다른 버전은 제공된 시험 전체, 특히 CR·CRLF 원문 보존 시험을 먼저 통과해야 사용하세요.
표준 라이브러리만 사용하며 별도 패키지는 필요하지 않습니다.
Windows와 Microsoft Excel은 실행하지 않았습니다.

결과 CSV는 텍스트 편집기로 확인하세요. 원문에 =, +, -, @로 시작하는 값이 있을 수 있으므로 Excel에서 더블클릭해 열거나 수식을 실행하지 마세요.

2. 먼저 시험한 뒤 기본 실행
python --version
python -m unittest discover -s tests -v

검수 환경의 버전 표시는 Python 3.12.14입니다.
시험 결과가 Ran 53 tests / OK인지 확인한 뒤 아래 명령을 실행하세요.
하나라도 실패하면 자신의 자료를 검사하기 전에 실행 환경과 오류를 확인하세요.
CSV writer의 특수문자 인용 동작은 버전별 차이가 있으므로 CR·CRLF 원문 보존을 특히 확인합니다.

python strict_dates.py input/dates.csv date_audit.csv

기대 메시지:
COMPLETED records=5 valid=2 impossible=1 format_unresolved=1 missing=1
기대 종료코드: 0
비교 파일: expected/date_audit.csv

입력과 판정:
R001 / 2024-02-29 / valid / calendar_date_valid
R002 / 2025-02-29 / impossible / calendar_date_invalid
R003 / 2026-10-05 / valid / calendar_date_valid
R004 / 03/04/2026 / format_unresolved / requires_source_confirmation
R005 / 빈 문자열 / missing / empty_value

03/04/2026은 3월 4일 또는 4월 3일로 추측하지 않습니다.
존재 불가·형식 미확정·누락 행도 검수 결과에 남습니다.
종료코드 0은 결과 저장 완료이며 모든 날짜가 정상이라는 뜻은 아닙니다.

3. 날짜와 원문 보존 규칙
빈 문자열만 missing입니다. 공백 세 개·탭·앞뒤 공백은 format_unresolved입니다.
공백을 지우는 strip()이나 날짜 추정 변환을 하지 않습니다.
정규식 fullmatch와 [0-9]로 정확한 ASCII 모양을 확인한 뒤 date()로 달력을 검사합니다.
달력 범위는 0001-01-01부터 9999-12-31입니다.
연도 0000, 잘못된 윤일, 월 13, 일 0 등은 모양이 맞아도 impossible입니다.
20261005, 2026-W41-1, ASCII 외 숫자, 시각 포함 문자열은 format_unresolved입니다.

출력 열: source_record,ID,raw_date,status,reason
source_record는 머리글 제외 데이터 레코드 번호이며 1부터 시작합니다.
인용 필드 안의 줄바꿈이 있어도 하나의 레코드로 셉니다.
ID·raw_date의 읽힌 문자열과 레코드 순서는 그대로 남습니다.
입력 파일의 바이트는 변경하지 않습니다.
결과 CSV의 인용 방식·BOM 유무·줄바꿈 표현까지 입력과 같은 것은 아닙니다.

4. 파일 전체 실패 규칙
입력은 UTF-8 CSV이며 시작 BOM은 허용합니다.
머리글은 정확히 ID,raw_date 순서의 두 필드입니다.
데이터도 두 필드여야 하며 ID는 빈 문자열이거나 중복일 수 없습니다.
ID 중복은 대소문자를 포함한 읽힌 문자열이 같을 때 판정합니다.
쉼표 구분과 큰따옴표 인용을 사용합니다.
큰따옴표는 필드 시작에만 놓고 내부 큰따옴표는 두 번 씁니다.
닫힌 큰따옴표 뒤에는 쉼표·줄바꿈·파일 끝만 허용합니다.
다른 열·순서·열 수·중복 ID·인용 오류·UTF-8 오류는 종료코드 2입니다.
오류를 발견하면 새 최종 결과 파일을 만들지 않습니다.

중복 ID 실패 확인:
python strict_dates.py input/failures/duplicate_id.csv rejected_duplicate_id.csv

기대 메시지:
FAILED: record 2: duplicate ID
기대 종료코드: 2
rejected_duplicate_id.csv가 없어야 합니다.

원본은 보존하고 원자료를 확인한 정정 사본에서만 고치세요.
날짜를 오늘이나 0으로 채우거나 중복 행을 근거 없이 지우지 않습니다.
인코딩 오류는 제공자의 인코딩을 확인한 뒤 UTF-8 사본을 만듭니다.
깨진 문자를 대체 문자로 바꿔 저장하면 원문을 잃을 수 있습니다.

5. 재실행과 새 출력
date_audit.csv가 이미 있으면 같은 출력 이름은 거부합니다.
기대 오류: FAILED: output already exists; choose a new output name
기존 보고서는 보존하고 다음처럼 새 이름을 사용하세요.

python strict_dates.py input/dates.csv date_audit_02.csv

정상 입력의 상태별 기대값은 다시 2 / 1 / 1 / 1입니다.
입력과 출력에 같은 경로를 쓰면 거부합니다.
출력 폴더는 먼저 존재해야 합니다.
전체 입력 검사를 마친 뒤 같은 출력 폴더의 임시 파일에 결과를 씁니다.
완성되어 닫힌 파일을 하드링크로 새 이름에 연결하며 기존 경로는 덮어쓰지 않습니다.
하드링크 미지원·저장 권한·경로 문제는 실패로 보고합니다.
일반 로컬 연습 폴더의 새로운 이름으로 다시 시도하세요.
강제 종료·전원 차단은 시험하지 않았습니다.
남은 .strict_dates_*.tmp 파일은 완성된 검수 보고서로 읽지 않습니다.

6. 경계값과 자동 시험
python strict_dates.py input/edge_cases.csv edge_audit.csv
python strict_dates.py input/header_only.csv header_only_audit.csv
python -m unittest discover -s tests -v

경계값 20행 기대 메시지:
COMPLETED records=20 valid=3 impossible=5 format_unresolved=11 missing=1
비교 파일: expected/edge_audit.csv

머리글만 있는 입력 기대 메시지:
COMPLETED records=0 valid=0 impossible=0 format_unresolved=0 missing=0
비교 파일: expected/header_only_audit.csv
빈 결과가 실제 업무의 날짜 누락이 없다는 증거는 아닙니다.

시험 기대 결과: Ran 53 tests / OK
시험은 격리된 임시 폴더의 가상 입력만 사용합니다.
윤일·월일 경계·ISO 기본 및 주차 표기·Unicode 숫자·공백·누락·원문 보존·
머리글·열 수·큰따옴표·UTF-8·ID 중복·출력 충돌·동일 경로·재실행을 확인합니다.
수식처럼 보이는 문자열은 평가하지 않고 보존하는지만 확인합니다.

7. 첨부 구조와 기록
strict_dates.py: 본문과 같은 전체 코드
input/dates.csv: 기본 가상 다섯 행
input/edge_cases.csv: 경계값 20행
input/header_only.csv: 머리글만 있는 입력
input/failures/: 구조 오류 반례 8개
expected/: 세 정상 결과 CSV와 실패 계약
tests/test_strict_dates.py: 자동 시험 53개
logs/red.log: 초기 구현 없는 골격에서 50개 계약 시험 실패 기록
logs/green.log: 최종 코드에서 53개 시험 통과 기록
logs/supplemental_cr_preservation.log: 원문 CR 경계값 추가 시 통과 기록
logs/actual_cli.log: 격리 CLI 14회 실제 실행 기록
logs/test_first_record.txt: RED와 GREEN 단계 설명
logs/runtime_scope_record.txt: 검수 버전 범위와 특수문자 보존 조건
VERSION.txt / version.json: 버전과 실제 실행 환경
SHA256SUMS.txt: 실습 파일 SHA-256 목록(자기 자신 제외)

코드는 파일 전체와 결과를 메모리에 저장하는 작은 CSV 실습입니다.
큰 파일 성능, 공유 폴더 동시 변경, Windows·Excel 동작은 검증 범위 밖입니다.
자기 업무 자료는 복사본에서 검사하고 날짜 계약과 ID 규칙부터 확인하세요.

공식 문서 확인일: 2026-10-05 UTC
https://docs.python.org/3.12/library/datetime.html#datetime.date
https://docs.python.org/3.12/library/re.html#re.fullmatch
https://docs.python.org/3.12/library/csv.html
https://docs.python.org/3.12/library/os.html#os.link
https://docs.python.org/3.12/library/tempfile.html#tempfile.NamedTemporaryFile
Python 3.12 문서는 현재 3.12.15 표제로 제공되며 실제 실행은 3.12.14입니다.

검수한 CSV writer의 정확한 버전 소스:
https://raw.githubusercontent.com/python/cpython/v3.12.14/Modules/_csv.c
