TDateTimePicker adquirió la propiedad Format en algún momento entre Delphi 5 y Delphi 6. El límite exacto de versión rara vez está documentado de forma fiable, y cuando lo encontráis, el compilador simplemente os dice que el identificador no existe. La línea que compila y funciona en todos los Delphi más nuevos que tenéis falla silenciosamente o directamente en el antiguo, dependiendo de cómo esté estructurado el proyecto.
El control subyacente es el control común Windows DATETIMEPICK_CLASS de comctl32.dll, que siempre ha aceptado una cadena de formato mediante el mensaje DTM_SETFORMAT. El VCL de Delphi envuelve ese mensaje en la propiedad Format en las versiones más recientes. En Delphi 5, enviaréis el mensaje vosotros mismos mediante el wrapper de macro DateTime_SetFormat declarado en CommCtrl.
El patrón de compilación condicional
El enfoque estándar es un bloque condicional de compilador activado por un símbolo de versión. Delphi 5 define VER130; podéis comprobarlo directamente o definir vuestro propio símbolo D5 en las opciones del proyecto para que la etiqueta de la rama sea más legible en toda la base de código. En cualquier caso, la rama de Delphi 5 llama a DateTime_SetFormat con el handle del control; todas las demás ramas asignan la propiedad:
{$IFDEF D5}
DateTime_SetFormat(DateTimePicker1.Handle, PChar('MM/dd/yyyy'));
{$ELSE}
DateTimePicker1.Format := 'MM/dd/yyyy';
{$ENDIF}
Añadid CommCtrl a la cláusula uses de la unidad que contiene la rama de Delphi 5. No es necesario añadirlo de forma incondicional; si preferís mantener la dependencia en ámbito, envolved la entrada uses en el mismo condicional:
uses
...,
{$IFDEF D5}
CommCtrl,
{$ENDIF}
...;
Sintaxis de la cadena de formato
La cadena de formato pasada a DateTime_SetFormat sigue el formato del selector de fecha y hora de Windows, no los tokens de FormatDateTime de Delphi. Los dos se parecen pero no son intercambiables. Windows usa d para el día del mes (sin cero inicial), dd para el día con cero, M para el número de mes, MM para el mes con cero, yy para el año de dos dígitos y yyyy para el de cuatro dígitos. Los campos de hora usan h/hh para horas en formato de 12 horas, H/HH para 24 horas, m/mm para minutos y s/ss para segundos. El texto literal va entre comillas simples dentro de la cadena de formato, por lo que 'dd/MM/yyyy' ya es correcto, pero 'dd '<literal>' MM' requeriría pares de comillas simples incrustadas.
FormatDateTime de Delphi, por el contrario, usa d/dd/ddd/dddd para formas de día con semántica diferente, y m para el mes (no M). Si copiáis una cadena de formato de una llamada a FormatDateTime y la pasáis directamente a DateTime_SetFormat, los campos de mes y minutos probablemente se intercambiarán en la salida. Escribid la cadena de formato del control desde cero siguiendo la documentación de Windows en lugar de convertirla desde un formato de Delphi.
Configuración regional y ShortDateFormat global
Cambiar la variable global ShortDateFormat de Delphi no afecta a un TDateTimePicker ya creado. El selector lee la configuración regional de Windows en el momento de la creación y a partir de entonces renderiza según los mensajes que recibe, no según los globales del RTL de Delphi. Eso significa que establecer ShortDateFormat en FormCreate no cambiará lo que muestra el control. Necesitáis DateTime_SetFormat (o la propiedad Format en Delphi más reciente) para anular la cadena de formato propia del control después de que el handle exista.
Para aplicaciones desplegadas internacionalmente, probad la cadena de formato en una máquina con una configuración regional no estadounidense. Windows puede reemplazar una cadena de formato vacía o nil por el valor predeterminado del locale, pero una cadena no nil explícita tiene precedencia sobre la configuración regional. Eso es normalmente lo que queréis, pero significa que un patrón centrado en EE.UU. como 'MM/dd/yyyy' aparecerá tal cual para usuarios que esperan dd/MM/yyyy por convención. Si el selector de fecha es visible para el usuario en lugar de un campo de introducción de datos puro, considerad dejar el valor predeterminado del control (pasad nil a DateTime_SetFormat) para que siga el locale del usuario automáticamente.
Recreación del handle
La configuración del formato pertenece al handle de ventana, no a ningún campo de objeto VCL. Si el handle del control se destruye y se vuelve a crear, lo que VCL puede hacer cuando reparentáis un control o cambiáis ciertas propiedades de estilo en tiempo de ejecución, el formato vuelve al valor predeterminado de Windows. El lugar seguro para aplicar DateTime_SetFormat es en un manejador que se ejecute después de la creación del handle: sobreescribid CreateWnd en una clase descendiente y llamadlo allí, o aplicadlo en el evento OnEnter o OnShow solo después de confirmar que el handle está activo. Establecerlo una vez en FormCreate suele ser suficiente para formularios simples, pero no es fiable si el formulario realiza cambios de estilo dinámicos o reparentado de controles.
La misma restricción se aplica a la propiedad Format del VCL en versiones más recientes de Delphi; internamente llama al mismo mensaje de Windows y se enfrenta al mismo ciclo de vida del handle. La diferencia es que el setter de la propiedad VCL comprueba si el handle está asignado antes de llamar, y vuelve a aplicar el formato automáticamente en CreateWnd. La llamada directa a DateTime_SetFormat no tiene esa protección, por lo que la rama de Delphi 5 necesita ser más deliberada sobre cuándo se ejecuta.
Eliminar el workaround
Cuando un proyecto abandona el soporte de Delphi 5, el bloque condicional se convierte en peso muerto. Eliminad la rama {$IFDEF D5} y la importación limitada de CommCtrl, dejando solo la asignación directa de la propiedad Format. Mantened la eliminación en un único commit para que sea fácil de identificar si algo se rompe inesperadamente en un compilador que no habéis probado. La cadena de formato en sí permanece igual; solo cambia el mecanismo de entrega.