나이 계열 7종·주민번호 마스킹 3종 — 215종 → 225종 (조사 라운드 7 시작)
PAT_나이(bzDataInterface.vb:373 Case Else — 통합 대표행의 AgeMonth 파생 컬럼과 같은 식을 SQL 로: UDF_GETAGE_FROMRESNUM(복호화, 적용일시), dtCommonLib.vb:3725 확인. CGCH 분기·암호화 N 갈래 미이식), PAT_나이_세(:417 — 산정코드 24* 는 UDF_GETAGE(PatBthDay), 그 밖은 AgeCheck), PAT_성별_나이(:359 — "성별/나이". HIMCHAN_BP·BSYD 분기 미이식), PAT_나이_개월수(:430 — 월 경계 -1, 기존 MonthsSince 재사용), 개월·일 4종(:436-508 — 30일 나눗셈, 새 DaysSince 로 분해). AgeCheck(clsCommonLib.vb:665-974)를 ResidentNumber.AgeOf 로 이식 — 세기 접두 규칙(1·2→19, 3·4→20, 5·6→출생2자리<20 이면 20xx 아니면 19xx+월일 0101 강제, 7·8→서버 연도 2자리 비교, 그 외→18xx. REDCROSS· BSYD·BSGH 특례 미이식), 만나이(생일 당일 차감 없음 — 2024-09-25 이후 전 병원 규칙), 1세 이하는 고정 365일. 테스트 5건 — 기대값 하나가 틀려 있었다(출생 2자리 "20"은 <20 이 아니라 1920년으로 강제 — 구현이 맞고 판정을 고침). 개월·일 4종의 기준일은 레거시가 PC 시계(Now)라 서버 오늘로 바꿈(의도적 이탈 — 단말마다 값이 갈리면 안 된다). PAT_주민번호_Blind/SexTyp_Blind/SexTyp_BlindStar(:105-186 Case Else — 앞6 " - " 뒤 XXXXXXX / 성별1+XXXXXX / 성별1+******. SYBS 의 J-계열 서식 전체 노출 분기 미이식). 대조군 교체: PAT_나이가 이식되면서 ⑬·edit-smoke 의 "안 옮긴 태그" 대조군이 깨졌다(의도된 동작) — ETC_수술실간호사로 교체. ㊱ 신설: 나이 UDF 2종이 실값을 돌려준다(접두 없이 동작 확인). - dotnet test 342/342 (AgeOf 5건 추가) · --edit-smoke 실패 0 - --db-patient ①~㊱ 전건 통과 - --db-render P062 md5 8d683835f5d81e7bb41c79071d6bf954 불변 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
abb08d0c6b
commit
8256b79800
@@ -134,6 +134,16 @@ public static class ResidentNumber
|
||||
/// 실제 개월수와 다르지만 레거시가 그렇게 찍는다 — 달력으로 고치면 값이 달라진다.
|
||||
/// </summary>
|
||||
public static string MonthsDaysSince(string? birthDay, string? todayYmd)
|
||||
{
|
||||
var days = DaysSince(birthDay, todayYmd);
|
||||
return days is null ? string.Empty : $"{days / 30}개월 {days % 30}일";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 생일부터 기준일까지 총 일수 — 개월·일 분해 태그 4종의 공통 재료.
|
||||
/// 날짜를 못 읽으면 null(레거시는 예외가 전파돼 노란색이 되던 자리다).
|
||||
/// </summary>
|
||||
public static int? DaysSince(string? birthDay, string? todayYmd)
|
||||
{
|
||||
var birth = Clean(birthDay);
|
||||
var today = Clean(todayYmd);
|
||||
@@ -143,10 +153,83 @@ public static class ResidentNumber
|
||||
|| !DateTime.TryParseExact(today[..8], "yyyyMMdd", null,
|
||||
System.Globalization.DateTimeStyles.None, out var to))
|
||||
{
|
||||
return string.Empty;
|
||||
return null;
|
||||
}
|
||||
var days = (int)(to - from).TotalDays;
|
||||
return $"{days / 30}개월 {days % 30}일";
|
||||
return (int)(to - from).TotalDays;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 만 나이 — 레거시 <c>AgeCheck</c>(clsCommonLib.vb:665-974)의 이식.
|
||||
///
|
||||
/// <b>세기 접두 규칙</b>(주민번호 7번째 자리): 1·2→19xx, 3·4→20xx,
|
||||
/// 5·6(외국인)→ 출생 2자리가 20 미만이면 20xx, 아니면 19xx 에 <b>월일을 0101 로
|
||||
/// 강제</b>(행려·외국인은 앞 6자리가 생년월일이 아닐 수 있다는 레거시 판단),
|
||||
/// 7·8→ 서버 오늘의 연도 2자리와 비교해 19/20, 그 외(0·9)→18xx.
|
||||
/// REDCROSS(적십자)·BSYD·BSGH 의 병원 특례는 옮기지 않았다 — 전부 Case Else 갈래다.
|
||||
///
|
||||
/// <b>만 나이 규칙</b>: 기준년-출생년, 생일이 아직 안 지났으면 -1(생일 당일은 차감 없음 —
|
||||
/// 2024-09-25 이후 전 병원 규칙). 나이가 1 이하면 총 일수차가 <b>365 미만</b>일 때 0
|
||||
/// (고정 365 — 윤년 경계의 하루 오차까지 레거시 그대로).
|
||||
///
|
||||
/// 레거시는 잘못된 입력에서 오류창을 띄우고 0 을 돌려줬다 — 여기서는 조용히 0 이다.
|
||||
/// </summary>
|
||||
public static long AgeOf(string? residentNumber, string? toDate, string serverToday)
|
||||
{
|
||||
var res = Clean(residentNumber);
|
||||
if (res.Length < 13 || serverToday.Length < 8)
|
||||
{
|
||||
return 0; // 레거시도 빈 값은 0, 짧은 값은 예외→0 이었다
|
||||
}
|
||||
string birth8;
|
||||
switch (res[6])
|
||||
{
|
||||
case '1' or '2':
|
||||
birth8 = "19" + res[..6];
|
||||
break;
|
||||
case '3' or '4':
|
||||
birth8 = "20" + res[..6];
|
||||
break;
|
||||
case '5' or '6':
|
||||
if (!int.TryParse(res[..2], out var left2))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
birth8 = left2 < 20 ? "20" + res[..6] : "19" + res[..2] + "0101";
|
||||
break;
|
||||
case '7' or '8':
|
||||
if (!int.TryParse(res[..2], out var yy2)
|
||||
|| !int.TryParse(serverToday.Substring(2, 2), out var nowYy))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
birth8 = (nowYy < yy2 ? "19" : "20") + res[..6];
|
||||
break;
|
||||
default:
|
||||
birth8 = "18" + res[..6];
|
||||
break;
|
||||
}
|
||||
var to = Clean(toDate);
|
||||
if (to.Length < 8)
|
||||
{
|
||||
to = serverToday;
|
||||
}
|
||||
if (!int.TryParse(to[..4], out var toYear) || !int.TryParse(birth8[..4], out var birthYear)
|
||||
|| !int.TryParse(birth8.Substring(4, 4), out var birthMmdd)
|
||||
|| !int.TryParse(to.Substring(4, 4), out var toMmdd))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
long age = toYear - birthYear;
|
||||
if (birthMmdd > toMmdd)
|
||||
{
|
||||
age -= 1;
|
||||
}
|
||||
if (age <= 1)
|
||||
{
|
||||
var days = DaysSince(birth8, to[..8]);
|
||||
return days is null ? 0 : days < 365 ? 0 : 1;
|
||||
}
|
||||
return age;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user