Jump to content
PizzaProgram

ISuperObject local double conversion problem. {"value":0,22}

Recommended Posts

In Hungarian language (and Windows) defaults we use "decimal-comma", instead of decimal-point to write down float numbers: `100 000,34 (instead of: 100000.34)`

I know, it's not ideal, but that's how it is.

 

The original ISuperObject had no problem with this, (we have tested!) it has created still numbers `Obj.D['value'] := 100000.34` with dec.point:  `{"value":100000.34}`

But now it does insert comma "," instead of point "."

I see at CHANGED:  Aug 11, 2020 - V8.65 ... Replaced gcvt with FloattoStr

 

Usually I am using my own conversion function for these, and thought I could pass the value by string:

var FormatSetting : TFormatSettings;

FormatSSajat : TFormatSettings;

//0x040e Hungarian Hungary 1250 HUN

GetLocaleFormatSettings(1038, FormatSetting);

FormatSSajat := FormatSetting;

FormatSSajat.DecimalSeparator := '.';

FormatSSajat.DateSeparator := '.';

FormatSSajat.ShortDateFormat := 'yyyy.MM.dd'; // Win10 compatibility, because they have changed to 'yyyy. MM. dd' 😮

...

function fts(const i:Double ) : string;

begin

  Result := FormatFloat('0.00000000', i, FormatSSajat);

 

end;

 

// and pass as string:

json.S['value'] := fts(0.33);

 

But that is wrong too !!!

because it will enclose it to "" : `{"value":"100000.34"}`

 

What can we do ?

Share this post


Link to post

Yep, there must be no any locale-dependent conversions in standardized format. Alas, these functions are hard to spot and remember. Anyway, there should be special formatsettings instance with all explicilty assigned properties.

Share this post


Link to post
35 minutes ago, PizzaProgram said:

V8.65 ... Replaced gcvt with FloattoStr

That change was to allow the unit to be used on non-Windows systems, gcvt is a Windows API. 

 

The dirty way to fix this is to replace a comma with a period immediately after the FloatToText statement, I'll investigate if there is a non-localized FloatToText alternate.

 

Angus

  • Confused 1

Share this post


Link to post

The solution is to use the FloatToStr overload that takes a TFormatSettings and pass one that has DecimalSeparator set to dot.

 

I typically declare such a TFormatSettings as const and fill all the fields that are required for JSON or some other textual format like this - the following for example is being used in Spring for converting various data types to string (from TValue):

 

const
  ISO8601FormatSettings: TFormatSettings = (
    DateSeparator: '-';
    TimeSeparator: ':';
    ShortDateFormat: 'YYYY-MM-DD';
    LongDateFormat: 'YYYY-MM-DD';
    TimeAMString: '';
    TimePMString: '';
    ShortTimeFormat: 'hh:nn:ss';
    LongTimeFormat: 'hh:nn:ss';
    DecimalSeparator: '.';
  );

 

  • Like 3

Share this post


Link to post
14 minutes ago, Stefan Glienke said:

