File indexing completed on 2024-05-12 03:54:59

0001 /*
0002     This file is part of the KDE Frameworks
0003 
0004     SPDX-FileCopyrightText: 2013 Alex Merry <alex.merry@kdemail.net>
0005     SPDX-FileCopyrightText: 2013 John Layt <jlayt@kde.org>
0006     SPDX-FileCopyrightText: 2010 Michael Leupold <lemma@confuego.org>
0007     SPDX-FileCopyrightText: 2009 Michael Pyne <mpyne@kde.org>
0008     SPDX-FileCopyrightText: 2008 Albert Astals Cid <aacid@kde.org>
0009 
0010     SPDX-License-Identifier: LGPL-2.0-or-later
0011 */
0012 
0013 #ifndef KFORMAT_H
0014 #define KFORMAT_H
0015 
0016 #include <kcoreaddons_export.h>
0017 
0018 #include <QLocale>
0019 #include <QSharedPointer>
0020 #include <QString>
0021 
0022 class QDate;
0023 class QDateTime;
0024 
0025 class KFormatPrivate;
0026 
0027 /**
0028  * \file kformat.h
0029  */
0030 
0031 /*
0032    The code in this class was copied from the old KLocale and modified
0033    by John Layt (and also Alex Merry) in the KDELIBS 4 to KDE
0034    Frameworks 5 transition in 2013.
0035 
0036    Albert Astals Cid is the original author of formatSpelloutDuration()
0037    originally named KLocale::prettyFormatDuration().
0038 
0039    Michael Pyne is the original author of formatByteSize().
0040 
0041    Michael Leupold is the original author of formatRelativeDate(()
0042    originally part of KFormat::formatDate().
0043 */
0044 
0045 /**
0046  * @class KFormat kformat.h KFormat
0047  *
0048  * KFormat provides support for formatting numbers and datetimes in
0049  * formats that are not supported by QLocale.
0050  *
0051  * @author John Layt <jlayt@kde.org>,
0052  *         Michael Pyne <mpyne@kde.org>,
0053  *         Albert Astals Cid <aacid@kde.org>,
0054  *
0055  * @short Class for formatting numbers and datetimes.
0056  * @since 5.0
0057  */
0058 class KCOREADDONS_EXPORT KFormat final
0059 {
0060     Q_GADGET
0061 
0062 public:
0063     /**
0064      * These binary units are used in KDE by the formatByteSize()
0065      * function.
0066      *
0067      * NOTE: There are several different units standards:
0068      * 1) SI  (i.e. metric), powers-of-10.
0069      * 2) IEC, powers-of-2, with specific units KiB, MiB, etc.
0070      * 3) JEDEC, powers-of-2, used for solid state memory sizing which
0071      *    is why you see flash cards labels as e.g. 4GB.  These (ab)use
0072      *    the metric units.  Although JEDEC only defines KB, MB, GB, if
0073      *    JEDEC is selected all units will be powers-of-2 with metric
0074      *    prefixes for clarity in the event of sizes larger than 1024 GB.
0075      *
0076      * Although 3 different dialects are possible this enum only uses
0077      * metric names since adding all 3 different names of essentially the same
0078      * unit would be pointless.  Use BinaryUnitDialect to control the exact
0079      * units returned.
0080      *
0081      * @see BinaryUnitDialect
0082      * @see formatByteSize
0083      */
0084     enum BinarySizeUnits {
0085         /// Auto-choose a unit such that the result is in the range [0, 1000 or 1024)
0086         DefaultBinaryUnits = -1,
0087 
0088         // The first real unit must be 0 for the current implementation!
0089         UnitByte, ///<  B         1 byte
0090         UnitKiloByte, ///<  KiB/KB/kB 1024/1000 bytes.
0091         UnitMegaByte, ///<  MiB/MB/MB 2^20/10^06 bytes.
0092         UnitGigaByte, ///<  GiB/GB/GB 2^30/10^09 bytes.
0093         UnitTeraByte, ///<  TiB/TB/TB 2^40/10^12 bytes.
0094         UnitPetaByte, ///<  PiB/PB/PB 2^50/10^15 bytes.
0095         UnitExaByte, ///<  EiB/EB/EB 2^60/10^18 bytes.
0096         UnitZettaByte, ///<  ZiB/ZB/ZB 2^70/10^21 bytes.
0097         UnitYottaByte, ///<  YiB/YB/YB 2^80/10^24 bytes.
0098         UnitLastUnit = UnitYottaByte,
0099     };
0100 
0101     /**
0102      * These units are used in KDE by the formatValue() function.
0103      *
0104      * @see formatValue
0105      * @since 5.49
0106      */
0107     enum class Unit {
0108         Other,
0109         Bit, ///< "bit"
0110         Byte, ///< "B"
0111         Meter, ///< "m"
0112         Hertz, ///< "Hz"
0113     };
0114 
0115     /**
0116      * These prefixes are used in KDE by the formatValue()
0117      * function.
0118      *
0119      * IEC prefixes are only defined for integral units of information, e.g.
0120      * bits and bytes.
0121      *
0122      * @see BinarySizeUnits
0123      * @see formatValue
0124      * @since 5.49
0125      */
0126     enum class UnitPrefix {
0127         /// Auto-choose a unit such that the result is in the range [0, 1000 or 1024)
0128         AutoAdjust = -128,
0129 
0130         Yocto = 0, ///<  --/-/y  10^-24
0131         Zepto, ///<  --/-/z  10^-21
0132         Atto, ///<  --/-/a  10^-18
0133         Femto, ///<  --/-/f  10^-15
0134         Pico, ///<  --/-/p  10^-12
0135         Nano, ///<  --/-/n  10^-9
0136         Micro, ///<  --/-/ยต  10^-6
0137         Milli, ///<  --/-/m  10^-3
0138         Centi, ///<  --/-/c  0.01
0139         Deci, ///<  --/-/d  0.1
0140         Unity, ///<  ""      1
0141         Deca, ///<  --/-/da 10
0142         Hecto, ///<  --/-/h  100
0143         Kilo, ///<  Ki/K/k  1024/1000
0144         Mega, ///<  Mi/M/M  2^20/10^06
0145         Giga, ///<  Gi/G/G  2^30/10^09
0146         Tera, ///<  Ti/T/T  2^40/10^12
0147         Peta, ///<  Pi/P/P  2^50/10^15
0148         Exa, ///<  Ei/E/E  2^60/10^18
0149         Zetta, ///<  Zi/Z/Z  2^70/10^21
0150         Yotta, ///<  Yi/Y/Y  2^80/10^24
0151     };
0152 
0153     /**
0154      * This enum chooses what dialect is used for binary units.
0155      *
0156      * Note: Although JEDEC abuses the metric prefixes and can therefore be
0157      * confusing, it has been used to describe *memory* sizes for quite some time
0158      * and programs should therefore use either Default, JEDEC, or IEC 60027-2
0159      * for memory sizes.
0160      *
0161      * On the other hand network transmission rates are typically in metric so
0162      * Default, Metric, or IEC (which is unambiguous) should be chosen.
0163      *
0164      * Normally choosing DefaultBinaryDialect is the best option as that uses
0165      * the user's selection for units.  If the user has not selected a preference,
0166      * IECBinaryDialect will typically be used.
0167      *
0168      * @see BinarySizeUnits
0169      * @see formatByteSize
0170      */
0171     enum BinaryUnitDialect {
0172         DefaultBinaryDialect = -1, ///< Used if no specific preference
0173         IECBinaryDialect, ///< KiB, MiB, etc. 2^(10*n)
0174         JEDECBinaryDialect, ///< KB, MB, etc. 2^(10*n)
0175         MetricBinaryDialect, ///< SI Units, kB, MB, etc. 10^(3*n)
0176         LastBinaryDialect = MetricBinaryDialect,
0177     };
0178 
0179     /**
0180      * Format flags for formatDuration()
0181      * @see DurationFormatOptions
0182      */
0183     enum DurationFormatOption {
0184         DefaultDuration = 0x0, ///< Default formatting in localized 1:23:45 format
0185         InitialDuration = 0x1, ///< Default formatting in localized 1h23m45s format
0186         ShowMilliseconds = 0x2, ///< Include milliseconds in format, e.g. 1:23:45.678
0187         HideSeconds = 0x4, ///< Hide the seconds, e.g. 1:23 or 1h23m, overrides ShowMilliseconds
0188         FoldHours = 0x8, ///< Fold the hours into the minutes, e.g. 83:45 or 83m45s, overrides HideSeconds
0189     };
0190     /**
0191      * Stores a combination of #DurationFormatOption values.
0192      */
0193     Q_DECLARE_FLAGS(DurationFormatOptions, DurationFormatOption)
0194     Q_FLAG(DurationFormatOption)
0195 
0196     /**
0197      * Constructs a KFormat.
0198      *
0199      * @param locale the locale to use, defaults to the system locale
0200      */
0201     explicit KFormat(const QLocale &locale = QLocale());
0202 
0203     /**
0204      * Copy constructor
0205      */
0206     KFormat(const KFormat &other);
0207 
0208     KFormat &operator=(const KFormat &other);
0209 
0210     /**
0211      * Destructor
0212      */
0213     ~KFormat();
0214 
0215     /**
0216      * Converts @p size from bytes to the appropriate string representation
0217      * using the binary unit dialect @p dialect and the specific units @p units.
0218      *
0219      * Example:
0220      * @code
0221      * QString metric, iec, jedec, small;
0222      * metric = formatByteSize(1000, 1, KFormat::MetricBinaryDialect, KFormat::UnitKiloByte);
0223      * iec    = formatByteSize(1024, 1, KFormat::IECBinaryDialect, KFormat::UnitKiloByte);
0224      * jedec  = formatByteSize(1024, 1, KFormat::JEDECBinaryDialect, KFormat::UnitKiloByte);
0225      * small  = formatByteSize(100);
0226      * // metric == "1.0 kB", iec == "1.0 KiB", jedec == "1.0 KB", small == "100 B"
0227      * @endcode
0228      *
0229      * @param size size in bytes
0230      * @param precision number of places after the decimal point to use.  KDE uses
0231      *        1 by default so when in doubt use 1.  Whenever KFormat::UnitByte is used
0232      *        (either explicitly or autoselected from KFormat::DefaultBinaryUnits),
0233      *        the fractional part is always omitted.
0234      * @param dialect binary unit standard to use.  Use DefaultBinaryDialect to
0235      *        use the localized user selection unless you need to use a specific
0236      *        unit type (such as displaying a flash memory size in JEDEC).
0237      * @param units specific unit size to use in result.  Use
0238      *        DefaultBinaryUnits to automatically select a unit that will return
0239      *        a sanely-sized number.
0240      * @return converted size as a translated string including the units.
0241      *         E.g. "1.23 KiB", "2 GB" (JEDEC), "4.2 kB" (Metric).
0242      * @see BinarySizeUnits
0243      * @see BinaryUnitDialect
0244      */
0245 
0246     QString formatByteSize(double size,
0247                            int precision = 1,
0248                            KFormat::BinaryUnitDialect dialect = KFormat::DefaultBinaryDialect,
0249                            KFormat::BinarySizeUnits units = KFormat::DefaultBinaryUnits) const;
0250 
0251     /**
0252      * Given a number of milliseconds, converts that to a string containing
0253      * the localized equivalent, e.g. 1:23:45
0254      *
0255      * @param msecs Time duration in milliseconds
0256      * @param options options to use in the duration format
0257      * @return converted duration as a string - e.g. "1:23:45" "1h23m"
0258      */
0259 
0260     QString formatDuration(quint64 msecs, KFormat::DurationFormatOptions options = KFormat::DefaultDuration) const;
0261 
0262     /**
0263      * Given a number of milliseconds, converts that to a string containing
0264      * the localized equivalent to the requested decimal places.
0265      *
0266      * e.g. given formatDuration(60000), returns "1.0 minutes"
0267      *
0268      * @param msecs Time duration in milliseconds
0269      * @param decimalPlaces Decimal places to round off to, defaults to 2
0270      * @return converted duration as a string - e.g. "5.5 seconds" "23.0 minutes"
0271      */
0272 
0273     QString formatDecimalDuration(quint64 msecs, int decimalPlaces = 2) const;
0274 
0275     /**
0276      * Given a number of milliseconds, converts that to a spell-out string containing
0277      * the localized equivalent.
0278      *
0279      * e.g. given formatSpelloutDuration(60001) returns "1 minute"
0280      *      given formatSpelloutDuration(62005) returns "1 minute and 2 seconds"
0281      *      given formatSpelloutDuration(90060000) returns "1 day and 1 hour"
0282      *
0283      * @param msecs Time duration in milliseconds
0284      * @return converted duration as a string.
0285      *         Units not interesting to the user, for example seconds or minutes when the first
0286      *         unit is day, are not returned because they are irrelevant. The same applies for
0287      *         seconds when the first unit is hour.
0288      */
0289     QString formatSpelloutDuration(quint64 msecs) const;
0290 
0291     /**
0292      * Returns a string formatted to a relative date style.
0293      *
0294      * If the @p date falls within one week before or after the current date
0295      * then a relative date string will be returned, such as:
0296      * * Yesterday
0297      * * Today
0298      * * Tomorrow
0299      * * Last Tuesday
0300      * * Next Wednesday
0301      *
0302      * If the @p date falls outside this period then the @p format is used.
0303      *
0304      * @param date the date to be formatted
0305      * @param format the date format to use
0306      *
0307      * @return the date as a string
0308      */
0309     QString formatRelativeDate(const QDate &date, QLocale::FormatType format) const;
0310 
0311     /**
0312      * Returns a string formatted to a relative datetime style.
0313      *
0314      * If the @p dateTime falls within one week before or after the current date
0315      * then a relative date string will be returned, such as:
0316      * * Yesterday at 3:00pm
0317      * * Today at 3:00pm
0318      * * Tomorrow at 3:00pm
0319      * * Last Tuesday at 3:00pm
0320      * * Next Wednesday at 3:00pm
0321      *
0322      * If the @p dateTime falls within one hour of the current time.
0323      * Then a shorter version is displayed:
0324      *  * Just a moment ago (for within the same minute)
0325      *  * 15 minutes ago
0326      *
0327      * If the @p dateTime falls outside this period then the date is rendered as:
0328      *  * Monday, 7 September, 2021 at 7:00 PM : date formatted @p format + " at " + time formatted with @p format
0329      *
0330      * With @p format LongFormat, time format used is set to ShortFormat (to omit timezone and seconds).
0331      *
0332      * First character is capitalized.
0333      *
0334      * @param dateTime the date to be formatted
0335      * @param format the date format to use
0336      *
0337      * @return the date as a string
0338      */
0339     QString formatRelativeDateTime(const QDateTime &dateTime, QLocale::FormatType format) const;
0340 
0341     /**
0342      * Converts @p value to the appropriate string representation
0343      *
0344      * Example:
0345      * @code
0346      * // sets formatted to "1.0 kbit"
0347      * auto formatted = format.formatValue(1000, KFormat::Unit::Bit, 1, KFormat::UnitPrefix::Kilo);
0348      * @endcode
0349      *
0350      * @param value value to be formatted
0351      * @param precision number of places after the decimal point to use.  KDE uses
0352      *        1 by default so when in doubt use 1.
0353      * @param unit unit to use in result.
0354      * @param prefix specific prefix to use in result.  Use UnitPrefix::AutoAdjust
0355      *        to automatically select an appropriate prefix.
0356      * @param dialect prefix standard to use.  Use DefaultBinaryDialect to
0357      *        use the localized user selection unless you need to use a specific
0358      *        unit type. Only meaningful for KFormat::Unit::Byte, and ignored for
0359      *        all other units.
0360      * @return converted size as a translated string including prefix and unit.
0361      *         E.g. "1.23 KiB", "2 GB" (JEDEC), "4.2 kB" (Metric), "1.2 kbit".
0362      * @see Unit
0363      * @see UnitPrefix
0364      * @see BinaryUnitDialect
0365      * @since 5.49
0366      */
0367     QString formatValue(double value,
0368                         KFormat::Unit unit,
0369                         int precision = 1,
0370                         KFormat::UnitPrefix prefix = KFormat::UnitPrefix::AutoAdjust,
0371                         KFormat::BinaryUnitDialect dialect = KFormat::DefaultBinaryDialect) const;
0372 
0373     /**
0374      * Converts @p value to the appropriate string representation
0375      *
0376      * Example:
0377      * @code
0378      * QString bits, slow, fast;
0379      * // sets bits to "1.0 kbit", slow to "1.0 kbit/s" and fast to "12.3 Mbit/s".
0380      * bits = format.formatValue(1000, QStringLiteral("bit"), 1, KFormat::UnitPrefix::Kilo);
0381      * slow = format.formatValue(1000, QStringLiteral("bit/s");
0382      * fast = format.formatValue(12.3e6, QStringLiteral("bit/s");
0383      * @endcode
0384      *
0385      * @param value value to be formatted
0386      * @param precision number of places after the decimal point to use.  KDE uses
0387      *        1 by default so when in doubt use 1.
0388      * @param unit unit to use in result.
0389      * @param prefix specific prefix to use in result.  Use UnitPrefix::AutoAdjust
0390      *        to automatically select an appropriate prefix.
0391      * @return converted size as a translated string including prefix and unit.
0392      *         E.g. "1.2 kbit", "2.4 kB", "12.3 Mbit/s"
0393      * @see UnitPrefix
0394      * @since 5.49
0395      */
0396     QString formatValue(double value, const QString &unit, int precision = 1, KFormat::UnitPrefix prefix = KFormat::UnitPrefix::AutoAdjust) const;
0397     /**
0398      * Converts @p value to the appropriate string representation.
0399      *
0400      * Example:
0401      * @code
0402      * QString iec, jedec, metric;
0403      * // Sets iec to "1.0 KiB/s", jedec to "1.0 KB/s" and metric to "1.0 kB/s"
0404      * iec = format.formatValue(1024, QStringLiteral("B/s"), 1, KFormat::UnitPrefix::AutoAdjust, KFormat::IECBinaryDialect);
0405      * jedec = format.formatValue(1024, QStringLiteral("B/s"), 1, KFormat::UnitPrefix::AutoAdjust, KFormat::JEDECBinaryDialect);
0406      * metric = format.formatValue(1000, QStringLiteral("B/s"), 1, KFormat::UnitPrefix::AutoAdjust, KFormat::MetricBinaryDialect);
0407      * @endcode
0408      *
0409      * @param value value to be formatted
0410      * @param precision number of places after the decimal point to use. 1 is used by default; when
0411      *        in doubt use 1
0412      * @param unit unit to use in result
0413      * @param prefix specific prefix to use in result. Use UnitPrefix::AutoAdjust
0414      *        to automatically select an appropriate prefix
0415      * @param dialect prefix standard to use. Use DefaultBinaryDialect to
0416      *        use the localized user selection unless you need to use a specific
0417      *        unit type
0418      * @return converted size as a translated string including prefix and unit.
0419      *         E.g. "1.2 kbit", "2.4 kB", "12.3 Mbit/s"
0420      * @see UnitPrefix
0421      * @since 5.74
0422      */
0423     QString formatValue(double value, const QString &unit, int precision, KFormat::UnitPrefix prefix, KFormat::BinaryUnitDialect dialect) const;
0424 
0425 private:
0426     QSharedDataPointer<KFormatPrivate> d;
0427 };
0428 
0429 #endif // KFORMAT_H