common: Make CommitDate Unix epoch, handle legacy
authorShane Synan <digitalcircuit36939@gmail.com>
Wed, 20 Jun 2018 09:05:00 +0000 (04:05 -0500)
committerManuel Nickschas <sputnick@quassel-irc.org>
Wed, 20 Jun 2018 20:24:09 +0000 (22:24 +0200)
Leave CommitDate (BuildDate) in Unix epoch format, converting it on
demand when displayed.  This allows clients to localize the time
shown.

Add tryFormatUnixEpoch, which checks a string for Unix epoch, parsing
as date/time if possible, otherwise letting the string through.  This
avoids breaking protocol or any existing packaging scripts that set
commit date to a string.

Check for empty commit/build dates when using them, replacing with
"Unknown date" or "unknown" as appropriate.  Don't encode this in
Quassel::setupBuildInfo() to allow for location-specific treatment
and client-side translation.

src/common/quassel.cpp
src/common/util.cpp
src/common/util.h
src/core/coresessioneventprocessor.cpp
src/qtui/aboutdlg.cpp
src/qtui/coreinfodlg.cpp
src/qtui/coresessionwidget.cpp
version.h.in

index 86ab48b..67eac80 100644 (file)
@@ -299,19 +299,13 @@ void Quassel::setupBuildInfo()
     // Check if we got a commit hash
     if (!QString(GIT_HEAD).isEmpty()) {
         buildInfo.commitHash = GIT_HEAD;
     // Check if we got a commit hash
     if (!QString(GIT_HEAD).isEmpty()) {
         buildInfo.commitHash = GIT_HEAD;
-        QDateTime date;
-#if QT_VERSION >= 0x050800
-        date.setSecsSinceEpoch(GIT_COMMIT_DATE);
-#else
-        // toSecsSinceEpoch() was added in Qt 5.8.  Manually downconvert to seconds for now.
-        // See https://doc.qt.io/qt-5/qdatetime.html#toMSecsSinceEpoch
-        // Warning generated if not converting the 1000 to a qint64 first.
-        date.setMSecsSinceEpoch(GIT_COMMIT_DATE * (qint64)1000);
-#endif
-        buildInfo.commitDate = date.toString();
+        // Set to Unix epoch, wrapped as a string for backwards-compatibility
+        buildInfo.commitDate = QString::number(GIT_COMMIT_DATE);
     }
     else if (!QString(DIST_HASH).contains("Format")) {
         buildInfo.commitHash = DIST_HASH;
     }
     else if (!QString(DIST_HASH).contains("Format")) {
         buildInfo.commitHash = DIST_HASH;
+        // Leave as Unix epoch if set as Unix epoch, but don't force this for
+        // backwards-compatibility with existing packaging/release tools that might set strings.
         buildInfo.commitDate = QString(DIST_DATE);
     }
 
         buildInfo.commitDate = QString(DIST_DATE);
     }
 
index b42f4fb..a2c4e25 100644 (file)
@@ -363,3 +363,29 @@ bool scopeMatch(const QString &string, const QString &scopeRule, const bool &isR
         return matches || (invertedRuleFound && !normalRuleFound);
     }
 }
         return matches || (invertedRuleFound && !normalRuleFound);
     }
 }
+
+
+QString tryFormatUnixEpoch(const QString &possibleEpochDate)
+{
+    // Does the string resemble a Unix epoch?  Parse as 64-bit time
+    qint64 secsSinceEpoch = possibleEpochDate.toLongLong();
+    if (secsSinceEpoch == 0) {
+        // Parsing either failed, or '0' was sent.  No need to distinguish; either way, it's not
+        // useful as epoch.
+        // See https://doc.qt.io/qt-5/qstring.html#toLongLong
+        return possibleEpochDate;
+    }
+
+    // Time checks out, parse it
+    QDateTime date;
+#if QT_VERSION >= 0x050800
+    date.setSecsSinceEpoch(secsSinceEpoch);
+#else
+    // toSecsSinceEpoch() was added in Qt 5.8.  Manually downconvert to seconds for now.
+    // See https://doc.qt.io/qt-5/qdatetime.html#toMSecsSinceEpoch
+    date.setMSecsSinceEpoch(secsSinceEpoch * 1000);
+#endif
+
+    // Return the localized date/time
+    return date.toString();
+}
index 8b312f9..d72dd8e 100644 (file)
@@ -101,3 +101,14 @@ QString formatCurrentDateTimeInString(const QString &formatStr);
  */
 bool scopeMatch(const QString &string, const QString &scopeRule,
                 const bool &isRegEx = false, const bool &isCaseSensitive = false);
  */
 bool scopeMatch(const QString &string, const QString &scopeRule,
                 const bool &isRegEx = false, const bool &isCaseSensitive = false);
