How to get correct DateSeparator in Delphi 5? - delphi

I am trying to get the correct DateSeparator when the system locale is set to Cenz Republic. The current date is formatted as 9.3.2017, but DateSeparator is always '/' instead of '.'. What can I do to get the correct date separator?

Regarding date presentations there are several separate global variables affecting the output. You mention two of them:
`DateSeparator: Char;` (initialized from registry with reference `LOCALE_SDATE`)
`ShortDateFormat: string;` (initialized from registry with reference `LOCALE_SSHORTDATE`)
The other ones you can see in the documentation or in code in unit SysUtils starting on line 490 (in Delphi 7, might be different in Delphi 5).
Since the DateSeparator and ShortDateFormat are separate variables, it is possible that you see dates presented correctly according your locale, while the DateSeparator return an erroneous character.
To rectify, you can assign the correct character to DateSeparator yourself in your code, but beware if you are using 3rd party libraries, that those might possibly also want to change it.

Related

Reading COBOL code with .NET to generate a call graph

I am working on a project to automate COBOL to generate a class diagram. I am developing using a .NET console application. I need help tracking down the procedure name where the perform statement in used in the below example.
**Z-POST-COPYRIGHT.
move 0 to RETURN-CODE
perform Z-WRITE-FILE**
How do I track the procedure name 'Z-Post-COPYRIGHT' where the procedure 'Z-write-file' is called? The only idea I could think of in terms of COBOL is through indentation as the procedure names are always indented. Ideally in the database, the code should track the procedure name after the word 'perform' and procedure under which it is called (in this case it is Z-POST-COPYRIGHT).
I assume you want to do this "on your own" without external tools (a faster approach can be found at the end).
You first have to "know" your source:
which compiler was it compiled with (get a manual for this compiler)
which options were used
Then you have to preparse the source:
include copybooks (doing the given REPLACING rules if any)
if the source is in free-form reference format: concatenate contents of last line and current line if you find a - in column 7
check for REPLACE and change the result accordingly
remove all comments (maybe only * and \ in column 7 in fixed-form reference format or similar (extensions like "variable" format / "terminal" format", ... exist, maybe only inline comments - when in free-form reference-format, otherwise maybe inline comments *> or compiler specific extensions like |) - depending on the further re-engineering you want to do it could be a good idea to extract them and store them at least with a line number reference
The you finally can track the procedure name with the following rule:
go backwards to the last separator period (there are more rules but the rule "at least one line break, another period, a space a comma or a semicolon" [I've never seen the last two in real code but it is possible" should be enough)
check if there is only one word between this separator period and the next
if this word is no reserved COBOL word (this depends on your compiler) it is very likely a procedure name
Start from here and check the output, then fine grade the rule with actual false positives or missing entries.
If you want to do more than only extract the procedure-names for PERFORM and GO TO (you should at least check the sources for PERFROM ... THRU) then this can get to a lot of work...
Faster approach with external tools:
run a COBOL compiler on the complete sources and tell it to do the preparsing only - this way you have the big second point solved already
if you have the option: tell the compiler or an external tool to create a symbol table / cross reference - this will tell you in which line a procedure is and its name (you can simply find the correct procedure by comparing the line)
Just a note: You may want to check GnuCOBOL (formerly OpenCOBOL) for the preparsing and/or generation of symbol tables/cross-reference and/or printcbl for a completely external tool doing preparsing and/or cobxref for a complete cross reference generation.

Extended ASCII characters displayed as ? (question mark)

I have a form with a bunch of flags (static images) and below each flag is a tick box. The user selects the tick box to allow them to use a particular language. At design-time, I've set the checkbox captions for each language in their localised equivalent, in this example "Español" (Spanish).
For nearly every language this is displayed just fine at runtime, but for a couple of languages this changes to "Espa?ol". Specifically, this happens when I select Lithuanian and use:
// Note: 1063 = ((SUBLANG_DEFAULT shl 10) or LANG_LITHUANIAN)
SetThreadLocale(1063);
Curiously, if I simply re-apply the caption with the following line in the form's OnShow handler, then it displays correctly as "Español".
tbLangSpanish.Caption := 'Español'; // Strange, it now corrects itself!
The above code might be improved slightly by checking to see whether the runtime caption has a "?" character in it and only then re-apply the caption. The rest of the application displays Lithuanian perfectly (with labels being set at runtime).
Note that "ñ" is extended ASCII code 241. This issue affects a couple of other extended characters such as "ç" (character 231) in "Français". Of interest is that some extended ASCII characters are displayed correctly eg. "¾" (character 190).
Is this a bug in the IDE (using Delphi 7) or just a fact-of-life with legacy ASCII (ie. non-UNICODE) characters? Is there a prefered way to detect incompatible design-time extended ASCII characters at runtime (perhaps based on locale)?
None of the searches I performed gave any explanation about why a character would display as "?". I'm assuming this is because the requested character must be missing from the current Windows codepage, but no reference I could find explicitly says what is displayed when this happens (nor how to overcome the problem if you cannot use UNICODE).
The ? character is what happens when a conversion from one code page to another fails because the target code page does not contain the required character. This is an inevitable consequence of programming against the ANSI Win32 API. You simply cannot represent all characters in all languages.
The only realistic way forward is to use Unicode. You have two main options starting from Delphi 7:
Stick to Delphi 7 and use the TNT Unicode components.
Upgrade to a modern version of Delphi which has native support for Unicode.

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.

Comparing Dates in Delphi 7 using DateTimePicker components

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.

Resources