From 2e6d65ef08f32df67c8261cb989042a33be9d50f Mon Sep 17 00:00:00 2001 From: Berthold Stoeger Date: Sun, 31 Jul 2022 22:23:24 +0200 Subject: [PATCH] profile: add local time to profile tooltip This is a user request: add local time of dive to the tooltip. Showing a localized time was surprisingly complex. First I had to add a function that decomposes a timestamp into h/m/s. Then the QLocale time-string has to be stripped of the timezone. Fixes #3469. Signed-off-by: Berthold Stoeger --- CHANGELOG.md | 2 +- core/string-format.cpp | 16 +++++++++++++++- core/subsurface-time.h | 5 +++++ core/time.c | 31 +++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ba284890..3870b1f0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ - +- profile: show local time of cursor position in tooltip (fixes #3469). --- * Always add new entries at the very top of this file above other existing entries and this note. * Use this layout for new entries: `[Area]: [Details about the change] [reference thread / issue]` diff --git a/core/string-format.cpp b/core/string-format.cpp index 97314c28e..361833141 100644 --- a/core/string-format.cpp +++ b/core/string-format.cpp @@ -304,6 +304,18 @@ QString formatTripTitleWithDives(const dive_trip *trip) gettextFromC::tr("(%n dive(s))", "", nr); } +static QString formatTimeOfDay(timestamp_t when) +{ + auto [h, m, s] = utc_time_of_day(when); + QLocale loc; + QString format = loc.timeFormat(QLocale::LongFormat); + // We don't want to show the timezone, as that currently is the + // timezone the application is run in, not the timezone of the dive! + format.replace("t", ""); + QTime time(h, m, s); + return loc.toString(time, format.trimmed()); +} + #define DIV_UP(x, y) (((x) + (y) - 1) / (y)) #define translate(x,y) qPrintable(QCoreApplication::translate(x,y)) @@ -316,9 +328,11 @@ static QString formatPlotInfoInternal(const dive *d, const plot_info *pi, int id int decimals, cyl; const char *unit; const struct plot_data *entry = pi->entry + idx; + timestamp_t when = d->when + entry->sec; depthvalue = get_depth_units(entry->depth, NULL, &depth_unit); - res = qasprintf_loc("%s: %d:%02d\n", translate("gettextFromC", "@"), FRACTION(entry->sec, 60)); + res = qasprintf_loc("%s: %d:%02d (%s)\n", translate("gettextFromC", "@"), FRACTION(entry->sec, 60), + qPrintable(formatTimeOfDay(when))); res += qasprintf_loc("%s: %.1f%s\n", translate("gettextFromC", "D"), depthvalue, depth_unit); for (cyl = 0; cyl < pi->nr_cylinders; cyl++) { int mbar = get_plot_pressure(pi, idx, cyl); diff --git a/core/subsurface-time.h b/core/subsurface-time.h index 097aa5215..f97f540b0 100644 --- a/core/subsurface-time.h +++ b/core/subsurface-time.h @@ -9,10 +9,15 @@ extern "C" { #endif +struct time_of_day { + int h, m, s; +}; + extern timestamp_t utc_mktime(const struct tm *tm); extern void utc_mkdate(timestamp_t, struct tm *tm); extern int utc_year(timestamp_t timestamp); extern int utc_weekday(timestamp_t timestamp); +extern struct time_of_day utc_time_of_day(timestamp_t timestamp); /* parse and format date times of the form YYYY-MM-DD hh:mm:ss */ extern timestamp_t parse_datetime(const char *s); /* returns 0 on error */ diff --git a/core/time.c b/core/time.c index 0dd47856b..d5e97c3a8 100644 --- a/core/time.c +++ b/core/time.c @@ -99,6 +99,37 @@ void utc_mkdate(timestamp_t timestamp, struct tm *tm) tm->tm_mon = m; } +/* + * Convert 64-bit timestamp to time of day (split into h, m, s) + * + * On 32-bit machines, only do 64-bit arithmetic for the seconds + * part, after that we do everything in 'long'. 64-bit divides + * are unnecessary once you're counting minutes (32-bit minutes: + * 8000+ years). + */ +struct time_of_day utc_time_of_day(timestamp_t timestamp) +{ + struct time_of_day res = { 0 }; + unsigned long val; + + // Midnight at Jan 1, 1970 means "no date" + if (!timestamp) + return res; + + /* Convert to seconds since 1900 */ + timestamp += EPOCH_OFFSET; + + /* minutes since 1900 */ + res.s = timestamp % 60; + val = timestamp / 60; + + res.m = val % 60; + val /= 60; + res.h = val % 24; + + return res; +} + timestamp_t utc_mktime(const struct tm *tm) { static const int mdays[] = {