TDateTimePicker มีคุณสมบัติ Format เพิ่มเข้ามาในช่วงระหว่าง Delphi 5 และ Delphi 6 ซึ่งขอบเขตของเวอร์ชันที่แน่นอนนั้นไม่ค่อยมีบันทึกที่เชื่อถือได้ และเมื่อคุณเจอเรื่องนี้ คอมไพเลอร์จะบอกเพียงว่า identifier ไม่มีอยู่ บรรทัดคำสั่งที่สามารถคอมไพล์และทำงานได้ใน Delphi เวอร์ชันใหม่ทั้งหมดที่คุณมี อาจจะล้มเหลวแบบเงียบๆ หรือพังไปเลยบนเวอร์ชันเก่า ขึ้นอยู่กับโครงสร้างของโปรเจ็กต์
คอนโทรลที่อยู่เบื้องหลังคือ Windows DATETIMEPICK_CLASS common control จาก comctl32.dll และรองรับรูปแบบสตริงผ่านข้อความ DTM_SETFORMAT เสมอ VCL ของ Delphi ห่อหุ้มข้อความนั้นไว้ในคุณสมบัติ Format ในเวอร์ชันที่ใหม่กว่า ส่วนใน Delphi 5 คุณจะต้องส่งข้อความเองผ่าน macro wrapper DateTime_SetFormat ที่ประกาศไว้ใน CommCtrl
รูปแบบ conditional compilation
วิธีการมาตรฐานคือบล็อก compiler-conditional ที่ระบุผ่านสัญลักษณ์เวอร์ชัน Delphi 5 กำหนดค่า VER130 คุณสามารถทดสอบกับสิ่งนี้ได้โดยตรง หรือกำหนดสัญลักษณ์ D5 ของคุณเองในตัวเลือกของโปรเจ็กต์ (project options) เพื่อให้ชื่อป้ายกำกับของสาขาอ่านง่ายขึ้นใน codebase ไม่ว่าจะใช้วิธีใด สาขาของ Delphi 5 จะเรียกใช้ DateTime_SetFormat ด้วยแฮนเดิลคอนโทรล ส่วนสาขาอื่นๆ จะกำหนดค่าไปที่คุณสมบัติ:
{$IFDEF D5}
DateTime_SetFormat(DateTimePicker1.Handle, PChar('MM/dd/yyyy'));
{$ELSE}
DateTimePicker1.Format := 'MM/dd/yyyy';
{$ENDIF}
เพิ่ม CommCtrl ลงในส่วนคำสั่ง uses สำหรับยูนิตที่มีสาขาของ Delphi 5 ไม่มีความจำเป็นต้องเพิ่มแบบไม่มีเงื่อนไข หากคุณต้องการควบคุมขอบเขตของ dependency ให้ห่อหุ้มรายการ uses ด้วยเงื่อนไขเดียวกัน:
uses
...,
{$IFDEF D5}
CommCtrl,
{$ENDIF}
...;
ไวยากรณ์รูปแบบสตริง (Format string syntax)
รูปแบบสตริงที่ส่งไปยัง DateTime_SetFormat จะเป็นไปตามรูปแบบ Windows date-time picker ไม่ใช่โทเค็น FormatDateTime ของ Delphi ทั้งสองแบบดูคล้ายกันแต่ไม่สามารถใช้แทนกันได้ Windows ใช้ d สำหรับวันที่ของเดือน (ไม่มีศูนย์นำหน้า), dd สำหรับวันที่เติมศูนย์นำหน้า, M สำหรับหมายเลขเดือน, MM สำหรับเดือนที่เติมศูนย์นำหน้า, yy สำหรับปีแบบสองหลัก และ yyyy สำหรับปีแบบสี่หลัก สำหรับฟิลด์เวลาจะใช้ h/hh สำหรับชั่วโมงแบบ 12 ชั่วโมง, H/HH สำหรับ 24 ชั่วโมง, m/mm สำหรับนาที, s/ss สำหรับวินาที ข้อความที่เป็น literal จะอยู่ในเครื่องหมายอัญประกาศเดี่ยว (single quote) ภายในรูปแบบสตริง ดังนั้น 'dd/MM/yyyy' จึงถูกต้องอยู่แล้ว แต่ 'dd '<literal>' MM' จะต้องใช้เครื่องหมายอัญประกาศเดี่ยวที่ซ้อนกัน
ในทางกลับกัน FormatDateTime ของ Delphi ใช้ d/dd/ddd/dddd สำหรับรูปแบบวันที่ซึ่งมีความหมายต่างกัน และใช้ m สำหรับเดือน (ไม่ใช่ M) หากคุณคัดลอกรูปแบบสตริงจากการเรียกใช้ FormatDateTime และนำมาส่งให้กับ DateTime_SetFormat โดยตรง ฟิลด์ของเดือนและนาทีอาจจะสลับกันในผลลัพธ์ ควรเขียนรูปแบบสตริงของคอนโทรลขึ้นมาใหม่ตั้งแต่ต้นโดยอิงตามเอกสารคู่มือของ Windows แทนที่จะแปลงจากรูปแบบของ Delphi
Regional settings และตัวแปร global ShortDateFormat
การเปลี่ยนตัวแปร global ShortDateFormat ของ Delphi จะไม่มีผลกับ TDateTimePicker ที่ถูกสร้างขึ้นมาแล้ว ตัวควบคุม picker จะอ่านการตั้งค่า regional settings จาก Windows ในช่วงเวลาที่สร้าง และหลังจากนั้นจะแสดงผลตามข้อความที่ได้รับ ไม่ใช่จาก Delphi RTL globals นั่นหมายความว่าการตั้งค่า ShortDateFormat ใน FormCreate จะไม่เปลี่ยนสิ่งที่คอนโทรลแสดงผล คุณจำเป็นต้องใช้ DateTime_SetFormat (หรือคุณสมบัติ Format ใน Delphi รุ่นใหม่) เพื่อเขียนทับรูปแบบสตริงของตัวคอนโทรลเองหลังจากที่แฮนเดิลถูกสร้างขึ้นแล้ว
สำหรับแอปพลิเคชันที่มีการปรับใช้ในระดับสากล ควรทดสอบรูปแบบสตริงในเครื่องที่มีการตั้งค่า regional settings นอกเหนือจาก US ระบบ Windows สามารถเขียนทับรูปแบบสตริงที่ว่างหรือ nil ด้วยค่าเริ่มต้นของ locale แต่สตริงที่มีการระบุค่าและไม่ใช่ nil จะแทนที่การตั้งค่า regional settings ทั้งหมด โดยปกติแล้วนั่นคือสิ่งที่คุณต้องการ แต่นั่นก็หมายความว่ารูปแบบที่ยึดตาม US เช่น 'MM/dd/yyyy' จะแสดงตามนั้นสำหรับผู้ใช้ที่คาดหวังรูปแบบ dd/MM/yyyy ตามธรรมเนียม หาก date picker เป็นสิ่งที่จะปรากฏให้ผู้ใช้เห็น แทนที่จะเป็นเพียงฟิลด์ป้อนข้อมูลเปล่าๆ ให้พิจารณาปล่อยให้คอนโทรลทำงานตามค่าเริ่มต้น (โดยการส่ง nil ไปยัง DateTime_SetFormat) เพื่อให้เป็นไปตาม locale ของผู้ใช้โดยอัตโนมัติ
การสร้างแฮนเดิลใหม่ (Handle recreation)
การตั้งค่ารูปแบบนั้นเป็นของ window handle ไม่ใช่ของฟิลด์ VCL object ใดๆ หากแฮนเดิลของคอนโทรลถูกทำลายและสร้างใหม่ ซึ่ง VCL สามารถทำได้เมื่อคุณเปลี่ยน parent (reparent) ของคอนโทรล หรือเปลี่ยนคุณสมบัติรูปแบบ (style properties) บางอย่างในช่วงรันไทม์ รูปแบบจะกลับไปเป็นค่าเริ่มต้นของ Windows ตำแหน่งที่ปลอดภัยในการใช้งาน DateTime_SetFormat คือใน handler ที่ทำงานหลังจากสร้างแฮนเดิลแล้ว: โดยการ override CreateWnd ใน descendant class และเรียกใช้ที่นั่น หรือนำไปใช้ในเหตุการณ์ OnEnter หรือ OnShow หลังจากตรวจสอบยืนยันแล้วว่าแฮนเดิลกำลังทำงานอยู่เท่านั้น การตั้งค่าเพียงครั้งเดียวใน FormCreate มักจะเพียงพอสำหรับฟอร์มทั่วไป แต่มันจะไม่เสถียรหากฟอร์มมีการสลับสไตล์แบบไดนามิก (dynamic style switching) หรือมีการทำ control reparenting
ข้อจำกัดแบบเดียวกันนี้ยังถูกนำไปใช้กับคุณสมบัติ VCL Format ใน Delphi เวอร์ชันที่ใหม่กว่า ในระบบภายในมันจะเรียกข้อความ Windows เดิมและเจอกับวงจรชีวิตของแฮนเดิลแบบเดียวกัน ความแตกต่างคือ VCL property setter จะตรวจสอบว่าแฮนเดิลได้รับการจัดสรรก่อนที่จะเรียกผ่านหรือไม่ และจะนำรูปแบบมาใช้ซ้ำโดยอัตโนมัติที่ CreateWnd ส่วนการเรียก DateTime_SetFormat ตรงๆ จะไม่มีการป้องกันแบบนั้น ดังนั้นสาขาของ Delphi 5 จึงต้องมีความรอบคอบมากขึ้นเกี่ยวกับเวลาที่มันจะทำงาน
การถอดการแก้ไขชั่วคราวออก (Removing the workaround)
เมื่อโปรเจ็กต์ยุติการสนับสนุน Delphi 5 บล็อกที่มีเงื่อนไขจะกลายเป็นส่วนเกิน (dead weight) ให้นำสาขา {$IFDEF D5} และการนำเข้า CommCtrl แบบมีขอบเขตออก ให้เหลือไว้เพียงการกำหนดค่าให้กับคุณสมบัติ Format โดยตรง ควรรวมการลบนั้นไว้ใน commit เดียวเพื่อให้ง่ายต่อการระบุปัญหาหากมีสิ่งผิดปกติเกิดขึ้นอย่างไม่คาดคิดในคอมไพเลอร์ที่คุณไม่ได้ทดสอบ รูปแบบสตริงจะยังคงเหมือนเดิม สิ่งที่เปลี่ยนไปมีเพียงกลไกการส่งมอบเท่านั้น