Issues related to using FormatSettings.LongDateFormat for Timestamps in ZDatasetParams

The offical for ZeosLib 7.3 Report problems, ask for help, post proposals for the new version of Zeoslib 7.3/v8
Quick Info:
-We made two new drivers: odbc(raw and unicode version) and oledb
-GUID domain/field-defined support for FB
-extended error infos of Firebird
-performance ups are still in queue
In future some more feature will arrive, so stay tuned and don't hassitate to help
Post Reply
MJFShark
Expert Boarder
Expert Boarder
Posts: 211
Joined: 04.06.2020, 13:59

Issues related to using FormatSettings.LongDateFormat for Timestamps in ZDatasetParams

Post by MJFShark »

Zeoslib seems to use FormatSettings.LongDateFormat in the ZDatasetparam unit to convert timestamps. This appears to be incorrect (or at least the default LongDateFormat format string is currently actually a very verbose date only format, perhaps that changed at some point?) On my system it defaults to 'dddd, mmmm d, yyyy' and includes no time component. This can be worked around by doing something like:

FormatSettings.LongDateFormat := FormatSettings.ShortDateFormat + ' ' + FormatSettings.LongTimeFormat;

But it seems it shouldn't be necessary. This comes into play if you set a timestamp param to a string in order to convert it.

ZParam := TZParam.Create(nil);
ZParam.Datatype := ftdatetime;
ZParam.Value := '1903. 03. 02.';

