Comparing Dates in Delphi 7 using DateTimePicker components - delphi

I am trying to dynamically assign a date to two DateTimePicker components, and then comparing the two.
I have two conditions that I want to do here. In the first, I want to test if the date given to the component is the same as the current date. I do it like this:
if DateClosed.date = DateCurrent.date then
begin
//some code goes here
end;
In the second instance I am trying to test if the date provided to dateClosed falls on or between two other dates that is also provided to two DateTimePicker.
I am using Borland Delphi 7 Professional.
Please try to keep answers as simple as possible, as I am fairly new to Delphi.

TDateTimePicker.Date includes a time component (a fractional part to the right of the decimal point) even when you've specified that you only want a date. This causes the comparison to fail, because even though the date portion (the part to the left of the decimal) might match exactly, the fractional portion doesn't.
If you only want to compare the date parts (ignoring any time difference), just remove the fractional part using Trunc (in the System unit, so automatically available without adding anything to your uses clause):
if Trunc(DateClosed.Date) = Trunc(DateCurrent.Date) then
// The dates are the same
For more info, see the Delphi help file - the XE3 documentation is here, but it hasn't changed since Delphi 7.

Related

How to change the system shortdatetime format using delphi xe3

I am going to try and make the question as simple as possible.
How do i either convert the system date to a format i would like, and still keep it a date and not a string.
Or how do i get the system's date format, to adjust my dates accordingly.
When i call
FormatShortdateTime('d/M/yyyy',Date);
I get the correct date as string, but cannot convert it back to a Tdate and use it, then it clashes with the system date settings.
If i can get the system shortdate format the problem would be solved.
Update
The answer below refers to the original question that you asked. You've edited the question multiple times now to ask different questions. You really should not do that and it is a sign that you should spend more time understanding the problem before asking questions.
Even so, the final part of the answer, probably still contains the advice that you need. Namely to stop using conversion functions that rely on the global FormatSettings variable, and always use conversion functions that are passed format settings as a parameter.
The date values in your database are not stored in the format that you expect. This program:
{$APPTYPE CONSOLE}
uses
System.SysUtils;
var
fs: TFormatSettings;
begin
fs := TFormatSettings.Create;
fs.ShortDateFormat := 'd/M/yyyy';
Writeln(DateToStr(StrToDate('18/2/2014', fs)));
end.
produces the following output on my machine:
18/02/2014
I guess on your machine it would produce a different output because your short date format is different from mine. But the point is that the call to StrToDate succeeds.
Clearly the values stored in your database are not in the form you claim. Because you claim that the above code would lead to a date conversion error in the call to StrToDate.
Let's step back and look at the initial part of your question:
I would like to know how to convert dates without having the system date influence the software.
The code in the answer above gives you an example of how to do that. Modern versions of Delphi overload the date and time conversion functions. There are overloads that accept TFormatSettings parameters, and overloads without such a parameter. The TFormatSettings parameter is used to control the format used for the conversion. The overloads that do not receive such a parameter use the global FormatSettings instance declared in the SysUtils unit.
What you should do to avoid having the system settings influence your conversions is to only use conversion functions that accept a format settings parameter.
On the other hand, if you want the system settings to influence your conversions, then feel free to call the overloads that use the global format settings variable.
My code above illustrates both. The conversion from string to date requires a fixed format, not varying with local system settings. The conversion from date to string is designed to show a date using the prevailing local system settings.
I would advice creating own TFormatSettings variable
older delphi versions
var
fs: TFormatSettings;
begin
fs := TFormatSettings.Create;
GetLocaleFormatSettings(LOCALE_SYSTEM_DEFAULT, fs);
end.
This will create your own formatSettings (filled with system format) so you won't alter the default one.
Now what's important is that '/' in shortDateFormat will be replaced by dateSeparator so if you do this
fs.ShortDateFormat:='M/d/yyyy';
fs.dateSeparator:='?';
your input should be like this
strtodate('12?30?1899', fs);
or if other way around you will end up with string: '12?30?1899';
I think that your problems originate from that you don't ask what dateSeparator is used. That would lead to problems if what program expects is '30-12-1899' but he gets '30/12/1899' from you.

Overriding the system Date Format

In my application I am reading from one database and writing to a second. The app is quick and dirty so I am reading / writing using AsString on both the FieldByName and ParamByName of the queries.
This works for all my use cases apart from where the data type is Date or DateTime
As far as I can tell FieldByName.AsString uses the system ShortDateTime format to return dates as (in my case) dd/mm/yyyy. The database expects the date to be written in as yyyy-mm-dd
According to Delphi Basics I should be able to set ShortDateFormat to what I need, but it appears that in XE5 this is no longer the case (correct?)
Further digging on here returns these two questions that use TFormatSettings to override the local settings. However, both of these use the resulting FormatSettings in StrToDate and FormatDateTime directly.
So two questions
1) Can I tell my application to override the System ShortDateFormat?
2) If so, How (I have a Plan B if not)?
The use of a global variable for the date and time formats was a mistake committed long ago by the original RTL designers. Functions that rely on the global format settings, like the single parameter StrToDate are retained for backwards compatibility, but you should not be using them.
For conversions between date/time and string you should:
Initialise a TFormatSettings instance with your date format.
Call the two parameter StrToDate, passing your TFormatSettings to convert from a string to a date.
Call FormatDateTime overload that accepts a TFormatSettings when converting in the other direction.
Now, to the main thrust of your question. You should not be using strings at all for your dates and times in the scenario you describe. Use AsDateTime rather than AsString. If you happen to have a database column that does store a date/time as a string, then you'll should use the TFormatSettings based conversion functions to work around that design fault.
If you are absolutely dead set on doing this all with strings, and I cannot persuade you otherwise, then you need to use FormatSettings.ShortDateFormat from SysUtils to control your short date formatting.

