From a53312dad1fbb454f32f1481b8c79351fe6ea512 Mon Sep 17 00:00:00 2001 From: John Layt Date: Fri, 25 Oct 2013 22:54:21 +0200 Subject: QLocale - Fix Mac date format code translation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mac uses the CLDR format codes which need to be translated into their Qt equivalent. The existing code mistranslates the year code, is outdated for a number of new codes introduced in recent versions of CLDR, and by default accepted any codes it didn't recognize. This change updates support to the latest version of CLDR, fixes the treatment of years, and defaults to ignoring any new format codes added in the future. Back-ported from qtbase/77dc33dcdbe0eec8ddc9059c4e0ff9dde264c5fa Task-number: QTBUG-25057 Change-Id: Ide040eca467cfada46fb0e2010db179a76b3096a Reviewed-by: Morten Johan Sørvig --- src/corelib/tools/qlocale_mac.mm | 105 +++++++++++++++++++++++++++---------- tests/auto/qlocale/tst_qlocale.cpp | 5 +- 2 files changed, 77 insertions(+), 33 deletions(-) diff --git a/src/corelib/tools/qlocale_mac.mm b/src/corelib/tools/qlocale_mac.mm index b4a0f44..cd74958 100644 --- a/src/corelib/tools/qlocale_mac.mm +++ b/src/corelib/tools/qlocale_mac.mm @@ -166,6 +166,11 @@ static QString macTimeToString(const QTime &time, bool short_format) return QCFString(CFDateFormatterCreateStringWithDate(0, myFormatter, myDate)); } +// Mac uses the Unicode CLDR format codes +// http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table +// See also qtbase/util/local_database/dateconverter.py +// Makes the assumption that input formats are always well formed and consecutive letters +// never exceed the maximum for the format code. static QString macToQtFormat(const QString &sys_fmt) { QString result; @@ -185,55 +190,97 @@ static QString macToQtFormat(const QString &sys_fmt) int repeat = qt_repeatCount(sys_fmt, i); switch (c.unicode()) { - case 'G': // Qt doesn't support these :( - case 'Y': - case 'D': - case 'F': - case 'w': - case 'W': - case 'g': + // Qt does not support the following options + case 'G': // Era (1..5): 4 = long, 1..3 = short, 5 = narrow + case 'Y': // Year of Week (1..n): 1..n = padded number + case 'U': // Cyclic Year Name (1..5): 4 = long, 1..3 = short, 5 = narrow + case 'Q': // Quarter (1..4): 4 = long, 3 = short, 1..2 = padded number + case 'q': // Standalone Quarter (1..4): 4 = long, 3 = short, 1..2 = padded number + case 'w': // Week of Year (1..2): 1..2 = padded number + case 'W': // Week of Month (1): 1 = number + case 'D': // Day of Year (1..3): 1..3 = padded number + case 'F': // Day of Week in Month (1): 1 = number + case 'g': // Modified Julian Day (1..n): 1..n = padded number + case 'A': // Milliseconds in Day (1..n): 1..n = padded number break; - case 'u': // extended year - use 'y' - if (repeat < 4) + case 'y': // Year (1..n): 2 = short year, 1 & 3..n = padded number + case 'u': // Extended Year (1..n): 2 = short year, 1 & 3..n = padded number + // Qt only supports long (4) or short (2) year, use long for all others + if (repeat == 2) result += QLatin1String("yy"); else result += QLatin1String("yyyy"); break; - case 'S': // fractional second - if (repeat < 3) - result += QLatin1Char('z'); + case 'M': // Month (1..5): 4 = long, 3 = short, 1..2 = number, 5 = narrow + case 'L': // Standalone Month (1..5): 4 = long, 3 = short, 1..2 = number, 5 = narrow + // Qt only supports long, short and number, use short for narrow + if (repeat == 5) + result += QLatin1String("MMM"); else - result += QLatin1String("zzz"); + result += QString(repeat, QLatin1Char('M')); break; - case 'E': - if (repeat <= 3) - result += QLatin1String("ddd"); - else + case 'd': // Day of Month (1..2): 1..2 padded number + result += QString(repeat, c); + break; + case 'E': // Day of Week (1..6): 4 = long, 1..3 = short, 5..6 = narrow + // Qt only supports long, short and padded number, use short for narrow + if (repeat == 4) result += QLatin1String("dddd"); + else + result += QLatin1String("ddd"); break; - case 'e': - if (repeat >= 2) - result += QLatin1String("dd"); + case 'e': // Local Day of Week (1..6): 4 = long, 3 = short, 5..6 = narrow, 1..2 padded number + case 'c': // Standalone Local Day of Week (1..6): 4 = long, 3 = short, 5..6 = narrow, 1..2 padded number + // Qt only supports long, short and padded number, use short for narrow + if (repeat >= 5) + result += QLatin1String("ddd"); else - result += QLatin1Char('d'); + result += QString(repeat, QLatin1Char('d')); break; - case 'a': + case 'a': // AM/PM (1): 1 = short + // Translate to Qt uppercase AM/PM result += QLatin1String("AP"); break; - case 'k': + case 'h': // Hour [1..12] (1..2): 1..2 = padded number + case 'K': // Hour [0..11] (1..2): 1..2 = padded number + case 'j': // Local Hour [12 or 24] (1..2): 1..2 = padded number + // Qt h is local hour + result += QString(repeat, QLatin1Char('h')); + break; + case 'H': // Hour [0..23] (1..2): 1..2 = padded number + case 'k': // Hour [1..24] (1..2): 1..2 = padded number + // Qt H is 0..23 hour result += QString(repeat, QLatin1Char('H')); break; - case 'K': - result += QString(repeat, QLatin1Char('h')); + case 'm': // Minutes (1..2): 1..2 = padded number + case 's': // Seconds (1..2): 1..2 = padded number + result += QString(repeat, c); + break; + case 'S': // Fractional second (1..n): 1..n = truncates to decimal places + // Qt uses msecs either unpadded or padded to 3 places + if (repeat < 3) + result += QLatin1Char('z'); + else + result += QLatin1String("zzz"); break; - case 'z': - case 'Z': - case 'v': + case 'z': // Time Zone (1..4) + case 'Z': // Time Zone (1..5) + case 'O': // Time Zone (1, 4) + case 'v': // Time Zone (1, 4) + case 'V': // Time Zone (1..4) + case 'X': // Time Zone (1..5) + case 'x': // Time Zone (1..5) result += QLatin1Char('t'); break; default: - result += QString(repeat, c); + // a..z and A..Z are reserved for format codes, so any occurrence of these not + // already processed are not known and so unsupported formats to be ignored. + // All other chars are allowed as literals. + if (c < QLatin1Char('A') || c > QLatin1Char('z') || + (c > QLatin1Char('Z') && c < QLatin1Char('a'))) { + result += QString(repeat, c); + } break; } diff --git a/tests/auto/qlocale/tst_qlocale.cpp b/tests/auto/qlocale/tst_qlocale.cpp index 8e299b1..9cac40f 100644 --- a/tests/auto/qlocale/tst_qlocale.cpp +++ b/tests/auto/qlocale/tst_qlocale.cpp @@ -1132,10 +1132,7 @@ void tst_QLocale::macDefaultLocale() QCOMPARE(locale.decimalPoint(), QChar('.')); QCOMPARE(locale.groupSeparator(), QChar(',')); QCOMPARE(locale.dateFormat(QLocale::ShortFormat), QString("M/d/yy")); - if (QSysInfo::MacintoshVersion > QSysInfo::MV_10_6) - QCOMPARE(locale.dateFormat(QLocale::LongFormat), QString("MMMM d, y")); - else - QCOMPARE(locale.dateFormat(QLocale::LongFormat), QString("MMMM d, yyyy")); + QCOMPARE(locale.dateFormat(QLocale::LongFormat), QString("MMMM d, yyyy")); QCOMPARE(locale.timeFormat(QLocale::ShortFormat), QString("h:mm AP")); QCOMPARE(locale.timeFormat(QLocale::LongFormat), QString("h:mm:ss AP t")); -- cgit v0.12