+
+/**
+ * Try to localize a given date/time in seconds from Unix epoch, pass through string if invalid
+ *
+ * Allows compatibility with date/time fields that may or may not be in Unix epoch format,
+ * localizing if possible, leaving alone if not.
+ *
+ * @param possibleEpochDate Date/time that might be in seconds since Unix epoch format
+ * @return Localized date/time if parse succeeded, otherwise the source string
+ */
+QString tryFormatUnixEpoch(const QString &possibleEpochDate);
index eb2ec0e..76cddb3 100644 (file)
@@ -1634,6 +1634,9 @@ void CoreSessionEventProcessor::handleCtcpTime(CtcpEvent *e)
 
 void CoreSessionEventProcessor::handleCtcpVersion(CtcpEvent *e)
 {
 
 void CoreSessionEventProcessor::handleCtcpVersion(CtcpEvent *e)
 {
-    e->setReply(QString("Quassel IRC %1 (built on %2) -- https://www.quassel-irc.org")
-        .arg(Quassel::buildInfo().plainVersionString).arg(Quassel::buildInfo().commitDate));
+    // Deliberately do not translate project name
+    e->setReply(QString("Quassel IRC %1 (version date %2) -- https://www.quassel-irc.org")
+                .arg(Quassel::buildInfo().plainVersionString)
+                .arg(Quassel::buildInfo().commitDate.isEmpty() ?
+                      "unknown" : tryFormatUnixEpoch(Quassel::buildInfo().commitDate)));
 }
 }
index 2fc3d6e..1468488 100644 (file)
@@ -26,6 +26,7 @@
 #include "aboutdata.h"
 #include "icon.h"
 #include "quassel.h"
 #include "aboutdata.h"
 #include "icon.h"
 #include "quassel.h"
+#include "util.h"
 
 AboutDlg::AboutDlg(QWidget *parent)
     : QDialog(parent)
 
 AboutDlg::AboutDlg(QWidget *parent)
     : QDialog(parent)
@@ -36,10 +37,21 @@ AboutDlg::AboutDlg(QWidget *parent)
     ui.setupUi(this);
     ui.quasselLogo->setPixmap(QPixmap{":/pics/quassel-64.svg"});  // don't let the icon theme affect our logo here
 
     ui.setupUi(this);
     ui.quasselLogo->setPixmap(QPixmap{":/pics/quassel-64.svg"});  // don't let the icon theme affect our logo here
 
-    ui.versionLabel->setText(QString(tr("<b>Version:</b> %1<br><b>Version date:</b> %2<br><b>Protocol version:</b> %3"))
-        .arg(Quassel::buildInfo().fancyVersionString)
-        .arg(Quassel::buildInfo().commitDate)
-        .arg(Quassel::buildInfo().protocolVersion));
+    QString versionDate;
+    if (Quassel::buildInfo().commitDate.isEmpty()) {
+        // This shouldn't happen, but sometimes the packaging environment cannot set a proper
+        // date/time.  Add a fallback just in case.
+        versionDate = QString("<i>%1</i>").arg(tr("Unknown date"));
+    }
+    else {
+        versionDate = tryFormatUnixEpoch(Quassel::buildInfo().commitDate);
+    }
+    ui.versionLabel->setText(QString(tr("<b>Version:</b> %1<br>"
+                                        "<b>Version date:</b> %2<br>"
+                                        "<b>Protocol version:</b> %3"))
+                             .arg(Quassel::buildInfo().fancyVersionString)
+                             .arg(versionDate)
+                             .arg(Quassel::buildInfo().protocolVersion));
     ui.aboutTextBrowser->setHtml(about());
     ui.authorTextBrowser->setHtml(authors());
     ui.contributorTextBrowser->setHtml(contributors());
     ui.aboutTextBrowser->setHtml(about());
     ui.authorTextBrowser->setHtml(authors());
     ui.contributorTextBrowser->setHtml(contributors());
