TDateTimePicker MaxDate - does not allow setting control to current date - delphi

I have set standard VCL TDateTimePicker - MaxDate property to Date - e.g.
DTPicker.MaxDate := Date;
However, there is a problem. If I now set the date to be the current one:
DTPicker.Date := Date;
It will not accept it. The control simply stays at the date which is set at the design time. I can solve it by setting MaxDate to be Date + 1 and then setting the Date property works fine and shows today's date, but then user is able to select tomorrow's date. I also tried to set MaxDate to Date + 0.99999999 but that also is of no help.
I use Delphi 2010 and C++Builder 2010 (if this is a bug in either of them).
Any ideas how to prevent selecting any date beyond today and set the control date to today's date?
Changing the date results in - "Failed to set calendar date or time."
Update:
I managed to make it work as following:
open drop-down in TDateTimePicker (during runtime) and intentionally select Today's date (click on already selected Today's date)
after that select any past date
click button which has the code to reset the date and then it works.
My solution will likely be to use range-check before closing the form, as it seems that MaxDate is useless, at least with this version of Delphi.

It appears it's the time portion of Date that's causing the problem. This works fine on D2007, XE, XE8, and Delphi 10 Seattle:
DateTimePicker1.MaxDate := Trunc(Date) + 0.99999999999;
DateTimePicker1.Date := Date;
Tested using a brand new VCL forms application. Drop a TDateTimePicker and a TButton on the form, and generate an event for the FormCreate for the form:
procedure TForm1.FormCreate(Sender: TObject);
begin
DateTimePicker1.MaxDate := Trunc(Date) + 0.99999999999;
end;
and the button:
procedure TForm1.Button1Click(Sender: TObject);
begin
DateTimePicker1.Date := Date;
end;
Run the app, click the DateTimePicker combobox to display the calendar, and pick any date that's available. The DateTimePicker displays the selected date. Click the button, and the DateTimePicker updates to show today's date. Dropping down the calendar again shows the correct dates available.
Of course, as Remy Lebeau pointed out in a comment: in an actual application, you wouldn't want to hard-code the time portion. A better solution would be to use DateUtils.EndOfDay(Date) or Trunc(Date) + EncodeTime(23, 59, 59, 999).

There is no big difference between adding 1 and 0.99999, as 1 you would increment one day to the date, and 0.999999 it would be almost one day (something like 23:59:59:xxx).
Try the following (you have to include DateUtils in the uses list):
DTPicker.MaxDate := IncSecond(Date);

Related

ECommonCalendarError: Failed to set calendar date or time

I started a new Delphi application, I dropped a TDateTimePicker on the main form, and I added this code:
procedure TForm1.FormShow(Sender: TObject);
begin
DateTimePicker1.MaxDate:= Now - 9;
DateTimePicker1.Date:= Now - 10;
end;
When I run the program and trying to change the date using UP ARROW from the keyboard, I get this error message. But if I change the date with the MOUSE to the last possible date, I don't receive the error message. And after that I can change the date with the arrow key too.
I do not understand what is wrong and how to correct this problem.
Update:
I found another situation when that error occurs: When I drop down the list and close it again, without selecting anything, but with these settings:
procedure TForm1.FormShow(Sender: TObject);
var D:TDate;
begin
D:= Date;
DateTimePicker1.Date:= D;
DateTimePicker1.MaxDate:= D;
end;
There is a bug in Delphi 2009 VCL. The problem is that setter for the MaxDate property did not add time portion of 23:59:59 to the maximum range limit. Then, when one left the Time property on time different from 00:00:00 and set only the Date property the DateTime_SetSystemTime macro failed because of a date time overflow of the date time range (which led to that exception).
To avoid this you can reset the Time property to 00:00:00, or assign date only (keeping time portion zeroed) to the DateTime property.

How do you apply a Delphi ADOTable filter to a date data type

