1/*
2 This file is part of the KDE Frameworks
3
4 SPDX-FileCopyrightText: 2013 Alex Merry <alex.merry@kdemail.net>
5 SPDX-FileCopyrightText: 2013 John Layt <jlayt@kde.org>
6 SPDX-FileCopyrightText: 2010 Michael Leupold <lemma@confuego.org>
7 SPDX-FileCopyrightText: 2009 Michael Pyne <mpyne@kde.org>
8 SPDX-FileCopyrightText: 2008 Albert Astals Cid <aacid@kde.org>
9
10 SPDX-License-Identifier: LGPL-2.0-or-later
11*/
12
13#ifndef KFORMAT_H
14#define KFORMAT_H
15
16#include <kcoreaddons_export.h>
17
18#include <QLocale>
19#include <QSharedPointer>
20#include <QString>
21
22class QDate;
23class QDateTime;
24
25class KFormatPrivate;
26
27/*
28 The code in this class was copied from the old KLocale and modified
29 by John Layt (and also Alex Merry) in the KDELIBS 4 to KDE
30 Frameworks 5 transition in 2013.
31
32 Albert Astals Cid is the original author of formatSpelloutDuration()
33 originally named KLocale::prettyFormatDuration().
34
35 Michael Pyne is the original author of formatByteSize().
36
37 Michael Leupold is the original author of formatRelativeDate(()
38 originally part of KFormat::formatDate().
39*/
40
41/*!
42 * \class KFormat
43 * \inmodule KCoreAddons
44 *
45 * \brief Class for formatting numbers and datetimes.
46 *
47 * KFormat provides support for formatting numbers and datetimes in
48 * formats that are not supported by QLocale.
49 * \since 5.0
50 */
51class KCOREADDONS_EXPORT KFormat final
52{
53 Q_GADGET
54
55public:
56 /*!
57 * These binary units are used in KDE by the formatByteSize()
58 * function.
59 *
60 * NOTE: There are several different units standards:
61 * 1) SI (i.e. metric), powers-of-10.
62 * 2) IEC, powers-of-2, with specific units KiB, MiB, etc.
63 * 3) JEDEC, powers-of-2, used for solid state memory sizing which
64 * is why you see flash cards labels as e.g. 4GB. These (ab)use
65 * the metric units. Although JEDEC only defines KB, MB, GB, if
66 * JEDEC is selected all units will be powers-of-2 with metric
67 * prefixes for clarity in the event of sizes larger than 1024 GB.
68 *
69 * Although 3 different dialects are possible this enum only uses
70 * metric names since adding all 3 different names of essentially the same
71 * unit would be pointless. Use BinaryUnitDialect to control the exact
72 * units returned.
73 *
74 * \sa BinaryUnitDialect
75 * \sa formatByteSize
76 *
77 * \value DefaultBinaryUnits Auto-choose a unit such that the result is in the range [0, 1000 or 1024)
78 * \value UnitByte B 1 byte
79 * \value UnitKiloByte KiB/KB/kB 1024/1000 bytes
80 * \value UnitMegaByte MiB/MB/MB 2^20/10^06 bytes
81 * \value UnitGigaByte GiB/GB/GB 2^30/10^09 bytes
82 * \value UnitTeraByte TiB/TB/TB 2^40/10^12 bytes
83 * \value UnitPetaByte PiB/PB/PB 2^50/10^15 bytes
84 * \value UnitExaByte EiB/EB/EB 2^60/10^18 bytes
85 * \value UnitZettaByte ZiB/ZB/ZB 2^70/10^21 bytes
86 * \value UnitYottaByte YiB/YB/YB 2^80/10^24 bytes
87 */
88 enum BinarySizeUnits {
89 DefaultBinaryUnits = -1,
90
91 // The first real unit must be 0 for the current implementation!
92 UnitByte,
93 UnitKiloByte,
94 UnitMegaByte,
95 UnitGigaByte,
96 UnitTeraByte,
97 UnitPetaByte,
98 UnitExaByte,
99 UnitZettaByte,
100 UnitYottaByte,
101 UnitLastUnit = UnitYottaByte,
102 };
103
104 /*!
105 * These units are used in KDE by the formatValue() function.
106 *
107 * \sa formatValue
108 * \since 5.49
109 *
110 * \value Other other
111 * \value Bit bit
112 * \value Byte B
113 * \value Meter m
114 * \value Hertz Hz
115 *
116 */
117 enum class Unit {
118 Other,
119 Bit,
120 Byte,
121 Meter,
122 Hertz,
123 };
124
125 /*!
126 * These prefixes are used in KDE by the formatValue()
127 * function.
128 *
129 * IEC prefixes are only defined for integral units of information, e.g.
130 * bits and bytes.
131 *
132 * \sa BinarySizeUnits
133 * \sa formatValue
134 * \since 5.49
135 *
136 * \value AutoAdjust Auto-choose a unit such that the result is in the range [0, 1000 or 1024)
137 * \value Yocto --/-/y 10^-24
138 * \value Zepto --/-/z 10^-21
139 * \value Atto --/-/a 10^-18
140 * \value Femto --/-/f 10^-15
141 * \value Pico --/-/p 10^-12
142 * \value Nano --/-/n 10^-9
143 * \value Micro --/-/ยต 10^-6
144 * \value Milli --/-/m 10^-3
145 * \value Centi --/-/c 0.01
146 * \value Deci --/-/d 0.1
147 * \value Unity "" 1
148 * \value Deca --/-/da 10
149 * \value Hecto --/-/h 100
150 * \value Kilo Ki/K/k 1024/1000
151 * \value Mega Mi/M/M 2^20/10^06
152 * \value Giga Gi/G/G 2^30/10^09
153 * \value Tera Ti/T/T 2^40/10^12
154 * \value Peta Pi/P/P 2^50/10^15
155 * \value Exa Ei/E/E 2^60/10^18
156 * \value Zetta Zi/Z/Z 2^70/10^21
157 * \value Yotta Yi/Y/Y 2^80/10^24
158 */
159 enum class UnitPrefix {
160 AutoAdjust = -128,
161
162 Yocto = 0,
163 Zepto,
164 Atto,
165 Femto,
166 Pico,
167 Nano,
168 Micro,
169 Milli,
170 Centi,
171 Deci,
172 Unity,
173 Deca,
174 Hecto,
175 Kilo,
176 Mega,
177 Giga,
178 Tera,
179 Peta,
180 Exa,
181 Zetta,
182 Yotta,
183 };
184
185 /*!
186 * This enum chooses what dialect is used for binary units.
187 *
188 * Note: Although JEDEC abuses the metric prefixes and can therefore be
189 * confusing, it has been used to describe *memory* sizes for quite some time
190 * and programs should therefore use either Default, JEDEC, or IEC 60027-2
191 * for memory sizes.
192 *
193 * On the other hand network transmission rates are typically in metric so
194 * Default, Metric, or IEC (which is unambiguous) should be chosen.
195 *
196 * Normally choosing DefaultBinaryDialect is the best option as that uses
197 * the user's selection for units. If the user has not selected a preference,
198 * IECBinaryDialect will typically be used.
199 *
200 * \value DefaultBinaryDialect Used if no specific preference
201 * \value IECBinaryDialect KiB, MiB, etc. 2^(10*n)
202 * \value JEDECBinaryDialect KB, MB, etc. 2^(10*n)
203 * \value MetricBinaryDialect SI Units, kB, MB, etc. 10^(3*n)
204 * \omitvalue LastBinaryDialect
205 *
206 * \sa BinarySizeUnits
207 * \sa formatByteSize
208 */
209 enum BinaryUnitDialect {
210 DefaultBinaryDialect = -1,
211 IECBinaryDialect,
212 JEDECBinaryDialect,
213 MetricBinaryDialect,
214 LastBinaryDialect = MetricBinaryDialect,
215 };
216
217 /*!
218 * Format flags for formatDuration()
219 *
220 * \value DefaultDuration Default formatting in localized 1:23:45 format
221 * \value InitialDuration Default formatting in localized 1h23m45s format
222 * \value ShowMilliseconds Include milliseconds in format, e.g. 1:23:45.678
223 * \value HideSeconds Hide the seconds, e.g. 1:23 or 1h23m, overrides ShowMilliseconds
224 * \value FoldHours Fold the hours into the minutes, e.g. 83:45 or 83m45s, overrides HideSeconds
225 * \value [since 6.11] AbbreviatedDuration Use abbreviated units (e.g. 1 hr 23 min), as a middle ground between just unit initials (InitialDuration) and
226 * fully spelled out units (formatSpelloutDuration). This always includes up to 2 components.
227 */
228 enum DurationFormatOption {
229 DefaultDuration = 0x0,
230 InitialDuration = 0x1,
231 ShowMilliseconds = 0x2,
232 HideSeconds = 0x4,
233 FoldHours = 0x8,
234 AbbreviatedDuration = 0x10,
235 };
236 Q_DECLARE_FLAGS(DurationFormatOptions, DurationFormatOption)
237 Q_FLAG(DurationFormatOptions)
238
239 /*!
240 * Format flags for formatTime()
241 *
242 * \value DoNotAddTimeZone Equivalent to the QLocale time formatting, does not add any timezone information
243 * \value AddTimezoneAbbreviation Adds the (translated) timezone abbreviation when timezone information is present, e.g. "12:23 CET"
244 * \value AddTimezoneAbbreviationIfNeeded Adds the (translated) timezone abbreviation when timezone information is present and differs from the current
245 * local timezone.
246 *
247 * \since 6.15
248 */
249 enum TimeFormatOption {
250 DoNotAddTimeZone = 0x0,
251 AddTimezoneAbbreviation = 0x1,
252 AddTimezoneAbbreviationIfNeeded = 0x2,
253 };
254 Q_DECLARE_FLAGS(TimeFormatOptions, TimeFormatOption)
255 Q_FLAG(TimeFormatOptions)
256
257 /*!
258 * Formatting options for formatDistance()
259 *
260 * \since 6.11
261 *
262 * \value LocaleDistanceUnits Automatically select metric or imperial units based on the current locale
263 * \value MetricDistanceUnits Force the use of metric unites regardless of the current locale
264 */
265 enum DistanceFormatOption {
266 LocaleDistanceUnits = 0x0,
267 MetricDistanceUnits = 0x1,
268 };
269 Q_DECLARE_FLAGS(DistanceFormatOptions, DistanceFormatOption)
270 Q_FLAG(DistanceFormatOptions)
271
272 /*!
273 * Constructs a KFormat.
274 *
275 * \a locale the locale to use, defaults to the system locale
276 */
277 explicit KFormat(const QLocale &locale = QLocale());
278
279 KFormat(const KFormat &other);
280
281 KFormat &operator=(const KFormat &other);
282
283 ~KFormat();
284
285 /*!
286 * Converts \a size from bytes to the appropriate string representation
287 * using the binary unit dialect \a dialect and the specific units \a units.
288 *
289 * Example:
290 * \code
291 * QString metric, iec, jedec, small;
292 * metric = formatByteSize(1000, 1, KFormat::MetricBinaryDialect, KFormat::UnitKiloByte);
293 * iec = formatByteSize(1024, 1, KFormat::IECBinaryDialect, KFormat::UnitKiloByte);
294 * jedec = formatByteSize(1024, 1, KFormat::JEDECBinaryDialect, KFormat::UnitKiloByte);
295 * small = formatByteSize(100);
296 * // metric == "1.0 kB", iec == "1.0 KiB", jedec == "1.0 KB", small == "100 B"
297 * \endcode
298 *
299 * \a size size in bytes
300 *
301 * \a precision number of places after the decimal point to use. KDE uses
302 * 1 by default so when in doubt use 1. Whenever KFormat::UnitByte is used
303 * (either explicitly or autoselected from KFormat::DefaultBinaryUnits),
304 * the fractional part is always omitted.
305 *
306 * \a dialect binary unit standard to use. Use DefaultBinaryDialect to
307 * use the localized user selection unless you need to use a specific
308 * unit type (such as displaying a flash memory size in JEDEC).
309 *
310 * \a units specific unit size to use in result. Use
311 * DefaultBinaryUnits to automatically select a unit that will return
312 * a sanely-sized number.
313 *
314 * Returns converted size as a translated string including the units.
315 * E.g. "1.23 KiB", "2 GB" (JEDEC), "4.2 kB" (Metric).
316 * \sa BinarySizeUnits
317 * \sa BinaryUnitDialect
318 */
319
320 QString formatByteSize(double size,
321 int precision = 1,
322 KFormat::BinaryUnitDialect dialect = KFormat::DefaultBinaryDialect,
323 KFormat::BinarySizeUnits units = KFormat::DefaultBinaryUnits) const;
324
325 /*!
326 * Given a number of milliseconds, converts that to a string containing
327 * the localized equivalent, e.g. 1:23:45
328 *
329 * \a msecs Time duration in milliseconds
330 *
331 * \a options options to use in the duration format
332 *
333 * Returns converted duration as a string - e.g. "1:23:45" "1h23m"
334 */
335
336 QString formatDuration(quint64 msecs, KFormat::DurationFormatOptions options = KFormat::DefaultDuration) const;
337
338 /*!
339 * Given a number of milliseconds, converts that to a string containing
340 * the localized equivalent to the requested decimal places.
341 *
342 * e.g. given formatDuration(60000), returns "1.0 minutes"
343 *
344 * \a msecs Time duration in milliseconds
345 *
346 * \a decimalPlaces Decimal places to round off to, defaults to 2
347 *
348 * Returns converted duration as a string - e.g. "5.5 seconds" "23.0 minutes"
349 */
350
351 QString formatDecimalDuration(quint64 msecs, int decimalPlaces = 2) const;
352
353 /*!
354 * Given a number of milliseconds, converts that to a spell-out string containing
355 * the localized equivalent.
356 *
357 * e.g. given formatSpelloutDuration(60001) returns "1 minute"
358 * given formatSpelloutDuration(62005) returns "1 minute and 2 seconds"
359 * given formatSpelloutDuration(90060000) returns "1 day and 1 hour"
360 *
361 * \a msecs Time duration in milliseconds
362 *
363 * Returns converted duration as a string.
364 * Units not interesting to the user, for example seconds or minutes when the first
365 * unit is day, are not returned because they are irrelevant. The same applies for
366 * seconds when the first unit is hour.
367 */
368 QString formatSpelloutDuration(quint64 msecs) const;
369
370 /*!
371 * Returns a string formatted to a relative date style.
372 *
373 * If the \a date falls within one week before or after the current date
374 * then a relative date string will be returned, such as:
375 * \list
376 * \li Yesterday
377 * \li Today
378 * \li Tomorrow
379 * \li Last Tuesday
380 * \li Next Wednesday
381 * \endlist
382 *
383 * If the \a date falls outside this period then the \a format is used.
384 *
385 * \a date the date to be formatted
386 *
387 * \a format the date format to use
388 *
389 * Returns the date as a string
390 */
391 QString formatRelativeDate(const QDate &date, QLocale::FormatType format) const;
392
393 /*!
394 * Returns a string formatted to a relative datetime style.
395 *
396 * If the \a dateTime falls within one week before or after the current date
397 * then a relative date string will be returned, such as:
398 * \list
399 * \li Yesterday at 3:00pm
400 * \li Today at 3:00pm
401 * \li Tomorrow at 3:00pm
402 * \li Last Tuesday at 3:00pm
403 * \li Next Wednesday at 3:00pm
404 * \endlist
405 *
406 * If the \a dateTime falls within one hour of the current time.
407 * Then a shorter version is displayed:
408 * \list
409 * \li Just a moment ago (for within the same minute)
410 * \li 15 minutes ago
411 * \endlist
412 *
413 * If the \a dateTime falls outside this period then the date is rendered as:
414 * \list
415 * \li Monday, 7 September, 2021 at 7:00 PM : date formatted \a format + " at " + time formatted with \a format
416 * \endlist
417 *
418 * With \a format LongFormat, time format used is set to ShortFormat (to omit timezone and seconds).
419 *
420 * First character is capitalized.
421 *
422 * \a dateTime the date to be formatted
423 *
424 * \a format the date format to use
425 *
426 * Returns the date as a string
427 */
428 QString formatRelativeDateTime(const QDateTime &dateTime, QLocale::FormatType format) const;
429
430 /*!
431 * Returns a time value formatted as string considering the timezone.
432 *
433 * This behaves like QLocale::toString(QTime, QLocale::FormatType) but can be
434 * made to add additional timezone information via \a options.
435 *
436 * \a dateTime the time to be formatted, as a full QDateTime object so timezone informations
437 * remain available.
438 * \a format the format used for formatting the time value
439 * \a options controls how timezone information should be formatted
440 *
441 * \since 6.15
442 */
443 [[nodiscard]] QString formatTime(const QDateTime &dateTime, QLocale::FormatType format, TimeFormatOptions options = KFormat::DoNotAddTimeZone) const;
444
445 /*!
446 * Converts \a value to the appropriate string representation
447 *
448 * Example:
449 * \code
450 * // sets formatted to "1.0 kbit"
451 * auto formatted = format.formatValue(1000, KFormat::Unit::Bit, 1, KFormat::UnitPrefix::Kilo);
452 * \endcode
453 *
454 * \a value value to be formatted
455 *
456 * \a precision number of places after the decimal point to use. KDE uses
457 * 1 by default so when in doubt use 1.
458 *
459 * \a unit unit to use in result.
460 *
461 * \a prefix specific prefix to use in result. Use UnitPrefix::AutoAdjust
462 * to automatically select an appropriate prefix.
463 *
464 * \a dialect prefix standard to use. Use DefaultBinaryDialect to
465 * use the localized user selection unless you need to use a specific
466 * unit type. Only meaningful for KFormat::Unit::Byte, and ignored for
467 * all other units.
468 *
469 * Returns converted size as a translated string including prefix and unit.
470 * E.g. "1.23 KiB", "2 GB" (JEDEC), "4.2 kB" (Metric), "1.2 kbit".
471 * \sa Unit
472 * \sa UnitPrefix
473 * \sa BinaryUnitDialect
474 * \since 5.49
475 */
476 QString formatValue(double value,
477 KFormat::Unit unit,
478 int precision = 1,
479 KFormat::UnitPrefix prefix = KFormat::UnitPrefix::AutoAdjust,
480 KFormat::BinaryUnitDialect dialect = KFormat::DefaultBinaryDialect) const;
481
482 /*!
483 * Converts \a value to the appropriate string representation
484 *
485 * Example:
486 * \code
487 * QString bits, slow, fast;
488 * // sets bits to "1.0 kbit", slow to "1.0 kbit/s" and fast to "12.3 Mbit/s".
489 * bits = format.formatValue(1000, QStringLiteral("bit"), 1, KFormat::UnitPrefix::Kilo);
490 * slow = format.formatValue(1000, QStringLiteral("bit/s");
491 * fast = format.formatValue(12.3e6, QStringLiteral("bit/s");
492 * \endcode
493 *
494 * \a value value to be formatted
495 *
496 * \a precision number of places after the decimal point to use. KDE uses
497 * 1 by default so when in doubt use 1.
498 *
499 * \a unit unit to use in result.
500 *
501 * \a prefix specific prefix to use in result. Use UnitPrefix::AutoAdjust
502 * to automatically select an appropriate prefix.
503 *
504 * Returns converted size as a translated string including prefix and unit.
505 * E.g. "1.2 kbit", "2.4 kB", "12.3 Mbit/s"
506 * \sa UnitPrefix
507 * \since 5.49
508 */
509 // TODO KF7: remove in favor of the method below
510 QString formatValue(double value, const QString &unit, int precision = 1, KFormat::UnitPrefix prefix = KFormat::UnitPrefix::AutoAdjust) const;
511 /*!
512 * Converts \a value to the appropriate string representation.
513 *
514 * Example:
515 * \code
516 * QString iec, jedec, metric;
517 * // Sets iec to "1.0 KiB/s", jedec to "1.0 KB/s" and metric to "1.0 kB/s"
518 * iec = format.formatValue(1024, QStringLiteral("B/s"), 1, KFormat::UnitPrefix::AutoAdjust, KFormat::IECBinaryDialect);
519 * jedec = format.formatValue(1024, QStringLiteral("B/s"), 1, KFormat::UnitPrefix::AutoAdjust, KFormat::JEDECBinaryDialect);
520 * metric = format.formatValue(1000, QStringLiteral("B/s"), 1, KFormat::UnitPrefix::AutoAdjust, KFormat::MetricBinaryDialect);
521 * \endcode
522 *
523 * \a value value to be formatted
524 *
525 * \a precision number of places after the decimal point to use. 1 is used by default; when
526 * in doubt use 1
527 *
528 * \a unit unit to use in result
529 *
530 * \a prefix specific prefix to use in result. Use UnitPrefix::AutoAdjust
531 * to automatically select an appropriate prefix
532 *
533 * \a dialect prefix standard to use. Use DefaultBinaryDialect to
534 * use the localized user selection unless you need to use a specific
535 * unit type
536 *
537 * Returns converted size as a translated string including prefix and unit.
538 * E.g. "1.2 kbit", "2.4 kB", "12.3 Mbit/s"
539 * \sa UnitPrefix
540 * \since 5.74
541 */
542 QString formatValue(double value, const QString &unit, int precision, KFormat::UnitPrefix prefix, KFormat::BinaryUnitDialect dialect) const;
543
544 /*!
545 * Format \a distance given in meters in a suitable unit for displaying.
546 *
547 * For locales using metric units (or when forcing metric units explicitly)
548 * this will use meters and kilometers depending on the distance, for locales
549 * using imperial units this wil use miles and feet.
550 *
551 * \a distance Distance value to be formatted, in meters.
552 *
553 * \a options Formatting options.
554 *
555 * Returns Formatted distance using locale- and distance-appropirate units.
556 *
557 * \since 6.11
558 */
559 [[nodiscard]] QString formatDistance(double distance, KFormat::DistanceFormatOptions = LocaleDistanceUnits) const;
560
561private:
562 QSharedDataPointer<KFormatPrivate> d;
563};
564
565Q_DECLARE_OPERATORS_FOR_FLAGS(KFormat::DurationFormatOptions)
566Q_DECLARE_OPERATORS_FOR_FLAGS(KFormat::DistanceFormatOptions)
567
568#endif // KFORMAT_H
569

source code of kcoreaddons/src/lib/util/kformat.h