[Interest] Question about setting QLocale

Murphy, Sean smurphy at walbro.com
Tue Dec 1 00:11:30 CET 2015


> 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:

I learned a new word today! 

> > 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.

But now that I'm understanding this issue better, the documentation (http://doc.qt.io/qt-5/qdate.html#fromString) suggests that there is no bug at all, that what I'm seeing is the intended (or at least the documented) behavior, and I'm inclined to agree with that's the way it should be. It specifically states that using the expressions "ddd", "dddd", "MMM", and "MMMM" are going to use the system locale (QLocale::system()) to populate the output string, so that's my error using those expressions with QDateTime::toString() in my log file functions and not understanding the repercussions of that. The bug you want me to submit certainly immediately breaks the documentation. Not necessarily a deal breaker, documentation can be changed...

But in general there's two different issues really, there's displaying dates and times to users and outputting dates in a locale-agnostic way for text data files. If I submit this as a bug as you want me to, and it's fixed in the way you suggest, the DEFAULT behavior is going to be producing the English/US outputs for those expressions above, for all QDate/QDateTime objects, anywhere they're used, regardless of whether it's on the UI or in a text file. I still think I'd find it VERY odd as a non-English developer to have my application default to saying Monday, instead of Montag (or Lunes in Spanish, or whatever "Monday" translates to for my given locale). And if I'm just writing an application for me, my local friends/coworkers, etc., it isn't going to naturally occur to me that I need to go out of my way to specifically ask for dates to be in MY language. I'm an English speaking American and even I find that unnecessarily Amerocentric!

I think a better fix would be that the to/from string functions in QDate/QDateTime like
  QDate QDate::fromString(const QString & string, const QString & format)
Be modified to
  QDate QDate::fromString(const QString & string, const QString & format, const QLocale& locale = QLocale::system())

And add a note in the documentation that states that when using these types of functions in data files where there's a reasonable chance locales will be crossed, that it is recommended that the developer passes in QLocale::c() as the third parameter to ensure compatibility. I think the use case for wanting those date & time strings to be localized on their UI HAS to be more common than log files being passed between countries. 

> > 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.

Fair point, although honestly with my example I was really only trying to understand the behavior of the "dddd" expression with regard to locales, so I should have really just been using "dddd" as my format string instead of bringing in all the MM, dd, yyyy, HH, mm, ss, zzz stuff. 

Now when you say I "should have used QLocale to format the date, asking it for the proper date-time formatting string", are you talking about this function, where QLocale takes over all the formatting
  QDateTime QLocale::toDateTime(const QString & string, FormatType format = LongFormat) const
Not the one I used?
  QDateTime QLocale::toDateTime(const QString & string, const QString & format) const

If that's what you meant, that certainly doesn't solve everything either. The choices for format are QLocale::LongFormat and QLocale::ShortFormat (and NarrowFormat too, but that isn't substantially different than ShortFormat). These produce these outputs in my little test application respectively:
  QLocale::LongFormat
  C: Monday, 30 November 2015 16:17:17 Eastern Standard Time
  System: Monday, November 30, 2015 4:17:17 PM
  German: Montag, 30. November 2015 16:17:17 Eastern Standard Time

  QLocale::ShortFormat
  C: 30 Nov 2015 16:17:17
  System: 11/30/2015 4:17 PM
  German: 30.11.15 16:17

I think the downside to using QLocale's built-in formats is that I as the developer lose a LOT of control over what fields get written out and in what order. Maybe I wanted time first, then date. Maybe I want the localized abbreviated day of week and the abbreviated month name. Maybe I want the localized version "Monday" but I don't want the time zone information. QLocale::toString(const QDate & date, FormatType format) has very limited flexibility. And the string format version provides no way to produce "11/30/2015" or "30.11.2015" from a QDate based on locale. Right?

So I'd think that sticking with the string format is better, but we'd need some more expressions. Something like 'g' to mean "print the delimited date correctly for the desired locale", so the date January 12, 2016 using 'g' (minimum digits for days, 2 digit year) would be expressed as 1/12/16 in the US and 12.1.16 in Germany. Then "gg" (two digits for days, 2 digits for year) could be 01/12/16 (12.01.16), "ggg" (minimum digits for days, 4 digit year) would be 1/12/2016 (12.1.2016) and "gggg" (2 digit days, 4 digit year) is 01/12/2016 (12.01.2016). 

Right now I don't see a way for me to say "Mon, 11/30/2015 5:12 PM" (abbreviated day name, properly delimited full date) in a platform agnostic way using either the QLocale path or the QDate/QDateTime path. The existing QDate/QDateTime classes begin to go a long ways down the path of letting the developer dictate exactly how dates should appear, I just think they don't go far enough when considering locales. 

I still think just switching the QDate/QDateTime to/from String functions to default to use QLocale::c() creates more problems than it solves, though.

Sean



More information about the Interest mailing list