A few users of an app of mine are having a weird issue, on start-up they get an Exception with the datitimepickers which have a predetermined min/max date set to 01 Jan 1950 - 31 Dec 2050.
The default error message thrown by the app is
"Error reading time1.Max: Failed to set calendar min/max range."
Upon embedding a debugger (madshi's madExcept) I see in the report:
"Error reading time1.MaxDate: '23:59:59' is not a valid date and time."
The object on the form has these properties:
Date = 39773.494141041670000000 Format = 'MMM yyyy' Time = 39773.494141041670000000 MaxDate = 55153.999988425920000000 MinDate = 18264.000000000000000000
Any idea what could be the issue?
Crash data:
main thread ($2b08):
> 0051501b +0a7 app.exe System.Classes 10430 +5 HandleException
> 00515255 +1f5 app.exe System.Classes 10487 +48 TReader.ReadProperty
> 00514a65 +015 app.exe System.Classes 10233 +1 TReader.ReadDataInner
> 00514a47 +067 app.exe System.Classes 10226 +11 TReader.ReadData
> 0051de05 +001 app.exe System.Classes 15947 +0 TComponent.ReadState
> 0057d017 +02f app.exe Vcl.Controls 5567 +3 TControl.ReadState
> 00581481 +025 app.exe Vcl.Controls 8434 +3 TWinControl.ReadState
> 005148bf +11f app.exe System.Classes 10187 +23 TReader.ReadComponent
> 00514ad9 +089 app.exe System.Classes 10241 +9 TReader.ReadDataInner
> 00514a47 +067 app.exe System.Classes 10226 +11 TReader.ReadData
> 0051de05 +001 app.exe System.Classes 15947 +0 TComponent.ReadState
> 0057d017 +02f app.exe Vcl.Controls 5567 +3 TControl.ReadState
> 00581481 +025 app.exe Vcl.Controls 8434 +3 TWinControl.ReadState
> 00604c4c +028 app.exe Vcl.ExtCtrls 10464 +3
> TCustomCategoryPanel.ReadState 005148bf +11f app.exe System.Classes
> 10187 +23 TReader.ReadComponent 00514ad9 +089 app.exe System.Classes
> 10241 +9 TReader.ReadDataInner 00514a47 +067 app.exe System.Classes
> 10226 +11 TReader.ReadData 0051de05 +001 app.exe System.Classes 15947
> +0 TComponent.ReadState 0057d017 +02f app.exe Vcl.Controls 5567 +3 TControl.ReadState 00581481 +025 app.exe Vcl.Controls 8434 +3 TWinControl.ReadState 005c8523 +00b app.exe Vcl.ComCtrls 6207 +1
> TTabSheet.ReadState 005148bf +11f app.exe System.Classes 10187 +23
> TReader.ReadComponent 00514ad9 +089 app.exe System.Classes 10241 +9
> TReader.ReadDataInner 00514a47 +067 app.exe System.Classes 10226 +11
> TReader.ReadData 0051de05 +001 app.exe System.Classes 15947 +0
> TComponent.ReadState 0057d017 +02f app.exe Vcl.Controls 5567 +3
> TControl.ReadState 00581481 +025 app.exe Vcl.Controls 8434 +3
> TWinControl.ReadState 005148bf +11f app.exe System.Classes 10187 +23
> TReader.ReadComponent 00514ad9 +089 app.exe System.Classes 10241 +9
> TReader.ReadDataInner 00514a18 +038 app.exe System.Classes 10220 +5
> TReader.ReadData 0051de05 +001 app.exe System.Classes 15947 +0
> TComponent.ReadState 0057d017 +02f app.exe Vcl.Controls 5567 +3
> TControl.ReadState 00581481 +025 app.exe Vcl.Controls 8434 +3
> TWinControl.ReadState 0064f15d +06d app.exe Vcl.Forms 3836 +11
> TCustomForm.ReadState 005159d7 +1d7 app.exe System.Classes 10667 +37
> TReader.ReadRootComponent 005109c6 +032 app.exe System.Classes 8269
> +3 TStream.ReadComponent 0050a37f +057 app.exe System.Classes 3834 +7 InternalReadComponentRes 0050bcbb +05f app.exe System.Classes 3891 +4 InitComponent 0050bd49 +061 app.exe System.Classes 3903 +6 InitInheritedComponent 0064e982 +0c6 app.exe Vcl.Forms 3592 +17
> TCustomForm.Create 006593da +076 app.exe Vcl.Forms 10407 +13
> TApplication.CreateForm 008e146e +cce app.exe app 342 +211
> initialization 74e9919d +00c KERNEL32.DLL
> BaseThreadInitThunk
>
> main thread ($2b08), inner exception level 1:
> >> EConvertError, '23:59:59' is not a valid date and time 0044d219 +019 app.exe System.SysUtils 5387 +1 ConvertErrorFmt 00453b74 +02c app.exe System.SysUtils 19596 +2 StrToDateTime 005dd4e1 +0f5 app.exe
> Vcl.ComCtrls 27328 +6 TCommonCalendar.SetMaxDate 004e873d +06d
> app.exe System.TypInfo 2238 +8
> {System.TypInfo}TPropSet<System.Double>.SetProc 004e729a +066 app.exe
> System.TypInfo 3185 +3 SetFloatProp 005155ff +18b app.exe
> System.Classes 10567 +25 TReader.ReadPropValue 005151f6 +196 app.exe
> System.Classes 10476 +37 TReader.ReadProperty 00514a65 +015 app.exe
> System.Classes 10233 +1 TReader.ReadDataInner 00514a47 +067 app.exe
> System.Classes 10226 +11 TReader.ReadData 0051de05 +001 app.exe
> System.Classes 15947 +0 TComponent.ReadState 0057d017 +02f app.exe
> Vcl.Controls 5567 +3 TControl.ReadState 00581481 +025 app.exe
> Vcl.Controls 8434 +3 TWinControl.ReadState 005148bf +11f app.exe
> System.Classes 10187 +23 TReader.ReadComponent 00514ad9 +089 app.exe
> System.Classes 10241 +9 TReader.ReadDataInner 00514a47 +067 app.exe
> System.Classes 10226 +11 TReader.ReadData 0051de05 +001 app.exe
> System.Classes 15947 +0 TComponent.ReadState 0057d017 +02f app.exe
> Vcl.Controls 5567 +3 TControl.ReadState 00581481 +025 app.exe
> Vcl.Controls 8434 +3 TWinControl.ReadState 00604c4c +028 app.exe
> Vcl.ExtCtrls 10464 +3 TCustomCategoryPanel.ReadState 005148bf
> +11f app.exe System.Classes 10187 +23 TReader.ReadComponent 00514ad9 +089 app.exe System.Classes 10241 +9 TReader.ReadDataInner 00514a47 +067 app.exe System.Classes 10226 +11 TReader.ReadData 0051de05 +001 app.exe System.Classes 15947 +0 TComponent.ReadState 0057d017 +02f
> app.exe Vcl.Controls 5567 +3 TControl.ReadState 00581481 +025
> app.exe Vcl.Controls 8434 +3 TWinControl.ReadState 005c8523 +00b
> app.exe Vcl.ComCtrls 6207 +1 TTabSheet.ReadState 005148bf +11f
> app.exe System.Classes 10187 +23 TReader.ReadComponent 00514ad9 +089
> app.exe System.Classes 10241 +9 TReader.ReadDataInner 00514a47 +067
> app.exe System.Classes 10226 +11 TReader.ReadData 0051de05 +001
> app.exe System.Classes 15947 +0 TComponent.ReadState 0057d017 +02f
> app.exe Vcl.Controls 5567 +3 TControl.ReadState 00581481 +025
> app.exe Vcl.Controls 8434 +3 TWinControl.ReadState 005148bf +11f
> app.exe System.Classes 10187 +23 TReader.ReadComponent 00514ad9 +089
> app.exe System.Classes 10241 +9 TReader.ReadDataInner 00514a18 +038
> app.exe System.Classes 10220 +5 TReader.ReadData 0051de05 +001
> app.exe System.Classes 15947 +0 TComponent.ReadState 0057d017 +02f
> app.exe Vcl.Controls 5567 +3 TControl.ReadState 00581481 +025
> app.exe Vcl.Controls 8434 +3 TWinControl.ReadState 0064f15d +06d
> app.exe Vcl.Forms 3836 +11 TCustomForm.ReadState 005159d7 +1d7
> app.exe System.Classes 10667 +37 TReader.ReadRootComponent 005109c6
> +032 app.exe System.Classes 8269 +3 TStream.ReadComponent 0050a37f +057 app.exe System.Classes 3834 +7 InternalReadComponentRes 0050bcbb +05f app.exe System.Classes 3891 +4 InitComponent
> 0050bd49 +061 app.exe System.Classes 3903 +6
> InitInheritedComponent 0064e982 +0c6 app.exe Vcl.Forms 3592
> +17 TCustomForm.Create 006593da +076 app.exe Vcl.Forms 10407 +13 TApplication.CreateForm 008e146e +cce app.exe app 342 +211 initialization 74e9919d +00c KERNEL32.DLL
> BaseThreadInitThunk
The "Failed to set calendar min/max range"
error means that DateTime_SetRange()
failed. It was likely given an array of invalid SYSTEMTIME
values as just a side effect of the MaxDate
property failing to load its value from the DFM properly.
The "not a valid date and time"
error comes from StrToDateTime()
. According to your call stack,
>> EConvertError, '23:59:59' is not a valid date and time 0044d219 +019 app.exe
System.SysUtils 5387 +1 ConvertErrorFmt 00453b74 +02c app.exe
System.SysUtils 19596 +2 StrToDateTime 005dd4e1 +0f5 app.exe
Vcl.ComCtrls 27328 +6 TCommonCalendar.SetMaxDate 004e873d +06d app.exe
SetMaxDate()
is calling StrToDateTime()
. I have never seen TDateTimePicker
do that before, so I checked the VCL source and found that the call was added in XE5 (and still exists in the recently released XE6):
procedure TCommonCalendar.SetMaxDate(Value: TDate);
begin
if (FMinDate <> 0.0) and (Value < FMinDate) then
raise CalExceptionClass.CreateFmt(SDateTimeMin, [DateToStr(FMinDate)]);
if FMaxDate <> Value then
begin
Value := Trunc(Value);
Value := Value + StrToDateTime('23:59:59'); // <-- HERE
SetRange(FMinDate, Value);
FMaxDate := Value;
end;
end;
Prior to XE5, SetMaxDate()
looked like this instead:
procedure TCommonCalendar.SetMaxDate(Value: TDate);
begin
if (FMinDate <> 0.0) and (Value < FMinDate) then
raise CalExceptionClass.CreateFmt(SDateTimeMin, [DateToStr(FMinDate)]);
if FMaxDate <> Value then
begin
SetRange(FMinDate, Value);
FMaxDate := Value;
end;
end;
That was just plain stupid on Embarcadero's part, because StrToDateTime()
is subject to user locale settings. Obviously, the time format on the failing machines does not match the hard-coded value that Embarcadero is using. EncodeTime()
should have been used instead:
Value := Value + EncodeTime(23, 59, 59, 0);
In fact, I think Embarcadero should have used ReplaceTime()
as well:
ReplaceTime(Value, EncodeTime(23, 59, 59, 0));
I have filed a bug report in QC:
#124326 MaxDate: '23:59:59' is not a valid date and time
Until Embarcadero fixes it, you have two choices:
patch your VCL manually to fix the bug. If you do not compile your app with Runtime Packages enabled, you can make a copy of Vcl.ComCtrls.pas, edit it as needed, and then add the copy to your project. If you want a more permanent patch, you can compile the edited Vcl.ComCtrls.pas and place the new DCU file(s) in the IDE's lib folder(s).
leave the MaxDate
set to 0.0 at design-time set SetMaxDate()
will not be called at DFM load time, then set MaxDate
manually in your code at startup, since as in the form's OnCreate
event. You will have to temporary change the global SysUtils.FormatSettings
variables (most likely just FormatSettings.TimeSeparator
) to match the format that SetMaxDate()
is using, then assign MaxDate
to the desired value, and then change the variables back to their original values:
var
TS: Char;
TS := FormatSettings.TimeSeparator;
FormatSettings.TimeSeparator := ':';
try
DateTimePicker1.MaxDate := ...;
finally
FormatSettings.TimeSeparator := TS;
end;
.