diff --git a/autotests/kformattest.cpp b/autotests/kformattest.cpp index bb74a99..5cc98b1 100644 --- a/autotests/kformattest.cpp +++ b/autotests/kformattest.cpp @@ -1,381 +1,392 @@ /* This file is part of the KDE Frameworks Copyright (C) 2013 John Layt , Copyright (C) 2010 Michael Leupold Copyright (C) 2009 Michael Pyne Copyright (C) 2008 Albert Astals Cid This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kformattest.h" #include #include "kformat.h" void KFormatTest::formatByteSize() { QLocale locale(QLocale::c()); locale.setNumberOptions(QLocale::DefaultNumberOptions); // Qt >= 5.6 sets QLocale::OmitGroupSeparator for the C locale KFormat format(locale); QCOMPARE(format.formatByteSize(0), QStringLiteral("0 B")); QCOMPARE(format.formatByteSize(50), QStringLiteral("50 B")); QCOMPARE(format.formatByteSize(500), QStringLiteral("500 B")); QCOMPARE(format.formatByteSize(5000), QStringLiteral("4.9 KiB")); QCOMPARE(format.formatByteSize(50000), QStringLiteral("48.8 KiB")); QCOMPARE(format.formatByteSize(500000), QStringLiteral("488.3 KiB")); QCOMPARE(format.formatByteSize(5000000), QStringLiteral("4.8 MiB")); QCOMPARE(format.formatByteSize(50000000), QStringLiteral("47.7 MiB")); QCOMPARE(format.formatByteSize(500000000), QStringLiteral("476.8 MiB")); #if (defined(__WORDSIZE) && (__WORDSIZE == 64)) || defined (_LP64) || defined(__LP64__) || defined(__ILP64__) QCOMPARE(format.formatByteSize(5000000000), QStringLiteral("4.7 GiB")); QCOMPARE(format.formatByteSize(50000000000), QStringLiteral("46.6 GiB")); QCOMPARE(format.formatByteSize(500000000000), QStringLiteral("465.7 GiB")); QCOMPARE(format.formatByteSize(5000000000000), QStringLiteral("4.5 TiB")); QCOMPARE(format.formatByteSize(50000000000000), QStringLiteral("45.5 TiB")); QCOMPARE(format.formatByteSize(500000000000000), QStringLiteral("454.7 TiB")); #endif QCOMPARE(format.formatByteSize(1024.0, 1, KFormat::IECBinaryDialect), QStringLiteral("1.0 KiB")); QCOMPARE(format.formatByteSize(1023.0, 1, KFormat::IECBinaryDialect), QStringLiteral("1,023 B")); QCOMPARE(format.formatByteSize(1163000.0, 1, KFormat::IECBinaryDialect), QStringLiteral("1.1 MiB")); // 1.2 metric QCOMPARE(format.formatByteSize(-1024.0, 1, KFormat::IECBinaryDialect), QStringLiteral("-1.0 KiB")); QCOMPARE(format.formatByteSize(-1023.0, 1, KFormat::IECBinaryDialect), QStringLiteral("-1,023 B")); QCOMPARE(format.formatByteSize(-1163000.0, 1, KFormat::IECBinaryDialect), QStringLiteral("-1.1 MiB")); // 1.2 metric QCOMPARE(format.formatByteSize(1024.0, 1, KFormat::JEDECBinaryDialect), QStringLiteral("1.0 KB")); QCOMPARE(format.formatByteSize(1023.0, 1, KFormat::JEDECBinaryDialect), QStringLiteral("1,023 B")); QCOMPARE(format.formatByteSize(1163000.0, 1, KFormat::JEDECBinaryDialect), QStringLiteral("1.1 MB")); QCOMPARE(format.formatByteSize(-1024.0, 1, KFormat::JEDECBinaryDialect), QStringLiteral("-1.0 KB")); QCOMPARE(format.formatByteSize(-1023.0, 1, KFormat::JEDECBinaryDialect), QStringLiteral("-1,023 B")); QCOMPARE(format.formatByteSize(-1163000.0, 1, KFormat::JEDECBinaryDialect), QStringLiteral("-1.1 MB")); QCOMPARE(format.formatByteSize(1024.0, 1, KFormat::MetricBinaryDialect), QStringLiteral("1.0 kB")); QCOMPARE(format.formatByteSize(1023.0, 1, KFormat::MetricBinaryDialect), QStringLiteral("1.0 kB")); QCOMPARE(format.formatByteSize(1163000.0, 1, KFormat::MetricBinaryDialect), QStringLiteral("1.2 MB")); QCOMPARE(format.formatByteSize(-1024.0, 1, KFormat::MetricBinaryDialect), QStringLiteral("-1.0 kB")); QCOMPARE(format.formatByteSize(-1023.0, 1, KFormat::MetricBinaryDialect), QStringLiteral("-1.0 kB")); QCOMPARE(format.formatByteSize(-1163000.0, 1, KFormat::MetricBinaryDialect), QStringLiteral("-1.2 MB")); // Ensure all units are represented QCOMPARE(format.formatByteSize(2.0e9, 1, KFormat::MetricBinaryDialect), QStringLiteral("2.0 GB")); QCOMPARE(format.formatByteSize(3.2e12, 1, KFormat::MetricBinaryDialect), QStringLiteral("3.2 TB")); QCOMPARE(format.formatByteSize(4.1e15, 1, KFormat::MetricBinaryDialect), QStringLiteral("4.1 PB")); QCOMPARE(format.formatByteSize(6.7e18, 2, KFormat::MetricBinaryDialect), QStringLiteral("6.70 EB")); QCOMPARE(format.formatByteSize(5.6e20, 2, KFormat::MetricBinaryDialect), QStringLiteral("560.00 EB")); QCOMPARE(format.formatByteSize(2.3e22, 2, KFormat::MetricBinaryDialect), QStringLiteral("23.00 ZB")); QCOMPARE(format.formatByteSize(1.0e27, 1, KFormat::MetricBinaryDialect), QStringLiteral("1,000.0 YB")); // Spattering of specific units QCOMPARE(format.formatByteSize(823000, 3, KFormat::IECBinaryDialect, KFormat::UnitMegaByte), QStringLiteral("0.785 MiB")); QCOMPARE(format.formatByteSize(1234034.0, 4, KFormat::JEDECBinaryDialect, KFormat::UnitByte), QStringLiteral("1,234,034 B")); // Check examples from the documentation QCOMPARE(format.formatByteSize(1000, 1, KFormat::MetricBinaryDialect, KFormat::UnitKiloByte), QStringLiteral("1.0 kB")); QCOMPARE(format.formatByteSize(1000, 1, KFormat::IECBinaryDialect, KFormat::UnitKiloByte), QStringLiteral("1.0 KiB")); QCOMPARE(format.formatByteSize(1000, 1, KFormat::JEDECBinaryDialect, KFormat::UnitKiloByte), QStringLiteral("1.0 KB")); } void KFormatTest::formatValue() { QLocale locale(QLocale::c()); locale.setNumberOptions(QLocale::DefaultNumberOptions); // Qt >= 5.6 sets QLocale::OmitGroupSeparator for the C locale KFormat format(locale); // Check examples from the documentation QCOMPARE(format.formatValue(1000, KFormat::Unit::Byte, 1, KFormat::UnitPrefix::Kilo, KFormat::MetricBinaryDialect), QStringLiteral("1.0 kB")); QCOMPARE(format.formatValue(1000, KFormat::Unit::Byte, 1, KFormat::UnitPrefix::Kilo, KFormat::IECBinaryDialect), QStringLiteral("1.0 KiB")); QCOMPARE(format.formatValue(1000, KFormat::Unit::Byte, 1, KFormat::UnitPrefix::Kilo, KFormat::JEDECBinaryDialect), QStringLiteral("1.0 KB")); // Check examples from the documentation QCOMPARE(format.formatValue(1000, KFormat::Unit::Bit, 1, KFormat::UnitPrefix::Kilo, KFormat::MetricBinaryDialect), QStringLiteral("1.0 kbit")); QCOMPARE(format.formatValue(1000, QStringLiteral("bit"), 1, KFormat::UnitPrefix::Kilo), QStringLiteral("1.0 kbit")); QCOMPARE(format.formatValue(1000, QStringLiteral("bit/s"), 1, KFormat::UnitPrefix::Kilo), QStringLiteral("1.0 kbit/s")); QCOMPARE(format.formatValue(100, QStringLiteral("bit/s")), QStringLiteral("100.0 bit/s")); QCOMPARE(format.formatValue(1000, QStringLiteral("bit/s")), QStringLiteral("1.0 kbit/s")); QCOMPARE(format.formatValue(10e3, QStringLiteral("bit/s")), QStringLiteral("10.0 kbit/s")); QCOMPARE(format.formatValue(10e6, QStringLiteral("bit/s")), QStringLiteral("10.0 Mbit/s")); QCOMPARE(format.formatValue(0.010, KFormat::Unit::Meter, 1, KFormat::UnitPrefix::Milli, KFormat::MetricBinaryDialect), QStringLiteral("10.0 mm")); QCOMPARE(format.formatValue(10.12e-6, KFormat::Unit::Meter, 2, KFormat::UnitPrefix::Micro, KFormat::MetricBinaryDialect), QStringLiteral("10.12 µm")); QCOMPARE(format.formatValue(10.55e-6, KFormat::Unit::Meter, 1, KFormat::UnitPrefix::AutoAdjust, KFormat::MetricBinaryDialect), QStringLiteral("10.6 µm")); } enum TimeConstants { MSecsInDay = 86400000, MSecsInHour = 3600000, MSecsInMinute = 60000, MSecsInSecond = 1000 }; void KFormatTest::formatDuration() { KFormat format(QLocale::c()); quint64 singleSecond = 3 * MSecsInSecond + 700; quint64 doubleSecond = 33 * MSecsInSecond + 700; quint64 singleMinute = 8 * MSecsInMinute + 3 * MSecsInSecond + 700; quint64 doubleMinute = 38 * MSecsInMinute + 3 * MSecsInSecond + 700; quint64 singleHour = 5 * MSecsInHour + 8 * MSecsInMinute + 3 * MSecsInSecond + 700; quint64 doubleHour = 15 * MSecsInHour + 8 * MSecsInMinute + 3 * MSecsInSecond + 700; quint64 singleDay = 1 * MSecsInDay + 5 * MSecsInHour + 8 * MSecsInMinute + 3 * MSecsInSecond + 700; quint64 doubleDay = 10 * MSecsInDay + 5 * MSecsInHour + 8 * MSecsInMinute + 3 * MSecsInSecond + 700; quint64 roundingIssues = 2* MSecsInHour + 59 * MSecsInMinute + 59 * MSecsInSecond + 900; + quint64 largeValue = 9999999999; // Default format QCOMPARE(format.formatDuration(singleSecond), QStringLiteral("0:00:04")); QCOMPARE(format.formatDuration(doubleSecond), QStringLiteral("0:00:34")); QCOMPARE(format.formatDuration(singleMinute), QStringLiteral("0:08:04")); QCOMPARE(format.formatDuration(doubleMinute), QStringLiteral("0:38:04")); QCOMPARE(format.formatDuration(singleHour), QStringLiteral("5:08:04")); QCOMPARE(format.formatDuration(doubleHour), QStringLiteral("15:08:04")); QCOMPARE(format.formatDuration(singleDay), QStringLiteral("29:08:04")); QCOMPARE(format.formatDuration(doubleDay), QStringLiteral("245:08:04")); QCOMPARE(format.formatDuration(roundingIssues), QStringLiteral("3:00:00")); + QCOMPARE(format.formatDuration(largeValue), QStringLiteral("2777:46:40")); // ShowMilliseconds format KFormat::DurationFormatOptions options = KFormat::ShowMilliseconds; QCOMPARE(format.formatDuration(singleSecond, options), QStringLiteral("0:00:03.700")); QCOMPARE(format.formatDuration(doubleSecond, options), QStringLiteral("0:00:33.700")); QCOMPARE(format.formatDuration(singleMinute, options), QStringLiteral("0:08:03.700")); QCOMPARE(format.formatDuration(doubleMinute, options), QStringLiteral("0:38:03.700")); QCOMPARE(format.formatDuration(singleHour, options), QStringLiteral("5:08:03.700")); QCOMPARE(format.formatDuration(doubleHour, options), QStringLiteral("15:08:03.700")); QCOMPARE(format.formatDuration(singleDay, options), QStringLiteral("29:08:03.700")); QCOMPARE(format.formatDuration(doubleDay, options), QStringLiteral("245:08:03.700")); QCOMPARE(format.formatDuration(roundingIssues, options), QStringLiteral("2:59:59.900")); + QCOMPARE(format.formatDuration(largeValue,options), QStringLiteral("2777:46:39.999")); // HideSeconds format options = KFormat::HideSeconds; QCOMPARE(format.formatDuration(singleSecond, options), QStringLiteral("0:00")); QCOMPARE(format.formatDuration(doubleSecond, options), QStringLiteral("0:01")); QCOMPARE(format.formatDuration(singleMinute, options), QStringLiteral("0:08")); QCOMPARE(format.formatDuration(doubleMinute, options), QStringLiteral("0:38")); QCOMPARE(format.formatDuration(singleHour, options), QStringLiteral("5:08")); QCOMPARE(format.formatDuration(doubleHour, options), QStringLiteral("15:08")); QCOMPARE(format.formatDuration(singleDay, options), QStringLiteral("29:08")); QCOMPARE(format.formatDuration(doubleDay, options), QStringLiteral("245:08")); QCOMPARE(format.formatDuration(roundingIssues, options), QStringLiteral("3:00")); + QCOMPARE(format.formatDuration(largeValue,options), QStringLiteral("2777:47")); // FoldHours format options = KFormat::FoldHours; QCOMPARE(format.formatDuration(singleSecond, options), QStringLiteral("0:04")); QCOMPARE(format.formatDuration(doubleSecond, options), QStringLiteral("0:34")); QCOMPARE(format.formatDuration(singleMinute, options), QStringLiteral("8:04")); QCOMPARE(format.formatDuration(doubleMinute, options), QStringLiteral("38:04")); QCOMPARE(format.formatDuration(singleHour, options), QStringLiteral("308:04")); QCOMPARE(format.formatDuration(doubleHour, options), QStringLiteral("908:04")); QCOMPARE(format.formatDuration(singleDay, options), QStringLiteral("1748:04")); QCOMPARE(format.formatDuration(doubleDay, options), QStringLiteral("14708:04")); QCOMPARE(format.formatDuration(roundingIssues, options), QStringLiteral("180:00")); + QCOMPARE(format.formatDuration(largeValue,options), QStringLiteral("166666:40")); // FoldHours ShowMilliseconds format options = KFormat::FoldHours; options = options | KFormat::ShowMilliseconds; QCOMPARE(format.formatDuration(singleSecond, options), QStringLiteral("0:03.700")); QCOMPARE(format.formatDuration(doubleSecond, options), QStringLiteral("0:33.700")); QCOMPARE(format.formatDuration(singleMinute, options), QStringLiteral("8:03.700")); QCOMPARE(format.formatDuration(doubleMinute, options), QStringLiteral("38:03.700")); QCOMPARE(format.formatDuration(singleHour, options), QStringLiteral("308:03.700")); QCOMPARE(format.formatDuration(doubleHour, options), QStringLiteral("908:03.700")); QCOMPARE(format.formatDuration(singleDay, options), QStringLiteral("1748:03.700")); QCOMPARE(format.formatDuration(doubleDay, options), QStringLiteral("14708:03.700")); QCOMPARE(format.formatDuration(roundingIssues, options), QStringLiteral("179:59.900")); + QCOMPARE(format.formatDuration(largeValue,options), QStringLiteral("166666:39.999")); // InitialDuration format options = KFormat::InitialDuration; QCOMPARE(format.formatDuration(singleSecond, options), QStringLiteral("0h00m04s")); QCOMPARE(format.formatDuration(doubleSecond, options), QStringLiteral("0h00m34s")); QCOMPARE(format.formatDuration(singleMinute, options), QStringLiteral("0h08m04s")); QCOMPARE(format.formatDuration(doubleMinute, options), QStringLiteral("0h38m04s")); QCOMPARE(format.formatDuration(singleHour, options), QStringLiteral("5h08m04s")); QCOMPARE(format.formatDuration(doubleHour, options), QStringLiteral("15h08m04s")); QCOMPARE(format.formatDuration(singleDay, options), QStringLiteral("29h08m04s")); QCOMPARE(format.formatDuration(doubleDay, options), QStringLiteral("245h08m04s")); QCOMPARE(format.formatDuration(roundingIssues, options), QStringLiteral("3h00m00s")); + QCOMPARE(format.formatDuration(largeValue,options), QStringLiteral("2777h46m40s")); // InitialDuration and ShowMilliseconds format options = KFormat::InitialDuration; options = options | KFormat::ShowMilliseconds; QCOMPARE(format.formatDuration(singleSecond, options), QStringLiteral("0h00m03.700s")); QCOMPARE(format.formatDuration(doubleSecond, options), QStringLiteral("0h00m33.700s")); QCOMPARE(format.formatDuration(singleMinute, options), QStringLiteral("0h08m03.700s")); QCOMPARE(format.formatDuration(doubleMinute, options), QStringLiteral("0h38m03.700s")); QCOMPARE(format.formatDuration(singleHour, options), QStringLiteral("5h08m03.700s")); QCOMPARE(format.formatDuration(doubleHour, options), QStringLiteral("15h08m03.700s")); QCOMPARE(format.formatDuration(singleDay, options), QStringLiteral("29h08m03.700s")); QCOMPARE(format.formatDuration(doubleDay, options), QStringLiteral("245h08m03.700s")); QCOMPARE(format.formatDuration(roundingIssues, options), QStringLiteral("2h59m59.900s")); + QCOMPARE(format.formatDuration(largeValue,options), QStringLiteral("2777h46m39.999s")); // InitialDuration and HideSeconds format options = KFormat::InitialDuration; options = options | KFormat::HideSeconds; QCOMPARE(format.formatDuration(singleSecond, options), QStringLiteral("0h00m")); QCOMPARE(format.formatDuration(doubleSecond, options), QStringLiteral("0h01m")); QCOMPARE(format.formatDuration(singleMinute, options), QStringLiteral("0h08m")); QCOMPARE(format.formatDuration(doubleMinute, options), QStringLiteral("0h38m")); QCOMPARE(format.formatDuration(singleHour, options), QStringLiteral("5h08m")); QCOMPARE(format.formatDuration(doubleHour, options), QStringLiteral("15h08m")); QCOMPARE(format.formatDuration(singleDay, options), QStringLiteral("29h08m")); QCOMPARE(format.formatDuration(doubleDay, options), QStringLiteral("245h08m")); QCOMPARE(format.formatDuration(roundingIssues, options), QStringLiteral("3h00m")); + QCOMPARE(format.formatDuration(largeValue,options), QStringLiteral("2777h47m")); // InitialDuration and FoldHours format options = KFormat::InitialDuration; options = options | KFormat::FoldHours; QCOMPARE(format.formatDuration(singleSecond, options), QStringLiteral("0m04s")); QCOMPARE(format.formatDuration(doubleSecond, options), QStringLiteral("0m34s")); QCOMPARE(format.formatDuration(singleMinute, options), QStringLiteral("8m04s")); QCOMPARE(format.formatDuration(doubleMinute, options), QStringLiteral("38m04s")); QCOMPARE(format.formatDuration(singleHour, options), QStringLiteral("308m04s")); QCOMPARE(format.formatDuration(doubleHour, options), QStringLiteral("908m04s")); QCOMPARE(format.formatDuration(singleDay, options), QStringLiteral("1748m04s")); QCOMPARE(format.formatDuration(doubleDay, options), QStringLiteral("14708m04s")); QCOMPARE(format.formatDuration(roundingIssues, options), QStringLiteral("180m00s")); + QCOMPARE(format.formatDuration(largeValue,options), QStringLiteral("166666m40s")); // InitialDuration and FoldHours and ShowMilliseconds format options = KFormat::InitialDuration; options = options | KFormat::FoldHours | KFormat::ShowMilliseconds; QCOMPARE(format.formatDuration(singleSecond, options), QStringLiteral("0m03.700s")); QCOMPARE(format.formatDuration(doubleSecond, options), QStringLiteral("0m33.700s")); QCOMPARE(format.formatDuration(singleMinute, options), QStringLiteral("8m03.700s")); QCOMPARE(format.formatDuration(doubleMinute, options), QStringLiteral("38m03.700s")); QCOMPARE(format.formatDuration(singleHour, options), QStringLiteral("308m03.700s")); QCOMPARE(format.formatDuration(doubleHour, options), QStringLiteral("908m03.700s")); QCOMPARE(format.formatDuration(singleDay, options), QStringLiteral("1748m03.700s")); QCOMPARE(format.formatDuration(doubleDay, options), QStringLiteral("14708m03.700s")); QCOMPARE(format.formatDuration(roundingIssues, options), QStringLiteral("179m59.900s")); + QCOMPARE(format.formatDuration(largeValue,options), QStringLiteral("166666m39.999s")); } void KFormatTest::formatDecimalDuration() { KFormat format(QLocale::c()); QCOMPARE(format.formatDecimalDuration(10), QStringLiteral("10 millisecond(s)")); QCOMPARE(format.formatDecimalDuration(10, 3), QStringLiteral("10 millisecond(s)")); QCOMPARE(format.formatDecimalDuration(1 * MSecsInSecond + 10), QStringLiteral("1.01 seconds")); QCOMPARE(format.formatDecimalDuration(1 * MSecsInSecond + 1, 3), QStringLiteral("1.001 seconds")); QCOMPARE(format.formatDecimalDuration(1 * MSecsInMinute + 10 * MSecsInSecond), QStringLiteral("1.17 minutes")); QCOMPARE(format.formatDecimalDuration(1 * MSecsInMinute + 10 * MSecsInSecond, 3), QStringLiteral("1.167 minutes")); QCOMPARE(format.formatDecimalDuration(1 * MSecsInHour + 10 * MSecsInMinute), QStringLiteral("1.17 hours")); QCOMPARE(format.formatDecimalDuration(1 * MSecsInHour + 10 * MSecsInMinute, 3), QStringLiteral("1.167 hours")); QCOMPARE(format.formatDecimalDuration(1 * MSecsInDay + 10 * MSecsInHour), QStringLiteral("1.42 days")); QCOMPARE(format.formatDecimalDuration(1 * MSecsInDay + 10 * MSecsInHour, 3), QStringLiteral("1.417 days")); } void KFormatTest::formatSpelloutDuration() { KFormat format(QLocale::c()); QCOMPARE(format.formatSpelloutDuration(1000), QStringLiteral("1 second(s)")); QCOMPARE(format.formatSpelloutDuration(5000), QStringLiteral("5 second(s)")); QCOMPARE(format.formatSpelloutDuration(60000), QStringLiteral("1 minute(s)")); QCOMPARE(format.formatSpelloutDuration(300000), QStringLiteral("5 minute(s)")); QCOMPARE(format.formatSpelloutDuration(3600000), QStringLiteral("1 hour(s)")); QCOMPARE(format.formatSpelloutDuration(18000000), QStringLiteral("5 hour(s)")); QCOMPARE(format.formatSpelloutDuration(75000), QStringLiteral("1 minute(s) and 15 second(s)")); // Problematic case #1 (there is a reference to this case on kformat.cpp) QCOMPARE(format.formatSpelloutDuration(119999), QStringLiteral("2 minute(s)")); // This case is strictly 2 hours, 15 minutes and 59 seconds. However, since the range is // pretty high between hours and seconds, formatSpelloutDuration always omits seconds when there // are hours in scene. QCOMPARE(format.formatSpelloutDuration(8159000), QStringLiteral("2 hour(s) and 15 minute(s)")); // This case is strictly 1 hour and 10 seconds. For the same reason, formatSpelloutDuration // detects that 10 seconds is just garbage compared to 1 hour, and omits it on the result. QCOMPARE(format.formatSpelloutDuration(3610000), QStringLiteral("1 hour(s)")); } void KFormatTest::formatRelativeDate() { KFormat format(QLocale::c()); QDate testDate = QDate::currentDate(); QCOMPARE(format.formatRelativeDate(testDate, QLocale::LongFormat), QStringLiteral("Today")); QCOMPARE(format.formatRelativeDate(testDate, QLocale::ShortFormat), QStringLiteral("Today")); QCOMPARE(format.formatRelativeDate(testDate, QLocale::NarrowFormat), QStringLiteral("Today")); testDate = QDate::currentDate().addDays(1); QCOMPARE(format.formatRelativeDate(testDate, QLocale::LongFormat), QStringLiteral("Tomorrow")); QCOMPARE(format.formatRelativeDate(testDate, QLocale::ShortFormat), QStringLiteral("Tomorrow")); QCOMPARE(format.formatRelativeDate(testDate, QLocale::NarrowFormat), QStringLiteral("Tomorrow")); testDate = QDate::currentDate().addDays(-1); QCOMPARE(format.formatRelativeDate(testDate, QLocale::LongFormat), QStringLiteral("Yesterday")); QCOMPARE(format.formatRelativeDate(testDate, QLocale::ShortFormat), QStringLiteral("Yesterday")); QCOMPARE(format.formatRelativeDate(testDate, QLocale::NarrowFormat), QStringLiteral("Yesterday")); // Relative dates within a week are up to translators but there's no // expectation that day names are shortened -- per the API docs, the date // format is only used when the date is outside the relative window testDate = QDate::currentDate().addDays(-7); QCOMPARE(format.formatRelativeDate(testDate, QLocale::LongFormat), QStringLiteral("Last %1").arg(QLocale::c().dayName(testDate.dayOfWeek(), QLocale::LongFormat))); QCOMPARE(format.formatRelativeDate(testDate, QLocale::ShortFormat), QStringLiteral("Last %1").arg(QLocale::c().dayName(testDate.dayOfWeek(), QLocale::LongFormat))); QCOMPARE(format.formatRelativeDate(testDate, QLocale::NarrowFormat), QStringLiteral("Last %1").arg(QLocale::c().dayName(testDate.dayOfWeek(), QLocale::LongFormat))); testDate = QDate::currentDate().addDays(7); QCOMPARE(format.formatRelativeDate(testDate, QLocale::LongFormat), QStringLiteral("Next %1").arg(QLocale::c().dayName(testDate.dayOfWeek(), QLocale::LongFormat))); QCOMPARE(format.formatRelativeDate(testDate, QLocale::ShortFormat), QStringLiteral("Next %1").arg(QLocale::c().dayName(testDate.dayOfWeek(), QLocale::LongFormat))); QCOMPARE(format.formatRelativeDate(testDate, QLocale::NarrowFormat), QStringLiteral("Next %1").arg(QLocale::c().dayName(testDate.dayOfWeek(), QLocale::LongFormat))); testDate = QDate::currentDate().addDays(-8); QCOMPARE(format.formatRelativeDate(testDate, QLocale::LongFormat), QLocale::c().toString(testDate, QLocale::LongFormat)); QCOMPARE(format.formatRelativeDate(testDate, QLocale::ShortFormat), QLocale::c().toString(testDate, QLocale::ShortFormat)); QCOMPARE(format.formatRelativeDate(testDate, QLocale::NarrowFormat), QLocale::c().toString(testDate, QLocale::NarrowFormat)); testDate = QDate::currentDate().addDays(8); QCOMPARE(format.formatRelativeDate(testDate, QLocale::LongFormat), QLocale::c().toString(testDate, QLocale::LongFormat)); QCOMPARE(format.formatRelativeDate(testDate, QLocale::ShortFormat), QLocale::c().toString(testDate, QLocale::ShortFormat)); QCOMPARE(format.formatRelativeDate(testDate, QLocale::NarrowFormat), QLocale::c().toString(testDate, QLocale::NarrowFormat)); testDate = QDate(); // invalid date QCOMPARE(format.formatRelativeDate(testDate, QLocale::LongFormat), QStringLiteral("Invalid date")); QDateTime testDateTime = QDateTime(QDate::currentDate(), QTime(3, 0, 0)); QCOMPARE(format.formatRelativeDateTime(testDateTime, QLocale::ShortFormat), QStringLiteral("Today, 03:00:00")); testDateTime = QDateTime(QDate::currentDate().addDays(8), QTime(3, 0, 0)); QCOMPARE(format.formatRelativeDateTime(testDateTime, QLocale::LongFormat), QLocale::c().toString(testDateTime, QLocale::LongFormat)); } QTEST_MAIN(KFormatTest) diff --git a/src/lib/util/kformatprivate.cpp b/src/lib/util/kformatprivate.cpp index e6a29f0..ffbd9f0 100644 --- a/src/lib/util/kformatprivate.cpp +++ b/src/lib/util/kformatprivate.cpp @@ -1,577 +1,577 @@ /* This file is part of the KDE Frameworks Copyright (C) 2013 Alex Merry Copyright (C) 2013 John Layt Copyright (C) 2010 Michael Leupold Copyright (C) 2009 Michael Pyne Copyright (C) 2008 Albert Astals Cid This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kformatprivate_p.h" #include #include KFormatPrivate::KFormatPrivate(const QLocale &locale) { m_locale = locale; } KFormatPrivate::~KFormatPrivate() { } constexpr double bpow(int exp) { return (exp > 0) ? 2.0 * bpow(exp - 1) : (exp < 0) ? 0.5 * bpow(exp + 1) : 1.0; } QString KFormatPrivate::formatValue(double value, KFormat::Unit unit, QString unitString, int precision, KFormat::UnitPrefix prefix, KFormat::BinaryUnitDialect dialect) const { if (dialect <= KFormat::DefaultBinaryDialect || dialect > KFormat::LastBinaryDialect) { dialect = KFormat::IECBinaryDialect; } if (static_cast(prefix) < static_cast(KFormat::UnitPrefix::Yocto) || static_cast(prefix) > static_cast(KFormat::UnitPrefix::Yotta)) { prefix = KFormat::UnitPrefix::AutoAdjust; } double multiplier = 1024.0; if (dialect == KFormat::MetricBinaryDialect) { multiplier = 1000.0; } int power = 0; if (prefix == KFormat::UnitPrefix::AutoAdjust) { double adjustValue = qAbs(value); while (adjustValue >= multiplier) { adjustValue /= multiplier; power += 1; } while (adjustValue && adjustValue < 1.0) { adjustValue *= multiplier; power -= 1; } const KFormat::UnitPrefix map[] = { KFormat::UnitPrefix::Yocto, // -8 KFormat::UnitPrefix::Zepto, KFormat::UnitPrefix::Atto, KFormat::UnitPrefix::Femto, KFormat::UnitPrefix::Pico, KFormat::UnitPrefix::Nano, KFormat::UnitPrefix::Micro, KFormat::UnitPrefix::Milli, KFormat::UnitPrefix::Unity, // 0 KFormat::UnitPrefix::Kilo, KFormat::UnitPrefix::Mega, KFormat::UnitPrefix::Giga, KFormat::UnitPrefix::Tera, KFormat::UnitPrefix::Peta, KFormat::UnitPrefix::Exa, KFormat::UnitPrefix::Zetta, KFormat::UnitPrefix::Yotta, // 8 }; power = std::max(-8, std::min(8, power)); prefix = map[power + 8]; } if (prefix == KFormat::UnitPrefix::Unity && unit == KFormat::Unit::Byte) { precision = 0; } struct PrefixMapEntry { KFormat::UnitPrefix prefix; double decimalFactor; double binaryFactor; QChar prefixChar; }; const PrefixMapEntry map[] = { { KFormat::UnitPrefix::Yocto, 1e-24, bpow(-80), u'y' }, { KFormat::UnitPrefix::Zepto, 1e-21, bpow(-70), u'z' }, { KFormat::UnitPrefix::Atto, 1e-18, bpow(-60), u'a' }, { KFormat::UnitPrefix::Femto, 1e-15, bpow(-50), u'f' }, { KFormat::UnitPrefix::Pico, 1e-12, bpow(-40), u'p' }, { KFormat::UnitPrefix::Nano, 1e-9, bpow(-30), u'n' }, // Thanks to broken MSVC, we can not use u'µ', but have to use the unicode codepoint { KFormat::UnitPrefix::Micro, 1e-6, bpow(-20), QChar(0xB5) }, { KFormat::UnitPrefix::Milli, 1e-3, bpow(-10), u'm' }, { KFormat::UnitPrefix::Unity, 1.0, 1.0, u'\0' }, { KFormat::UnitPrefix::Kilo, 1e3, bpow(10), u'k' }, { KFormat::UnitPrefix::Mega, 1e6, bpow(20), u'M' }, { KFormat::UnitPrefix::Giga, 1e9, bpow(30), u'G' }, { KFormat::UnitPrefix::Tera, 1e12, bpow(40), u'T' }, { KFormat::UnitPrefix::Peta, 1e15, bpow(50), u'P' }, { KFormat::UnitPrefix::Exa, 1e18, bpow(60), u'E' }, { KFormat::UnitPrefix::Zetta, 1e21, bpow(70), u'Z' }, { KFormat::UnitPrefix::Yotta, 1e24, bpow(80), u'Y' }, }; auto entry = std::find_if(std::begin(map), std::end(map), [prefix](const PrefixMapEntry& e) { return e.prefix == prefix; }); switch (unit) { case KFormat::Unit::Bit: unitString = QStringLiteral("bit"); break; case KFormat::Unit::Byte: unitString = QStringLiteral("B"); break; case KFormat::Unit::Meter: unitString = QStringLiteral("m"); break; case KFormat::Unit::Hertz: unitString = QStringLiteral("Hz"); break; case KFormat::Unit::Other: break; } if (prefix == KFormat::UnitPrefix::Unity) { QString numString = m_locale.toString(value, 'f', precision); //: value without prefix, format " " return tr("%1 %2", "no Prefix").arg(numString, unitString); } QString prefixString; if (dialect == KFormat::MetricBinaryDialect) { value /= entry->decimalFactor; prefixString = entry->prefixChar; } else { value /= entry->binaryFactor; prefixString = QString(entry->prefixChar).toUpper(); if (dialect == KFormat::IECBinaryDialect) { prefixString += u'i'; } } QString numString = m_locale.toString(value, 'f', precision); //: value with prefix, format " " return tr("%1 %2%3", "MetricBinaryDialect").arg(numString, prefixString, unitString); } QString KFormatPrivate::formatByteSize(double size, int precision, KFormat::BinaryUnitDialect dialect, KFormat::BinarySizeUnits units) const { // Current KDE default is IECBinaryDialect if (dialect <= KFormat::DefaultBinaryDialect || dialect > KFormat::LastBinaryDialect) { dialect = KFormat::IECBinaryDialect; } // Current KDE default is to auto-adjust so the size falls in the range 0 to 1000/1024 if (units < KFormat::DefaultBinaryUnits || units > KFormat::UnitLastUnit) { units = KFormat::DefaultBinaryUnits; } int unit = 0; // Selects what unit to use double multiplier = 1024.0; if (dialect == KFormat::MetricBinaryDialect) { multiplier = 1000.0; } // If a specific unit conversion is given, use it directly. Otherwise // search until the result is in [0, multiplier] (or out of our range). if (units == KFormat::DefaultBinaryUnits) { while (qAbs(size) >= multiplier && unit < int(KFormat::UnitYottaByte)) { size /= multiplier; ++unit; } } else { // A specific unit is in use unit = static_cast(units); if (unit > 0) { size /= pow(multiplier, unit); } } // Bytes, no rounding if (unit == 0) { precision = 0; } QString numString = m_locale.toString(size, 'f', precision); // Do not remove "//:" comments below, they are used by the translators. // NB: we cannot pass pluralization arguments, as the size may be negative if (dialect == KFormat::MetricBinaryDialect) { switch (unit) { case KFormat::UnitByte: //: MetricBinaryDialect size in bytes return tr("%1 B", "MetricBinaryDialect").arg(numString); case KFormat::UnitKiloByte: //: MetricBinaryDialect size in 1000 bytes return tr("%1 kB", "MetricBinaryDialect").arg(numString); case KFormat::UnitMegaByte: //: MetricBinaryDialect size in 10^6 bytes return tr("%1 MB", "MetricBinaryDialect").arg(numString); case KFormat::UnitGigaByte: //: MetricBinaryDialect size in 10^9 bytes return tr("%1 GB", "MetricBinaryDialect").arg(numString); case KFormat::UnitTeraByte: //: MetricBinaryDialect size in 10^12 bytes return tr("%1 TB", "MetricBinaryDialect").arg(numString); case KFormat::UnitPetaByte: //: MetricBinaryDialect size in 10^15 bytes return tr("%1 PB", "MetricBinaryDialect").arg(numString); case KFormat::UnitExaByte: //: MetricBinaryDialect size in 10^18 byte return tr("%1 EB", "MetricBinaryDialect").arg(numString); case KFormat::UnitZettaByte: //: MetricBinaryDialect size in 10^21 bytes return tr("%1 ZB", "MetricBinaryDialect").arg(numString); case KFormat::UnitYottaByte: //: MetricBinaryDialect size in 10^24 bytes return tr("%1 YB", "MetricBinaryDialect").arg(numString); } } else if (dialect == KFormat::JEDECBinaryDialect) { switch (unit) { case KFormat::UnitByte: //: JEDECBinaryDialect memory size in bytes return tr("%1 B", "JEDECBinaryDialect").arg(numString); case KFormat::UnitKiloByte: //: JEDECBinaryDialect memory size in 1024 bytes return tr("%1 KB", "JEDECBinaryDialect").arg(numString); case KFormat::UnitMegaByte: //: JEDECBinaryDialect memory size in 10^20 bytes return tr("%1 MB", "JEDECBinaryDialect").arg(numString); case KFormat::UnitGigaByte: //: JEDECBinaryDialect memory size in 10^30 bytes return tr("%1 GB", "JEDECBinaryDialect").arg(numString); case KFormat::UnitTeraByte: //: JEDECBinaryDialect memory size in 10^40 bytes return tr("%1 TB", "JEDECBinaryDialect").arg(numString); case KFormat::UnitPetaByte: //: JEDECBinaryDialect memory size in 10^50 bytes return tr("%1 PB", "JEDECBinaryDialect").arg(numString); case KFormat::UnitExaByte: //: JEDECBinaryDialect memory size in 10^60 bytes return tr("%1 EB", "JEDECBinaryDialect").arg(numString); case KFormat::UnitZettaByte: //: JEDECBinaryDialect memory size in 10^70 bytes return tr("%1 ZB", "JEDECBinaryDialect").arg(numString); case KFormat::UnitYottaByte: //: JEDECBinaryDialect memory size in 10^80 bytes return tr("%1 YB", "JEDECBinaryDialect").arg(numString); } } else { // KFormat::IECBinaryDialect, KFormat::DefaultBinaryDialect switch (unit) { case KFormat::UnitByte: //: IECBinaryDialect size in bytes return tr("%1 B", "IECBinaryDialect").arg(numString); case KFormat::UnitKiloByte: //: IECBinaryDialect size in 1024 bytes return tr("%1 KiB", "IECBinaryDialect").arg(numString); case KFormat::UnitMegaByte: //: IECBinaryDialect size in 10^20 bytes return tr("%1 MiB", "IECBinaryDialect").arg(numString); case KFormat::UnitGigaByte: //: IECBinaryDialect size in 10^30 bytes return tr("%1 GiB", "IECBinaryDialect").arg(numString); case KFormat::UnitTeraByte: //: IECBinaryDialect size in 10^40 bytes return tr("%1 TiB", "IECBinaryDialect").arg(numString); case KFormat::UnitPetaByte: //: IECBinaryDialect size in 10^50 bytes return tr("%1 PiB", "IECBinaryDialect").arg(numString); case KFormat::UnitExaByte: //: IECBinaryDialect size in 10^60 bytes return tr("%1 EiB", "IECBinaryDialect").arg(numString); case KFormat::UnitZettaByte: //: IECBinaryDialect size in 10^70 bytes return tr("%1 ZiB", "IECBinaryDialect").arg(numString); case KFormat::UnitYottaByte: //: IECBinaryDialect size in 10^80 bytes return tr("%1 YiB", "IECBinaryDialect").arg(numString); } } // Should never reach here Q_ASSERT(false); return numString; } enum TimeConstants { MSecsInDay = 86400000, MSecsInHour = 3600000, MSecsInMinute = 60000, MSecsInSecond = 1000 }; QString KFormatPrivate::formatDuration(quint64 msecs, KFormat::DurationFormatOptions options) const { quint64 ms = msecs; if (options & KFormat::HideSeconds) { //round to nearest minute - ms = qRound(ms / (qreal)MSecsInMinute) * MSecsInMinute ; + ms = qRound64(ms / (qreal)MSecsInMinute) * MSecsInMinute ; } else if (!(options & KFormat::ShowMilliseconds)) { //round to nearest second - ms = qRound(ms / (qreal)MSecsInSecond) * MSecsInSecond ; + ms = qRound64(ms / (qreal)MSecsInSecond) * MSecsInSecond ; } int hours = ms / MSecsInHour; ms = ms % MSecsInHour; int minutes = ms / MSecsInMinute; ms = ms % MSecsInMinute; int seconds = ms / MSecsInSecond; ms = ms % MSecsInSecond; if ((options & KFormat::InitialDuration) == KFormat::InitialDuration) { if ((options & KFormat::FoldHours) == KFormat::FoldHours && (options & KFormat::ShowMilliseconds) == KFormat::ShowMilliseconds) { //: @item:intext Duration format minutes, seconds and milliseconds return tr("%1m%2.%3s").arg(hours * 60 + minutes, 1, 10, QLatin1Char('0')) .arg(seconds, 2, 10, QLatin1Char('0')) .arg(ms, 3, 10, QLatin1Char('0')); } else if ((options & KFormat::FoldHours) == KFormat::FoldHours) { //: @item:intext Duration format minutes and seconds return tr("%1m%2s").arg(hours * 60 + minutes, 1, 10, QLatin1Char('0')) .arg(seconds, 2, 10, QLatin1Char('0')); } else if ((options & KFormat::HideSeconds) == KFormat::HideSeconds) { //: @item:intext Duration format hours and minutes return tr("%1h%2m").arg(hours, 1, 10, QLatin1Char('0')) .arg(minutes, 2, 10, QLatin1Char('0')); } else if ((options & KFormat::ShowMilliseconds) == KFormat::ShowMilliseconds) { //: @item:intext Duration format hours, minutes, seconds, milliseconds return tr("%1h%2m%3.%4s").arg(hours, 1, 10, QLatin1Char('0')) .arg(minutes, 2, 10, QLatin1Char('0')) .arg(seconds, 2, 10, QLatin1Char('0')) .arg(ms, 3, 10, QLatin1Char('0')); } else { // Default //: @item:intext Duration format hours, minutes, seconds return tr("%1h%2m%3s").arg(hours, 1, 10, QLatin1Char('0')) .arg(minutes, 2, 10, QLatin1Char('0')) .arg(seconds, 2, 10, QLatin1Char('0')); } } else { if ((options & KFormat::FoldHours) == KFormat::FoldHours && (options & KFormat::ShowMilliseconds) == KFormat::ShowMilliseconds) { //: @item:intext Duration format minutes, seconds and milliseconds return tr("%1:%2.%3").arg(hours * 60 + minutes, 1, 10, QLatin1Char('0')) .arg(seconds, 2, 10, QLatin1Char('0')) .arg(ms, 3, 10, QLatin1Char('0')); } else if ((options & KFormat::FoldHours) == KFormat::FoldHours) { //: @item:intext Duration format minutes and seconds return tr("%1:%2").arg(hours * 60 + minutes, 1, 10, QLatin1Char('0')) .arg(seconds, 2, 10, QLatin1Char('0')); } else if ((options & KFormat::HideSeconds) == KFormat::HideSeconds) { //: @item:intext Duration format hours and minutes return tr("%1:%2").arg(hours, 1, 10, QLatin1Char('0')) .arg(minutes, 2, 10, QLatin1Char('0')); } else if ((options & KFormat::ShowMilliseconds) == KFormat::ShowMilliseconds) { //: @item:intext Duration format hours, minutes, seconds, milliseconds return tr("%1:%2:%3.%4").arg(hours, 1, 10, QLatin1Char('0')) .arg(minutes, 2, 10, QLatin1Char('0')) .arg(seconds, 2, 10, QLatin1Char('0')) .arg(ms, 3, 10, QLatin1Char('0')); } else { // Default //: @item:intext Duration format hours, minutes, seconds return tr("%1:%2:%3").arg(hours, 1, 10, QLatin1Char('0')) .arg(minutes, 2, 10, QLatin1Char('0')) .arg(seconds, 2, 10, QLatin1Char('0')); } } Q_UNREACHABLE(); return QString(); } QString KFormatPrivate::formatDecimalDuration(quint64 msecs, int decimalPlaces) const { if (msecs >= MSecsInDay) { //: @item:intext %1 is a real number, e.g. 1.23 days return tr("%1 days").arg(m_locale.toString(msecs / (MSecsInDay * 1.0), 'f', decimalPlaces)); } else if (msecs >= MSecsInHour) { //: @item:intext %1 is a real number, e.g. 1.23 hours return tr("%1 hours").arg(m_locale.toString(msecs / (MSecsInHour * 1.0), 'f', decimalPlaces)); } else if (msecs >= MSecsInMinute) { //: @item:intext %1 is a real number, e.g. 1.23 minutes return tr("%1 minutes").arg(m_locale.toString(msecs / (MSecsInMinute * 1.0), 'f', decimalPlaces)); } else if (msecs >= MSecsInSecond) { //: @item:intext %1 is a real number, e.g. 1.23 seconds return tr("%1 seconds").arg(m_locale.toString(msecs / (MSecsInSecond * 1.0), 'f', decimalPlaces)); } //: @item:intext %1 is a whole number //~ singular %n millisecond //~ plural %n milliseconds return tr("%n millisecond(s)", nullptr, msecs); } enum DurationUnits { Days = 0, Hours, Minutes, Seconds }; static QString formatSingleDuration(DurationUnits units, int n) { // NB: n is guaranteed to be non-negative switch (units) { case Days: //: @item:intext %n is a whole number //~ singular %n day //~ plural %n days return KFormatPrivate::tr("%n day(s)", nullptr, n); case Hours: //: @item:intext %n is a whole number //~ singular %n hour //~ plural %n hours return KFormatPrivate::tr("%n hour(s)", nullptr, n); case Minutes: //: @item:intext %n is a whole number //~ singular %n minute //~ plural %n minutes return KFormatPrivate::tr("%n minute(s)", nullptr, n); case Seconds: //: @item:intext %n is a whole number //~ singular %n second //~ plural %n seconds return KFormatPrivate::tr("%n second(s)", nullptr, n); } Q_ASSERT(false); return QString(); } QString KFormatPrivate::formatSpelloutDuration(quint64 msecs) const { quint64 ms = msecs; int days = ms / MSecsInDay; ms = ms % (MSecsInDay); int hours = ms / MSecsInHour; ms = ms % MSecsInHour; int minutes = ms / MSecsInMinute; ms = ms % MSecsInMinute; int seconds = qRound(ms / 1000.0); // Handle correctly problematic case #1 (look at KFormatTest::prettyFormatDuration()) if (seconds == 60) { return formatSpelloutDuration(msecs - ms + MSecsInMinute); } if (days && hours) { /*: @item:intext days and hours. This uses the previous item:intext messages. If this does not fit the grammar of your language please contact the i18n team to solve the problem */ return tr("%1 and %2").arg(formatSingleDuration(Days, days)) .arg(formatSingleDuration(Hours, hours)); } else if (days) { return formatSingleDuration(Days, days); } else if (hours && minutes) { /*: @item:intext hours and minutes. This uses the previous item:intext messages. If this does not fit the grammar of your language please contact the i18n team to solve the problem */ return tr("%1 and %2").arg(formatSingleDuration(Hours, hours)) .arg(formatSingleDuration(Minutes, minutes)); } else if (hours) { return formatSingleDuration(Hours, hours); } else if (minutes && seconds) { /*: @item:intext minutes and seconds. This uses the previous item:intext messages. If this does not fit the grammar of your language please contact the i18n team to solve the problem */ return tr("%1 and %2").arg(formatSingleDuration(Minutes, minutes)) .arg(formatSingleDuration(Seconds, seconds)); } else if (minutes) { return formatSingleDuration(Minutes, minutes); } else { return formatSingleDuration(Seconds, seconds); } } QString KFormatPrivate::formatRelativeDate(const QDate &date, QLocale::FormatType format) const { if (!date.isValid()) { return tr("Invalid date", "used when a relative date string can't be generated because the date is invalid"); } const qint64 daysTo = QDate::currentDate().daysTo(date); if (daysTo > 7 || daysTo < -7) { return m_locale.toString(date, format); } switch (daysTo) { case 1: return tr("Tomorrow"); case 0: return tr("Today"); case -1: return tr("Yesterday"); } if (daysTo < -1) { switch (date.dayOfWeek()) { case 1: return tr("Last Monday", "most recent such day before today"); case 2: return tr("Last Tuesday", "most recent such day before today"); case 3: return tr("Last Wednesday", "most recent such day before today"); case 4: return tr("Last Thursday", "most recent such day before today"); case 5: return tr("Last Friday", "most recent such day before today"); case 6: return tr("Last Saturday", "most recent such day before today"); case 7: return tr("Last Sunday", "most recent such day before today"); } } else if (daysTo > 1) { switch (date.dayOfWeek()) { case 1: return tr("Next Monday", "the next such day after today"); case 2: return tr("Next Tuesday", "the next such day after today"); case 3: return tr("Next Wednesday", "the next such day after today"); case 4: return tr("Next Thursday", "the next such day after today"); case 5: return tr("Next Friday", "the next such day after today"); case 6: return tr("Next Saturday", "the next such day after today"); case 7: return tr("Next Sunday", "the next such day after today"); } } Q_UNREACHABLE(); } QString KFormatPrivate::formatRelativeDateTime(const QDateTime &dateTime, QLocale::FormatType format) const { const qint64 daysTo = QDate::currentDate().daysTo(dateTime.date()); if (daysTo > 7 || daysTo < -7) { return m_locale.toString(dateTime, format); } /*: relative datetime with %1 result of formatReleativeDate() and %2 the formatted time If this does not fit the grammar of your language please contact the i18n team to solve the problem */ return tr("%1, %2").arg(formatRelativeDate(dateTime.date(), format)) .arg(m_locale.toString(dateTime.time(), format)); }