How do I set Excel column types and formatting?

I'm exporting data from a CxDBGrid to an Excel file.
I'm able to create the file and copy data in it, but I'm having real trouble with the column formatting. Since I'm pulling the data from a DB I'd like the spreadsheet to reflect the type: NUMBER, VARCHAR2,DATE and so on.
I visually created a macro, went to look for the VBA code, and replicated it in the Delphi project:
sheet.Columns[K+2].NumberFormat := '0,000'; //Number
sheet.Columns[K+2].NumberFormat := '#'; //Text
sheet.Columns[K+2].NumberFormat := 'm/d/yyyy'; //Date
Number formatting works ok most of the times, but the other two don't.
When I open the generated file, the text columns show up as type "Custom" and every cell displays "-64". If I go to edit a cell, the correct value is actually there.
Date is another issue: the DB's format is dd/mm/yyyy and if I feed it to Excel as-is, it gets all messed up. I tried setting the correct format, but then Excel doesn't recognize it.
Any clues?
I'm also setting column width. That works flawlessly.
The problem is that the assigned values are Unicode strings. Try this:
sheet.Columns[K+2].NumberFormat := AnsiChar('#');
sheet.Columns[K+2].NumberFormat := AnsiString('m/d/yyyy');
You haven't said "how you are doing things manually" which means people have to completely guess what you're doing. So here's my wild guess:
If I assume you're using the Express Spreadsheet component from Developer Express
I have estensive experience with this component. It does not support arbitrary numeric formats. It supports a "money" format (0.00) with exactly two decimal places. It does not support three or one, or any other number of decimal places.
If so, this is a known by-design issue in the Express spreadsheet.
If by manually you mean that "sheet" as you show above is an OLE object and you're communicating via OLE Automation to Excel itself, then you should be formatting CELLS either individually or as a range, and not column objects. I am not sure how column object formats would ever override the cell values, if they do at all. The formatting of cells is generally a cell by cell matter, and must be dealt with as such.
If you really want this to work properly you won't use Excel via OLE automation, you'll get a proper Excel XLS format capable writing library. I was quite sure that you could get proper results directly from the CX (DevEx) db grid, but I would ask on their forums, not here. With a regular DB Grid, I'd just use TJvDBGridExcelExport which comes in the Jedi JVCL, and which works with the regular VCL DB Grid.

TDictionary.ContainsKey returning false, even though the key exists

The problem I'm facing now has totally made me feel like I don't understand programming at all. I have a TDictionary object which consists of pairs of TDate => TEvent (custom class). The object is used in a class which is shared by two separate applications (they don't communicate). In one application, the following works correctly:
// Get recipes from the very event.
Tmp := FCalendar.ContainsKey(D);
if (Tmp) then
begin
E := FCalendar[D];
CopyRecipes(E);
end;
On the other hand, the same piece of code doesn't work in the other application ! How is that possible? I have attached a screenshot of what is happening in the debugger:
As you can see, the key is present in the dictionary, and yet ContainsKey() returns FALSE.
What is causing this?
Regards,
Patryk.
The reason is that TDate is actually just a TDateTime. That means it is a double precision value holding number of days since the Delphi epoch. The IDE debug hints for a TDate show just the date part and omit the time part. You are comparing for equality and so two values that are in the same day, but have different time components will not be equal. Here's a screenshot to illustrate:
Solve the problem by using DateOf to remove the time part of the date time. You will have to use DateOf whenever you receive a date value, and clearly before you add to the dictionary.
possibly in D not 2011-11-11
possibly D:=2011-11-11 00-00-00

Delphi FormatFloat and Format functions

I have an application where users can set how values are displayed. The users enter a formatting string and the component uses FormatFloat to display the value.
But now we are using a new third-party component which formats values using the Format function and of course none of our user formats work as the Format & FormatFloat functions use a different syntax.
So does anyone know of a way of converting between the two? Or maybe someone has code to do it?
Thanks,
AJ
Though the format strings for FormatFloat can be more or less transformed to ones for Format, you may only get real similarity for positive values. The Format method simply doesn't offer enough flexibility to incorperate the features and fine-grained control that the format strings for the FormatFloat method offers.
For example, the FormatFloat method allows for three different formats for positive, negative and zero values. Also, the FormatFloat format strings allow for string literals, e.g. '#,##0.00;;Zero'; (which means that zero values are printed as "Zero").
To get something similar using the Format function, you yourself would need to do all the grunt work that FormatFloat is doing for you through the format string.
So, although I am as opposed to changing third party control's sources as I am opposed to changing the vcl sources, I am with David on this one: find a way to make the third party control use the FormatFloat function. Preferably through a custom descendant or through an interposer class (also known as an interceptor class), but if that fails, by all means change the third party control's source. Just make sure that you mark the changed sections properly so you can easily redo it when switching to a new version of that control.
Far and away the simplest solution will be to take the source of the 3rd party component (you should only consider using 3rd party Delphi components that come with source) and modify it to call FormatFloat rather than Format.

Resources