On my system which has a longdateformat as shown above, this goes into an infinite loop. Obviously this is a bad value (It's from a recent csv file used for debugging purposes) but it would be best if it just failed instead of looping.

The eventual call that fails is:

Test := TryUniToTimeStamp('1903. 03. 02.', 13, 'dddd, mmmm d, yyyy', TS);
(I just mention this as it's the smallest code to show the issue.)

I can enter this as a bug in the tracker, but I wanted others to check to see if maybe I'm just misunderstanding something. Thanks as always!

-Mark
User avatar
aehimself
Zeos Dev Team
Zeos Dev Team
Posts: 765
Joined: 18.11.2018, 17:37
Location: Hungary

Re: Issues related to using FormatSettings.LongDateFormat for Timestamps in ZDatasetParams

Post by aehimself »

It's important here to mention the IDE used. Delphi 11 changed how date parsing is done and it caused our software at work to start failing at almost any point.

Edit: 2 things.

1, Infinite loop? If I'm trying to feed it with a value surely different from my LongDateFormat, it simply crashes with a range check error.
2, You are right with .LongDateFormat. Even Delphi RTL is using ShortDateFormat for string to date(time) transformation:

Code: Select all

function ScanDate(const S: string; var Pos: Integer; var Date: TDateTime;
  const AFormatSettings: TFormatSettings): Boolean; overload;
[...]
begin
  DateSeq := ParseDateTimeFormat(AFormatSettings.ShortDateFormat, False);
[...]
I vote on chaning this to .ShortDayFormat at least, however it won't solve your issue just yet.

Edit-edit: it'll clearly be an issue with Zeos. Check InternalSetAsUnicodeString:
stDate: if (FDataSet = nil) or not TZAbstractRODataset(FDataSet).FormatSettings.EditDateFormatSettings.TryStrToDate(PZDate(DataAddr)^, Value) then
if not TryUniToDate(P, L, {$IFDEF WITH_FORMATSETTINGS}FormatSettings{$ELSE}SysUtils{$ENDIF}.ShortDateFormat, PZDate(DataAddr)^) then goto jmpErr;
stTime: if (FDataSet = nil) or not TZAbstractRODataset(FDataSet).FormatSettings.EditTimeFormatSettings.TryStringToTime(PZTime(DataAddr)^, Value, 9) then
if not TryUniToTime(P, L, {$IFDEF WITH_FORMATSETTINGS}FormatSettings{$ELSE}SysUtils{$ENDIF}.LongTimeFormat, PZTime(DataAddr)^) then goto jmpErr;
stTimestamp: if (FDataSet = nil) or not TZAbstractRODataset(FDataSet).FormatSettings.EditTimestampFormatSettings.TryStrToTimestamp(PZTimestamp(DataAddr)^, Value, 9) then
if not TryUniToTimeStamp(P, L, {$IFDEF WITH_FORMATSETTINGS}FormatSettings{$ELSE}SysUtils{$ENDIF}.LongDateFormat, PZTimeStamp(DataAddr)^) then goto jmpErr;
If no dataset is assigned, then it uses .ShortDateFormat for date only parsing and .LongDateFormat for time and date/time parsing. This is clearly wrong.
I'll check what it does if we have a dataset assigned.

Edit-edit-edit:
Same thing with a dataset. However an other suspicious line in TryUniToDate:

Code: Select all

            else if (F in [Byte('-'),Byte('/'),Byte('\'),Byte(' ')]) then begin
Shouldn't we be using FormatSettings.DateSeparator instead of a constant array...?
Delphi 12.1, Zeos 8 from latest GIT snapshot
Using:
- MySQL server 8.0.18; libmariadb.dll 3.3.8
- Oracle server 11.2.0, 12.1.0, 19.0.0; oci.dll 21.13
- MSSQL 2012, 2019; sybdb.dll FreeTDS_2435
- SQLite 3.45.2
MJFShark
Expert Boarder
Expert Boarder
Posts: 211
Joined: 04.06.2020, 13:59

Re: Issues related to using FormatSettings.LongDateFormat for Timestamps in ZDatasetParams

Post by MJFShark »

That's interesting. For me, this call goes into an infinite loop in both 32bit and 64bit debug mode. Delphi 11.3 patch 1.

Test := TryUniToTimeStamp('1903. 03. 02.', 13, 'dddd, mmmm d, yyyy', TS);

That's odd that it causes a range error for you instead, but I haven't spent a lot of time debugging it. On a side note, I'm not sure I've ever seen a date formatted that way before. Is that a regional format in some country?

-Mark
MJFShark
Expert Boarder
Expert Boarder
Posts: 211
Joined: 04.06.2020, 13:59

Re: Issues related to using FormatSettings.LongDateFormat for Timestamps in ZDatasetParams

Post by MJFShark »

Update! I've also now seen it give range check/pointer errors when trying to convert that format. It looks like (and confirmed from the thread you linked to) that those library functions just can't handle multi-char date delimiters. I'm not sure how important that is, since that's a format I've never seen "in the wild." The general issue about using LongDateFormat for timestamps still should be looked at.

-Mark
User avatar
aehimself
Zeos Dev Team
Zeos Dev Team
Posts: 765
Joined: 18.11.2018, 17:37
Location: Hungary

Re: Issues related to using FormatSettings.LongDateFormat for Timestamps in ZDatasetParams

Post by aehimself »

Yes, this is the standard date format in Hungary (where I live).

I don't know which library you mean, because built-in RTL functions do handle "multi-char" delimiters (up to 2, that is) fine. The only issue on D11+ was that it's not accepting "2023. 06. 17" because it requires the trailing delimiter as well as short date format is "yyyy/mm/dd/".
Delphi 12.1, Zeos 8 from latest GIT snapshot
Using:
- MySQL server 8.0.18; libmariadb.dll 3.3.8
- Oracle server 11.2.0, 12.1.0, 19.0.0; oci.dll 21.13
- MSSQL 2012, 2019; sybdb.dll FreeTDS_2435
- SQLite 3.45.2
Fr0sT
Zeos Dev Team
Zeos Dev Team
Posts: 280
Joined: 08.05.2014, 12:08

Re: Issues related to using FormatSettings.LongDateFormat for Timestamps in ZDatasetParams

Post by Fr0sT »

aehimself wrote: 16.06.2023, 20:47 However an other suspicious line in TryUniToDate:

Code: Select all

            else if (F in [Byte('-'),Byte('/'),Byte('\'),Byte(' ')]) then begin
Shouldn't we be using FormatSettings.DateSeparator instead of a constant array...?
I guess TryUniToTimeStamp is meant to be a kind of universal converter regardless of some regional settings to allow more broad set of formats on input. Thus these separators. Multichar separators were likely not foreseen. As you can see, this function does custom parsing with whole lot of black magic to boost performance so has nothing to do with current locale or RTL.
Anyway I consider the practice of assigning a string value to a timestamp field toxic and only allowable for simple apps by beginners. Serious apps should convert dates themselves according to locale settings and assign TDate(Time) values.
Post Reply