perf(chat): use reentrant local time for chat timestamps
The open chat thread called std::localtime at least twice per message per frame (two day keys for grouping), and more for day separators and time labels. On glibc every call re-checks the timezone with a stat of /etc/localtime. The chat time helpers now use util::localTime() from the new util/local_time.h: localtime_r (localtime_s on Windows), with no per-call timezone check and no shared static result buffer. glibc's localtime_r reads the timezone only once, so local_time.h also adds util::refreshTimezone() (tzset) for caches to call when they rebuild. Nothing calls it yet; its first caller is the chat thread's grouping-flags cache in the next commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+17
-21
@@ -10,6 +10,7 @@
|
||||
#include "../../data/address_book.h"
|
||||
#include "../../chat/chat_service.h"
|
||||
#include "../../util/i18n.h"
|
||||
#include "../../util/local_time.h" // reentrant localtime (chat day keys / time labels)
|
||||
#include "../../util/address_validation.h" // isShieldedAddress — chat requires a z-address recipient
|
||||
#include "../../util/platform.h" // getConfigDir + writeFileAtomically — conversation export (Q11)
|
||||
#include "../../config/settings.h" // per-conversation mute (Q10)
|
||||
@@ -134,11 +135,10 @@ std::string shorten(const std::string& s, std::size_t head = 12, std::size_t tai
|
||||
|
||||
std::string formatTime(std::int64_t ts) {
|
||||
if (ts <= 0) return "";
|
||||
std::time_t t = static_cast<std::time_t>(ts);
|
||||
std::tm* tm = std::localtime(&t); // UI thread only
|
||||
if (!tm) return "";
|
||||
std::tm tmv;
|
||||
if (!util::localTime(static_cast<std::time_t>(ts), tmv)) return "";
|
||||
char buf[40];
|
||||
std::strftime(buf, sizeof(buf), s_chat_time_12h ? "%Y-%m-%d %I:%M %p" : "%Y-%m-%d %H:%M", tm);
|
||||
std::strftime(buf, sizeof(buf), s_chat_time_12h ? "%Y-%m-%d %I:%M %p" : "%Y-%m-%d %H:%M", &tmv);
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -146,21 +146,19 @@ std::string formatTime(std::int64_t ts) {
|
||||
// now lives in a per-day separator, so the group header doesn't repeat it). UI thread only.
|
||||
std::string chatTimeOnly(std::int64_t ts) {
|
||||
if (ts <= 0) return "";
|
||||
std::time_t t = static_cast<std::time_t>(ts);
|
||||
std::tm* tm = std::localtime(&t);
|
||||
if (!tm) return "";
|
||||
std::tm tmv;
|
||||
if (!util::localTime(static_cast<std::time_t>(ts), tmv)) return "";
|
||||
char buf[24];
|
||||
std::strftime(buf, sizeof(buf), s_chat_time_12h ? "%I:%M %p" : "%H:%M", tm);
|
||||
std::strftime(buf, sizeof(buf), s_chat_time_12h ? "%I:%M %p" : "%H:%M", &tmv);
|
||||
return buf;
|
||||
}
|
||||
|
||||
// Local calendar-day key (YYYYMMDD) for detecting day boundaries between messages. UI thread only.
|
||||
std::int64_t chatDayKey(std::int64_t ts) {
|
||||
std::time_t t = static_cast<std::time_t>(ts);
|
||||
std::tm* tm = std::localtime(&t);
|
||||
if (!tm) return -1;
|
||||
return static_cast<std::int64_t>(tm->tm_year + 1900) * 10000 +
|
||||
static_cast<std::int64_t>(tm->tm_mon + 1) * 100 + tm->tm_mday;
|
||||
std::tm tmv;
|
||||
if (!util::localTime(static_cast<std::time_t>(ts), tmv)) return -1;
|
||||
return static_cast<std::int64_t>(tmv.tm_year + 1900) * 10000 +
|
||||
static_cast<std::int64_t>(tmv.tm_mon + 1) * 100 + tmv.tm_mday;
|
||||
}
|
||||
|
||||
// Date-separator label: "Today" / "Yesterday" / "Jul 16, 2026". UI thread only.
|
||||
@@ -168,11 +166,10 @@ std::string chatDaySeparator(std::int64_t ts, std::int64_t todayKey, std::int64_
|
||||
const std::int64_t k = chatDayKey(ts);
|
||||
if (k == todayKey) return TR("chat_today");
|
||||
if (k == yestKey) return TR("chat_yesterday");
|
||||
std::time_t t = static_cast<std::time_t>(ts);
|
||||
std::tm* tm = std::localtime(&t);
|
||||
if (!tm) return "";
|
||||
std::tm tmv;
|
||||
if (!util::localTime(static_cast<std::time_t>(ts), tmv)) return "";
|
||||
char buf[32];
|
||||
std::strftime(buf, sizeof(buf), "%b %d, %Y", tm);
|
||||
std::strftime(buf, sizeof(buf), "%b %d, %Y", &tmv);
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -185,11 +182,10 @@ std::string relativeTime(std::int64_t ts) {
|
||||
if (d < 3600) return std::to_string(d / 60) + "m";
|
||||
if (d < 86400) return std::to_string(d / 3600) + "h";
|
||||
if (d < 7 * 86400) return std::to_string(d / 86400) + "d";
|
||||
std::time_t t = static_cast<std::time_t>(ts);
|
||||
std::tm* tm = std::localtime(&t);
|
||||
if (!tm) return "";
|
||||
std::tm tmv;
|
||||
if (!util::localTime(static_cast<std::time_t>(ts), tmv)) return "";
|
||||
char buf[16];
|
||||
std::strftime(buf, sizeof(buf), "%b %d", tm);
|
||||
std::strftime(buf, sizeof(buf), "%b %d", &tmv);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user