in MS Access I am able to filter a date in a query like this:
ex.
SignUpDate > #31/12/2013#
this will make the database only show records where SignUpDate is in 2014 or newer
How will I do this in delphi?
dmGym.tblMembers.filter := 'SignUpDate > ''#31/12/2013#''' doesn't seem to work
please help it wil be greatly appreciated
You can try :
dmGym.tblMembers.Filter:='SignUpDate > 31/12/2013';
dmGym.tblMembers.Filtered:=True;
This will make the database only show records where SignUpDate is in 2014 or newer.
Good Luck.
I think you don't need the #s, try
[...].Filter := '12/31/2013'; // this is for Sql Server and tested
// for UK locale, for Access you may need to swap the dd and mm,
//and maybe even the yyyy as suggested by #kobik in a comment.
If you use a TDateTime field in a TAdoDataSet.Locate(), the function GetFilterStr plugs the # signs in for you (and makes a hash of it (spot the pun) when doing similar for string fields - see # signs in ADO locates (Delphi XE5)).
But setting a simple filter on a TAdoTable seems to bypass ADODB.GetFilterStr and does a direct assignment to its recordset's Filter property, so I'm guessing that if the #s are needed, they must be plugged in by the ADO/MDac layer.
Delphi stores the datetime as a real number. Today is 05 June 2016 and the interger part of the DateTime is 42,526. Date zero is the start of 1900. You need to generate a variable called DateInt.
Var
DateInt: integer
Date1: TDate;
Begin
DateInt := Trunc(Date1)
When you save a date, save DateInt in the BeforePost event handler. This is an extra field, but filtering is now easy. For example, your filter can now be
NewDateInt := Trunc(Date1);
Filter := ‘NewDate = DateInt’;
Try dmGym.tblMembers.filter := 'SignUpDate > #yyyy/mm/dd#' (2013/12/31)
-credit to kobik's comment

TDateTimePicker and Date

It's a simple question for a weird thing of DatetTimePicker from Delphi XE7.
I have this code...
procedure TForm1.Button1Click(Sender: TObject);
begin
DateTimePicker1.Date:= Date;
memo1.Lines.Add(FloatToStr(Date) + ' vs ' + FloatToStr(DateTimePicker1.Date));
end;
Today, 18 of March 2015, after I press the button the results I get is:
42081 vs 42081.846316956
If I press again after 5 minutes I get the same result.
Why the values are not the same?
The Date() function truncates the decimal portion of the return value (sets the time portion to 0). So it returns the current date/time with only the date filled in.
The TDateTimePicker.Date property setter only updates the date portion of the internal stored TDateTime, leaving the existing time intact. The TDateTimePicker.Date property getter returns the entire internal stored date/time, not the date by itself, as one would expect. So you are seeing the updated date + the original time as initialized by TDateTimePicker.
The TDateTimePicker.Date and TDateTimePicker.Time property getters return both a full date/time value, despite their names. The property setters, on the other hand, update only the date and time portions, respectively, as expected.
The Date() function returns a TDateTime that just contains a date portion, no time portion.
To retrieve just the date portion by itself, you can use the DateOf() function from the DateUtils unit to strip off the time portion of the value returned by the TDateTimePicker.Date or TDateTimePicker.DateTime properties:
DateOf(DateTimePicker1.Date)
Set Datepicker1.Time to 0 and you'll get the same results.
It's the fraction of the daytime passed you see in the decimals.

TMonthCalendar behaviour changed