const ISO8601FormatSettings: TFormatSettings = (

Normally I would agree.

But

1.

  I just tried to modify the ICS code under Delphi 7 and got this error:

[Error] OverbyteIcsSuperObject.pas(205): Order of fields in record constant differs from declaration

 

2.

 important settings getting lost, like: CurrencyString !

 

So IMHO this approach (loading the defaults ) is better:

GetLocaleFormatSettings(LOCALE_SYSTEM_DEFAULT, icsFormatSetting);

because it will use a local-default, (by reading every necessary sting for the format-record),

but the user may override it during usage:

icsFormatSentting.DecimalSeparator:= '.';

 

Although there is a big problem about multithreading, so using a simple "global var" isn't a good solution either.

All SuperObjects  should have a global thread-safe variable of this.

 

As for a quick solution it would be also enough to insert some new functions, like: PutD_iso  , PutDT_iso, etc

procedure TSuperObject.PutD_iso(const path: SOString; Value: Double);

 

Share this post


Link to post

IIRC in Delphi 7, you have to list all fields in a const record declaration while in later versions you can omit some as I did - they are then automatically initialized by their default value. And depending on the usage of such a record they don't matter like in my case because I never need the CurrencyString. And you don't need it either because JSON has no currency representation. If you need that usually its represented by different fields, the amount and the currency abbreviation

Personally, I could not care less about a Delphi version from almost 20 years ago lol

Edited by Stefan Glienke
  • Like 1

Share this post


Link to post
22 minutes ago, PizzaProgram said:

 important settings getting lost, like: CurrencyString !

Not relevant to JSON

22 minutes ago, PizzaProgram said:

So IMHO this approach (loading the defaults ) is better:


GetLocaleFormatSettings(LOCALE_SYSTEM_DEFAULT, icsFormatSetting);

because it will use a local-default, (by reading every necessary sting for the format-record),

Nope. You'll get LOCALE settings most of which will be unused and the rest will be overwritten anyway. FS should be either derived from LOCALE_NEUTRAL or just explicitly assigned with only necessary values. As for LOCALE_* stuff, they seem convenient indeed but alas not x-platform. So the most reliable way is to set everything directly just as format specs dictate.

 

22 minutes ago, PizzaProgram said:

using a simple "global var" isn't a good solution either.

All SuperObjects  should have a global thread-safe variable of this.

No problem as it will be used internally and for read only.

 

In my XML unit I do

initialization
  GetLocaleFormatSettings(LOCALE_NEUTRAL, XmlFs);
  XmlFs.DecimalSeparator := XmlDecSep;
  XmlFs.ShortDateFormat  := XmlDateFmtRead;
  XmlFs.DateSeparator    := XmlDateSep;
  XmlFs.LongTimeFormat   := XmlTimeFmtRead;

but that was before I realized that getting values, even neutral, is effectively useless. The only one relatively useful application of this that I could imagine is getting month or day names.

Edited by Fr0sT.Brutal

Share this post


Link to post

Unfortunately, ICS claims to still support Delphi 7, and I did build V8.69 on it last week to check, so any fixes need to be backward compatible, although there are one or two features not supported on D7.  I'll look at this next week, long holiday weekend in the UK.

 

Angus

 

Share this post


Link to post

SVN has been updated with a fix to create period decimal points instead of commas, using a simple version of TFormatSettings, thanks for finding this and the fix suggestions. 

 

When I change the test app locale to Hungarian, I noticed the strange date formatting with spaces, fortunately ICS uses it's own masks and functions for internal date formats. 

 

Angus

Share this post


Link to post

Thanks for the Fix ! 🙂

So the latest 8.70 is good to go? Always "." as decimal point ?

 

Quote

I noticed the strange date formatting with spaces ...

Win10 introduced this crazy new "short" date format: "yyyy. mm. dd." (with spaces)

instead of leaving the "yyyy.mm.dd", which worked fine for 30+ years from Win3.1 up to Win8.1 .

We programmers hate that too.


None of the old programs work on Win10 + 11 any more, freezing at start by trying to load a simple date and creating unhandled AV errors.

IT guys normally go to Win10 settings >> and manually set it back to yyyy.mm.dd (without spaces).

But Win11 does not have that  "custom date" setting any more.

 

Microsoft did not fix it's own DLL to be able to convert both back.

  • Like 1

Share this post


Link to post

Never mind, found the answer at Release mode :

9. Fixed bug in V8.65 where FloattoStr could create Json with comma decimal point instead of a period with some languages.

Share this post


Link to post
On 11/3/2022 at 8:29 PM, PizzaProgram said:

None of the old programs work on Win10 + 11 any more, freezing at start by trying to load a simple date and creating unhandled AV errors.

And that's how their creators learned to not use locale- or OS-dependent formats

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×