[Interest] Question about setting QLocale

Thiago Macieira thiago.macieira at intel.com
Mon Nov 30 20:29:52 CET 2015


On Monday 30 November 2015 18:58:53 Murphy, Sean wrote:
> Thanks for the quick reply, Thiago
> 
> > That's a bug. And there's another bug in your reading/writing of the
> > string, but that's besides the point.
> 
> Can you go into more details about this? I'd prefer to have no bugs! ;)

You said:

> it fails to convert because what's been written in the file for data recorded
> on a Friday is "ÖÜÎå"

That's Mojibake[1], which means you wrote to the file with one encoding and 
read using another. The Chinese word for Friday is 周五, not "ÖÜÎå". Since 
you're getting 4 characters instead of the Chinese two, I'm guessing the file 
was written in GB18030 and read as Latin1[2]. A simple test confirms this:

$ echo 周五 | iconv -t gb18030 | iconv -f latin1
ÖÜÎå

[1] https://en.wikipedia.org/wiki/Mojibake
[2] if you had got six, I would have guessed writing as UTF-8 and reading as 
Latin1; if you had got 4 replacement characters instead of letters in the 
Latin-A Extended block, I would have guessed writing as GB18030 and reading as 
UTF-8.

> > QString QDateTime::toString(const QString& format) const {
> > 
> >     return QLocale::system().toString(*this, format); }
> > 
> > It should have been QLocale::c(). It's been like the above since 5.2.0 and
> > no one noticed. That is, btw, your workaround: use
> > 
> >   QLocale::c().toString(ample.sampleTime(), "ddd MM/dd/yyyy HH:mm:ss.zzz")
> 
> Is that really a bug in Qt though?

Yes. QString, QByteArray, QDateTime, etc. should always use the C locale when 
formatting their contents to a string and when parsing a string. That's so 
that data files produced with those strings can be parsed when the locale 
changes. That is to say, exactly your scenario.

Take, for example, one of the greatest design flaws of the C library: scanf and 
printf. They always use the locale API to format the decimal and group 
separators, which means they are wholly unsuitable for formatting data meant 
to be portable. That's why QtCore carries its own code to format integers and 
floating point to string, instead of using the C library.

That's why POSIX extends the C API with scanf_l and printf_l, fixing the design 
flaw. Qt 5.7 will allow you to optionally use those (sscanf_l and snprintf_l) 
if your C library has them.

> I'd think as a developer/user in a
> non-English speaking country that if I were to write out a date object
> using either the "ddd" or "dddd" options, that I would expect those to show
> up in my native language.

If you want locale-formatted output, use QLocale.

> This produces:
>     DateTime: Saturday 01/01/2000 00:00:00.000
>     Default: Samstag 01/01/2000 00:00:00.000
>     C: Saturday 01/01/2000 00:00:00.000
>     German: Samstag 01/01/2000 00:00:00.000
> 
> So I'd think your proposal to change QDateTime::toString() to use
> QLocale::c() would be the wrong behavior. 

It will be done. The question is whether we do it in 5.6, 5.7 or in 6.0. But 
it will happen.

> If I'm in Germany, I'd expect to
> see Samstag, not Saturday. 

Actually, your code is wrong. Let's use today's date instead:

    DateTime: Monday 11/30/2015 00:00:00.000
    Default: Montag 11/30/2015 00:00:00.000
    C: Monday 11/30/2015 00:00:00.000
    German: Montag 11/30/2015 00:00:00.000

If I am in Germany, I'd expect to see 30.11.2015 (dd.MM.yyyy), not MM/dd/yyyy 
like you used. So your code should have used QLocale to format the date, 
asking it for the proper date-time formatting string.

You may argue whether QDateTime::toString() should have done that by default. 
My argument stands that QDateTime, like QString and QByteArray, should only 
produce predictable output (not locale-dependent).

> Or am I making some other mistake in my test
> application (or misunderstanding what QLocale::c() actually does)? I'm
> assuming that the line: QLocale::setDefault(QLocale(QLocale::German,
> QLocale::Germany)); Fakes out the rest of the Qt classes to think I'm in
> Germany, although that first line I print out, where I use
> QDateTime::toString() and I'm getting it in English kind of says otherwise.

QLocale::setDefault() changes the default locale, not the system locale. The 
system locale is determined by, well, the system. Consult its documentation on 
how to change (you're on Windows, as proven by the Mojibake above).

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Software Architect - Intel Open Source Technology Center




More information about the Interest mailing list