using System.Globalization; namespace Infrastructure.StockData; /// /// SEIBro 파서 공용 필드 변환 헬퍼 — 순수 C#. YYYYMMDD→DateOnly, 콤마 포함 숫자→decimal/long/int, Y/N→bool. /// 값 없음/""/비형식 = null (SeibroXml 이 빈 value 를 이미 키 제외 처리하므로 여기 들어오는 raw 는 대개 비어있지 않지만 방어적으로 처리). /// Wave 0 파서들(SeibroStkStatParser 등)의 로컬 헬퍼와 동일 규칙을 한 곳에 모아 Wave 1+ 파서가 재사용한다. /// internal static class SeibroFieldParse { /// YYYYMMDD 8자리 → DateOnly. 그 외(빈값/형식 불일치)는 null. public static DateOnly? Date(string? raw) { var value = raw?.Trim(); if (string.IsNullOrEmpty(value) || value.Length != 8) { return null; } return DateOnly.TryParseExact(value, "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var date) ? date : null; } /// 콤마 제거 후 decimal. 빈값/비숫자는 null (0 과 구분). public static decimal? Decimal(string? raw) { var value = raw?.Replace(",", string.Empty, StringComparison.Ordinal); return decimal.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var parsed) ? parsed : null; } public static int? Int(string? raw) { var value = raw?.Replace(",", string.Empty, StringComparison.Ordinal); return int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsed) ? parsed : null; } /// NUMBER(15,4) 등 소수 표기 정수 → long (decimal 로 읽고 절사). 빈값/비숫자는 null. public static long? Long(string? raw) { var value = raw?.Replace(",", string.Empty, StringComparison.Ordinal); return decimal.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var parsed) ? (long)parsed : null; } /// Y→true, N→false, 그 외(빈값/미제공)→null. public static bool? Yn(string? raw) { return raw?.Trim().ToUpperInvariant() switch { "Y" => true, "N" => false, _ => null }; } }