index d952735..b175977 100644 (file)
@@ -25,6 +25,7 @@
 #include "bufferwidget.h"
 #include "client.h"
 #include "icon.h"
 #include "bufferwidget.h"
 #include "client.h"
 #include "icon.h"
+#include "util.h"
 
 CoreInfoDlg::CoreInfoDlg(QWidget *parent) : QDialog(parent) {
     ui.setupUi(this);
 
 CoreInfoDlg::CoreInfoDlg(QWidget *parent) : QDialog(parent) {
     ui.setupUi(this);
@@ -94,7 +95,13 @@ void CoreInfoDlg::coreInfoChanged(const QVariantMap &coreInfo) {
     } else {
         ui.labelCoreVersion->setText(coreInfo["quasselVersion"].toString());
         // "BuildDate" for compatibility
     } else {
         ui.labelCoreVersion->setText(coreInfo["quasselVersion"].toString());
         // "BuildDate" for compatibility
-        ui.labelCoreVersionDate->setText(coreInfo["quasselBuildDate"].toString());
+        if (coreInfo["quasselBuildDate"].toString().isEmpty()) {
+            ui.labelCoreVersionDate->setText(QString("<i>%1</i>").arg(tr("Unknown date")));
+        }
+        else {
+            ui.labelCoreVersionDate->setText(
+                        tryFormatUnixEpoch(coreInfo["quasselBuildDate"].toString()));
+        }
         ui.labelClientCount->setNum(coreInfo["sessionConnectedClients"].toInt());
     }
 
         ui.labelClientCount->setNum(coreInfo["sessionConnectedClients"].toInt());
     }
 
index 97993f4..fbbb39b 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "client.h"
 #include "coresessionwidget.h"
 
 #include "client.h"
 #include "coresessionwidget.h"
+#include "util.h"
 
 
 CoreSessionWidget::CoreSessionWidget(QWidget *parent)
 
 
 CoreSessionWidget::CoreSessionWidget(QWidget *parent)
@@ -36,7 +37,12 @@ void CoreSessionWidget::setData(QMap<QString, QVariant> map)
     ui.sessionGroup->setTitle(map["remoteAddress"].toString());
     ui.labelLocation->setText(map["location"].toString());
     ui.labelClient->setText(map["clientVersion"].toString());
     ui.sessionGroup->setTitle(map["remoteAddress"].toString());
     ui.labelLocation->setText(map["location"].toString());
     ui.labelClient->setText(map["clientVersion"].toString());
-    ui.labelVersionDate->setText(map["clientVersionDate"].toString());
+    if (map["clientVersionDate"].toString().isEmpty()) {
+        ui.labelVersionDate->setText(QString("<i>%1</i>").arg(tr("Unknown date")));
+    }
+    else {
+        ui.labelVersionDate->setText(tryFormatUnixEpoch(map["clientVersionDate"].toString()));
+    }
     ui.labelUptime->setText(map["connectedSince"].toDateTime().toLocalTime().toString(Qt::DateFormat::SystemLocaleShortDate));
     if (map["location"].toString().isEmpty()) {
         ui.labelLocation->hide();
     ui.labelUptime->setText(map["connectedSince"].toDateTime().toLocalTime().toString(Qt::DateFormat::SystemLocaleShortDate));
     if (map["location"].toString().isEmpty()) {
         ui.labelLocation->hide();
index 59112c9..4be8e52 100644 (file)
@@ -7,8 +7,10 @@
 // Determined from Git
 #define GIT_HEAD "@GIT_HEAD@"
 #define GIT_DESCRIBE "@GIT_DESCRIBE@"
 // Determined from Git
 #define GIT_HEAD "@GIT_HEAD@"
 #define GIT_DESCRIBE "@GIT_DESCRIBE@"
+// Unix epoch in seconds
 #define GIT_COMMIT_DATE @GIT_COMMIT_DATE@
 
 // Will be substituted in official tarballs
 #define DIST_HASH "$Format:%H$"
 #define GIT_COMMIT_DATE @GIT_COMMIT_DATE@
 
 // Will be substituted in official tarballs
 #define DIST_HASH "$Format:%H$"
+// Unix epoch in seconds
 #define DIST_DATE "$Format:%at$"
 #define DIST_DATE "$Format:%at$"