기술 문서

델파이 5의 TDateTimePicker 형식: DateTime_SetFormat

TDateTimePicker는 델파이 5와 델파이 6 사이 어딘가에서 Format 속성을 얻었습니다. 정확한 버전 경계는 신뢰할 수 있는 방식으로 문서화된 경우가 드물며, 해당 경계에 도달하면 컴파일러는 식별자가 존재하지 않는다고 단순하게 알려줍니다. 가지고 있는 모든 최신 델파이에서는 컴파일되고 작동하는 코드가 프로젝트 구조에 따라 이전 버전에서는 조용히 실패하거나 완전히 실패합니다

기본 컨트롤은 comctl32.dll의 Windows DATETIMEPICK_CLASS 공용 컨트롤이며 항상 DTM_SETFORMAT 메시지를 통해 형식(format) 문자열을 허용해 왔습니다. 델파이의 VCL은 최신 버전의 Format 속성에 이 메시지를 래핑합니다. 델파이 5에서는 CommCtrl에 선언된 DateTime_SetFormat 매크로 래퍼를 통해 메시지를 직접 전송합니다

조건부 컴파일 패턴

표준 접근 방식은 버전 심볼에 키를 맞춘 컴파일러 조건부 블록입니다. 델파이 5는 VER130을 정의합니다. 이에 대해 직접 테스트하거나 프로젝트 옵션에서 고유한 D5 심볼을 정의하여 코드베이스 전체에서 분기(branch) 레이블을 더 읽기 쉽게 만들 수 있습니다. 어느 쪽이든 델파이 5 분기는 컨트롤 핸들을 사용하여 DateTime_SetFormat을 호출하고 다른 모든 분기는 속성을 할당합니다:

{$IFDEF D5}
  DateTime_SetFormat(DateTimePicker1.Handle, PChar('MM/dd/yyyy'));
{$ELSE}
  DateTimePicker1.Format := 'MM/dd/yyyy';
{$ENDIF}

델파이 5 분기를 포함하는 유닛의 uses 절에 CommCtrl을 추가하세요. 무조건 추가할 필요는 없습니다. 종속성의 범위를 유지하려는 경우 동일한 조건문에 uses 항목을 래핑하세요:

uses
  ...,
{$IFDEF D5}
  CommCtrl,
{$ENDIF}
  ...;

형식 문자열 구문

DateTime_SetFormat에 전달되는 형식 문자열은 델파이의 FormatDateTime 토큰이 아니라 Windows 날짜-시간 선택기 형식을 따릅니다. 둘은 비슷해 보이지만 서로 바꿔 사용할 수 없습니다. Windows는 월의 날짜(선행 0 없음)에 d, 0으로 채워진 날짜에 dd, 월 번호에 M, 0으로 채워진 월에 MM, 두 자리 연도에 yy, 네 자리 연도에 yyyy를 사용합니다. 시간 필드는 12시간제 시간에 h/hh, 24시간제에 H/HH, 분에 m/mm, 초에 s/ss를 사용합니다. 리터럴 텍스트는 형식 문자열 내의 작은따옴표 안에 들어가므로 'dd/MM/yyyy'는 이미 정확하지만 'dd '<literal>' MM'은 내장된 작은따옴표 쌍이 필요합니다

대조적으로 델파이의 FormatDateTime은 의미론이 다른 일(day) 양식에 d/dd/ddd/dddd를 사용하고 월(month)에 m(M이 아님)을 사용합니다. FormatDateTime 호출에서 형식 문자열을 복사하여 DateTime_SetFormat에 직접 전달하면 출력에서 월과 분 필드가 아마도 바뀌게 될 것입니다. 델파이 형식에서 변환하지 말고 Windows 설명서를 참조하여 컨트롤의 형식 문자열을 처음부터 작성하세요

지역 설정 및 전역 ShortDateFormat

델파이의 전역 ShortDateFormat 변수를 변경해도 이미 생성된 TDateTimePicker에는 영향을 미치지 않습니다. 선택기(picker)는 생성 시 Windows에서 지역 설정을 읽고 그 이후에는 델파이 RTL 전역 변수가 아닌 수신한 메시지에 따라 렌더링됩니다. 즉, FormCreate에서 ShortDateFormat을 설정해도 컨트롤이 표시하는 내용이 변경되지 않습니다. 핸들이 존재하는 한 컨트롤 자체의 형식 문자열을 재정의하려면 DateTime_SetFormat(또는 최신 델파이의 Format 속성)이 필요합니다

국제적으로 배포되는 애플리케이션의 경우 미국 지역 설정이 아닌 시스템에서 형식 문자열을 테스트하세요. Windows는 비어 있거나 nil인 형식 문자열을 로캘 기본값으로 재정의할 수 있지만, 명시적인 nil이 아닌 문자열은 지역 설정을 완전히 대체합니다. 이는 대개 의도한 바일 수 있지만, 관례상 dd/MM/yyyy를 기대하는 사용자에게 'MM/dd/yyyy'와 같은 미국 중심 패턴이 있는 그대로 나타남을 의미합니다. 날짜 선택기가 순수 데이터 입력 필드가 아니라 사용자 대상이라면 컨트롤이 자동으로 사용자의 로캘을 따르도록 기본값으로 두는 것(DateTime_SetFormatnil 전달)을 고려해 보세요

핸들 재생성

형식 설정은 VCL 객체 필드가 아니라 창 핸들에 속합니다. VCL이 런타임에 컨트롤의 부모를 다시 지정(reparent)하거나 특정 스타일 속성을 변경할 때 수행할 수 있는 작업인 컨트롤의 핸들이 삭제되었다가 다시 생성되는 경우, 형식은 Windows 기본값으로 되돌아갑니다. DateTime_SetFormat을 적용하기에 안전한 위치는 핸들 생성 후 실행되는 핸들러입니다: 하위 클래스에서 CreateWnd를 재정의(override)하여 그곳에서 호출하거나, 핸들이 살아있는지 확인한 후에만 OnEnter 또는 OnShow 이벤트에 적용하세요. FormCreate에서 한 번 설정하는 것은 단순한 폼에는 종종 충분하지만 폼이 동적 스타일 전환이나 컨트롤의 부모 변경을 수행하는 경우 신뢰할 수 없습니다

최신 델파이 버전의 VCL Format 속성에도 동일한 제약 조건이 적용됩니다. 내부적으로 동일한 Windows 메시지를 호출하고 동일한 핸들 수명 주기 문제에 직면합니다. 차이점은 VCL 속성 설정자(setter)가 호출을 전달하기 전에 핸들이 할당되었는지 확인하고 CreateWnd에서 형식을 자동으로 다시 적용한다는 것입니다. 원시 DateTime_SetFormat 호출에는 이러한 보호 장치가 없으므로 델파이 5 분기는 언제 실행할지에 대해 더 신중해야 합니다

해결책 제거

프로젝트가 델파이 5 지원을 중단하면 조건부 블록은 무거운 짐이 됩니다. {$IFDEF D5} 분기와 범위가 지정된 CommCtrl 가져오기를 제거하고 직접적인 Format 속성 할당만 남기세요. 테스트하지 않은 컴파일러에서 예기치 않게 손상되는 사항이 있을 때 쉽게 식별할 수 있도록 단일 커밋으로 제거를 유지하세요. 형식 문자열 자체는 동일하게 유지되며 전달 메커니즘만 변경됩니다