Pregunta

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
¿Fue útil?

Solución

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:

  1. 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).

  2. 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;
    

.

Otros consejos

I was also getting "Failed to set calendar min/max range." when setting the min or max dates on a TMonthCalendar control:

myCalendar.MinDate:= myMinDate;

This was resolved by casting the new value as a TDateTime;

myCalendar.MinDate:= TDateTime(myMinDate);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top