#include "util/duration.h" #include #include #include #include "util/assert.h" #include "util/fpclassify.h" namespace mixxx { namespace { static const qint64 kSecondsPerMinute = 60; static const qint64 kSecondsPerHour = 60 * kSecondsPerMinute; static const qint64 kSecondsPerDay = 24 * kSecondsPerHour; } // namespace // static const QString DurationBase::kInvalidDurationString = "?"; // Unicode for thin space QChar DurationBase::kKiloGroupSeparator = QChar(0x2009); // Unicode for decimal point QChar DurationBase::kDecimalSeparator = QChar(0x002E); // static QString DurationBase::formatTime(double dSeconds, Precision precision) { if (dSeconds < 0.0 || !util_isfinite(dSeconds) // Use >= instead of >: 2^63-1 (qint64) is rounded to 2^63 (double) || dSeconds >= static_cast(std::numeric_limits::max())) { // negative durations and infinity or isNaN values are not supported return kInvalidDurationString; } const qint64 days = static_cast(std::floor(dSeconds)) / kSecondsPerDay; dSeconds -= days * kSecondsPerDay; // NOTE(uklotzde): QTime() constructs a 'null' object, but // we need 'zero' here. QTime t = QTime(0, 0).addMSecs(static_cast(dSeconds * kMillisPerSecond)); QString formatString = (t.hour() > 0 && days < 1 ? QStringLiteral("hh:mm:ss") : QStringLiteral("mm:ss")) + (Precision::SECONDS == precision ? QString() : QStringLiteral(".zzz")); QString durationString = t.toString(formatString); if (days > 0) { durationString = QString::number(days * 24 + t.hour()) + QChar(':') + durationString; } // remove leading 0 if (durationString.at(0) == '0' && durationString.at(1) != ':') { durationString = durationString.right(durationString.length() - 1); } // The format string gives us milliseconds but we want // centiseconds. Slice one character off. if (Precision::CENTISECONDS == precision) { DEBUG_ASSERT(1 <= durationString.length()); durationString = durationString.left(durationString.length() - 1); } return durationString; } // static QString DurationBase::formatSeconds(double dSeconds, Precision precision) { if (dSeconds < 0.0) { // negative durations are not supported return kInvalidDurationString; } QString durationString; if (Precision::CENTISECONDS == precision) { durationString = QString::number(dSeconds, 'f', 2); } else if (Precision::MILLISECONDS == precision) { durationString = QString::number(dSeconds, 'f', 3); } else { durationString = QString::number(dSeconds, 'f', 0); } return durationString; } // static QString DurationBase::formatSecondsLong(double dSeconds, Precision precision) { if (dSeconds < 0.0) { // negative durations are not supported return kInvalidDurationString; } QString durationString; if (Precision::CENTISECONDS == precision) { durationString = QString::number(dSeconds, 'f', 2) .rightJustified(6, QLatin1Char('0')); } else if (Precision::MILLISECONDS == precision) { durationString = QString::number(dSeconds, 'f', 3) .rightJustified(7, QLatin1Char('0')); } else { durationString = QString::number(dSeconds, 'f', 0) .rightJustified(3, QLatin1Char('0')); } return durationString; } // static QString DurationBase::formatKiloSeconds(double dSeconds, Precision precision) { if (dSeconds < 0.0) { // negative durations are not supported return kInvalidDurationString; } int kilos = (int)dSeconds / 1000; double seconds = std::floor(fmod(dSeconds, 1000)); double subs = fmod(dSeconds, 1); QString durationString = QString("%1%2%3").arg( QString::number(kilos), QString(kDecimalSeparator), QString::number(seconds).rightJustified(3, QLatin1Char('0'))); if (Precision::SECONDS != precision) { durationString += kKiloGroupSeparator % QString::number(subs, 'f', 3).right(3); } // The format string gives us milliseconds but we want // centiseconds. Slice one character off. if (Precision::CENTISECONDS == precision) { DEBUG_ASSERT(1 <= durationString.length()); durationString = durationString.left(durationString.length() - 1); } return durationString; } } // namespace mixxx