In the process of migrating one of my Win32 VCL application from Delphi 2006 to delphi XE6 I encountered the following issue :
One of my forms has a TMonthCalendar (plugged on a TPanel for the record) to help the user select a week to view in a graph. By week I mean Monday being the first day and Sunday the last (french locale). To achieve such a week selection pattern I set the multiSelect property to true and put the following code inside the CalendarClick event :
MonthCalendar1.MultiSelect := True;
//Temporarily storing the selected day in a variable
TempoDate := MonthCalendar1.Date;
//searching for the monday right before the selected day (by user)
while dayOfWeek(TempoDate) <> 2 do
TempoDate := IncDay( TempoDate , -1 );
//Setting the monday as the start date of the selection
MonthCalendar1.Date := TempoDate;
//Setting the Sunday as the last day of selection
MonthCalendar1.EndDate := IncDay(tempoDate, 6);
That used to work well on Delphi 2006 ( compiled on a win XP computer ).
Now that I have ported the same code to Delphi XE6 ( compiled on a win7 computer ) I have the following problems :
When clicking the right arrow (>) to switch to the next month it fails most of the time. It actually fails when the monday of the week containing the 1st of the next month is still in the previous month. Ex : switching from Sept '14 to Oct '14 fails because the monday before Oct. 1st is in september (Monday Sept. 29th).
So that brings me back to September.
On the other hand, switching from August 14 to September 14 works because Sept. 1st is a monday.
When clicking on the first days of the next month (the few grey one you can click on) the month doesn't switch anymore.
all that used to work before.
I've made some specific isolation tests :
Creating a minimal app under XE6 with the same behaviour -> still fails (of course)
Creating the same minimal app under Delphi 2006 -> it all work as expected.
My intuition is that the TMonthCalendar now takes the .Date property to define which month to show, while on D2006 it used to take .EndDate property.
Doesn't know if this is a VCL evolution or a microsoft MonthCalendar underlying component behaviour change (since i compiled on XP then SEVEN ).
Thanks for your help
Useful documentation :
http://docwiki.embarcadero.com/Libraries/XE7/en/Vcl.ComCtrls.TMonthCalendar
http://msdn.microsoft.com/en-us/library/system.windows.forms.monthcalendar(v=vs.110).aspx
Unfortunately I can't provide you with solution but athleast I have eplanation for current behavior.
The problem you are facing is the TMonthCalender controll itself and which date fields is trated as selected even when using multiselect.
If you take a good look you will notice that even when using multiselect one day always have doted square around it. That date controls which month is focused.
So now you need to figure out how to change that behavior working with multiple selection enabled. I laredy tried setting the Date and EndDate properties so that EndDate value was actually lower since I thought that doing so miygt force MonthCalendar to treat last day of the weak to be selected when detirmining which month is focused but it has no effect. But it has no effect.
As for finding starting and ending week date use these functions:
TempDate := MonthCalendar1.Date;
WeekStart := StartOfTheWeek(TempDate);
WeekEnd := EndOfTheWeek(TempDate);
Both of these functions treat monday as fist day of the week.
I wish I could have helped you more.

ISO 8601 string date picker (Delphi, DevExpress)

Our Delphi application uses database-bound TcxGridDBColumns to let the user manipulate a ISO 8601-formatted date (YYYY-MM-DD) as a string. I would like to offer the end user a calender-based date picker.
TcxDateEditProperties can't be used (directly) since the underlying database uses a string field. So to my understanding I'm left with the options to
Create an additional date column (TDateTime DB field) in all tables and convert the date to the ISO 8601 string column on the BeforePost event of TDataSet
Create a custom Tcx***Properties class. This would likely involve inheriting from TcxPopupEditProperties.
Since there are many tables affected, I would much rather use #2. Can you point to help documents helping me with that? Or is there a #3?
if what you mean by documents is about writing custom component, then you can see here Creating Custom Delphi Components, as well as the document 'Component Writer's Guide' pdf that comes with Delphi (it has example about customizing DBGrid and navigating months, year and days too). This can be used for starting point for option no.2
There is a #3: No extra column needed, DateEdit understands strings in both current system format (in which a user change is written back) and ISO format. In the BeforePost I convert the system format back to the ISO which I need in the database. As an extra luxury, the following event changes the existing ISO dates to what the user's default date format:
procedure T_RVVorbereitung.cxGridAnalysisDateGetDataText(
Sender: TcxCustomGridTableItem; ARecordIndex: Integer; var AText: string);
var
ADate : TDateTime;
begin
try
try
ADate := TIso8601.DateTimeFromIso8601(AText); // YYYY-MM-DD
except
ADate := StrToDate(AText);
end;
AText := DateToStr(ADate);
except
// neither system nor ISO date: show as it is
end;
end;

Resources