Common: Add helper for thread-safe localtime()

And use it with fmt instead of fmt::localtime.
pull/3568/head
Stenzek 2 months ago
parent aa929370ba
commit ae77a82ba3
No known key found for this signature in database

@ -56,6 +56,7 @@ add_library(common
small_string.h small_string.h
string_util.cpp string_util.cpp
string_util.h string_util.h
time_helpers.h
thirdparty/SmallVector.cpp thirdparty/SmallVector.cpp
thirdparty/SmallVector.h thirdparty/SmallVector.h
thirdparty/aes.cpp thirdparty/aes.cpp

@ -23,6 +23,7 @@
<ClInclude Include="heap_array.h" /> <ClInclude Include="heap_array.h" />
<ClInclude Include="intrin.h" /> <ClInclude Include="intrin.h" />
<ClInclude Include="layered_settings_interface.h" /> <ClInclude Include="layered_settings_interface.h" />
<ClInclude Include="time_helpers.h" />
<ClInclude Include="log.h" /> <ClInclude Include="log.h" />
<ClInclude Include="log_channels.h" /> <ClInclude Include="log_channels.h" />
<ClInclude Include="lru_cache.h" /> <ClInclude Include="lru_cache.h" />
@ -105,6 +106,9 @@
<ItemGroup> <ItemGroup>
<None Include="thirdparty\usb_key_code_data.inl" /> <None Include="thirdparty\usb_key_code_data.inl" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />
</ItemGroup>
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\marmasm.targets" /> <Import Project="$(VCTargetsPath)\BuildCustomizations\marmasm.targets" />
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" /> <Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />

@ -57,6 +57,7 @@
<ClInclude Include="thirdparty\usb_key_code_data.h"> <ClInclude Include="thirdparty\usb_key_code_data.h">
<Filter>thirdparty</Filter> <Filter>thirdparty</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="time_helpers.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="small_string.cpp" /> <ClCompile Include="small_string.cpp" />
@ -112,4 +113,7 @@
<Filter>thirdparty</Filter> <Filter>thirdparty</Filter>
</None> </None>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />
</ItemGroup>
</Project> </Project>

@ -0,0 +1,21 @@
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
#pragma once
#include <ctime>
namespace Common {
inline std::tm LocalTime(std::time_t tvalue)
{
std::tm ttime;
#ifdef _MSC_VER
localtime_s(&ttime, &tvalue);
#else
localtime_r(&tvalue, &ttime);
#endif
return ttime;
}
} // namespace Common

@ -27,6 +27,7 @@
#include "common/progress_callback.h" #include "common/progress_callback.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "common/thirdparty/SmallVector.h" #include "common/thirdparty/SmallVector.h"
#include "common/time_helpers.h"
#include "common/timer.h" #include "common/timer.h"
#include "fmt/format.h" #include "fmt/format.h"
@ -1592,17 +1593,8 @@ std::string GameList::FormatTimestamp(std::time_t timestamp)
} }
else else
{ {
struct tm ctime = {}; const std::tm ctime = Common::LocalTime(std::time(nullptr));
struct tm ttime = {}; const std::tm ttime = Common::LocalTime(timestamp);
const std::time_t ctimestamp = std::time(nullptr);
#ifdef _MSC_VER
localtime_s(&ctime, &ctimestamp);
localtime_s(&ttime, &timestamp);
#else
localtime_r(&ctimestamp, &ctime);
localtime_r(&timestamp, &ttime);
#endif
if (ctime.tm_year == ttime.tm_year && ctime.tm_yday == ttime.tm_yday) if (ctime.tm_year == ttime.tm_year && ctime.tm_yday == ttime.tm_yday)
{ {
ret = TRANSLATE_STR("GameList", "Today"); ret = TRANSLATE_STR("GameList", "Today");

@ -34,6 +34,7 @@
#include "common/path.h" #include "common/path.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "common/thirdparty/SmallVector.h" #include "common/thirdparty/SmallVector.h"
#include "common/time_helpers.h"
#include "common/timer.h" #include "common/timer.h"
#include "IconsEmoji.h" #include "IconsEmoji.h"
@ -44,7 +45,6 @@
#include <array> #include <array>
#include <atomic> #include <atomic>
#include <chrono>
#include <cmath> #include <cmath>
#include <deque> #include <deque>
#include <mutex> #include <mutex>
@ -1157,7 +1157,8 @@ void SaveStateSelectorUI::InitializeListEntry(ListEntry* li, ExtendedSaveStateIn
if (global) if (global)
li->game_details = fmt::format(TRANSLATE_FS("SaveStateSelectorUI", "{} ({})"), ssi->title, ssi->serial); li->game_details = fmt::format(TRANSLATE_FS("SaveStateSelectorUI", "{} ({})"), ssi->title, ssi->serial);
li->summary = fmt::format(TRANSLATE_FS("SaveStateSelectorUI", DATE_TIME_FORMAT), fmt::localtime(ssi->timestamp)); li->summary = fmt::format(TRANSLATE_FS("SaveStateSelectorUI", DATE_TIME_FORMAT),
Common::LocalTime(static_cast<std::time_t>(ssi->timestamp)));
li->filename = Path::GetFileName(path); li->filename = Path::GetFileName(path);
li->slot = slot; li->slot = slot;
li->global = global; li->global = global;
@ -1440,7 +1441,7 @@ void SaveStateSelectorUI::ShowSlotOSDMessage()
FILESYSTEM_STAT_DATA sd; FILESYSTEM_STAT_DATA sd;
std::string date; std::string date;
if (!path.empty() && FileSystem::StatFile(path.c_str(), &sd)) if (!path.empty() && FileSystem::StatFile(path.c_str(), &sd))
date = fmt::format(TRANSLATE_FS("SaveStateSelectorUI", DATE_TIME_FORMAT), fmt::localtime(sd.ModificationTime)); date = fmt::format(TRANSLATE_FS("SaveStateSelectorUI", DATE_TIME_FORMAT), Common::LocalTime(sd.ModificationTime));
else else
date = TRANSLATE_STR("SaveStateSelectorUI", "no save yet"); date = TRANSLATE_STR("SaveStateSelectorUI", "no save yet");

@ -67,6 +67,7 @@
#include "common/ryml_helpers.h" #include "common/ryml_helpers.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "common/task_queue.h" #include "common/task_queue.h"
#include "common/time_helpers.h"
#include "common/timer.h" #include "common/timer.h"
#include "IconsEmoji.h" #include "IconsEmoji.h"
@ -80,6 +81,7 @@
#include "xxhash.h" #include "xxhash.h"
#include <cctype> #include <cctype>
#include <chrono>
#include <cinttypes> #include <cinttypes>
#include <cmath> #include <cmath>
#include <cstdio> #include <cstdio>
@ -351,7 +353,7 @@ static StateVars s_state;
static TinyString GetTimestampStringForFileName() static TinyString GetTimestampStringForFileName()
{ {
return TinyString::from_format("{:%Y-%m-%d-%H-%M-%S}", fmt::localtime(std::time(nullptr))); return TinyString::from_format("{:%Y-%m-%d-%H-%M-%S}", Common::LocalTime(std::time(nullptr)));
} }
bool System::PerformEarlyHardwareChecks(Error* error) bool System::PerformEarlyHardwareChecks(Error* error)

@ -37,6 +37,7 @@
#include "common/path.h" #include "common/path.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "common/threading.h" #include "common/threading.h"
#include "common/time_helpers.h"
#include "IconsEmoji.h" #include "IconsEmoji.h"
#include "fmt/format.h" #include "fmt/format.h"
@ -1415,15 +1416,8 @@ std::string Host::FormatNumber(NumberFormatType type, s64 value)
DefaultCaseIsUnreachable(); DefaultCaseIsUnreachable();
} }
struct tm ttime = {};
const std::time_t tvalue = static_cast<std::time_t>(value);
#ifdef _MSC_VER
localtime_s(&ttime, &tvalue);
#else
localtime_r(&tvalue, &ttime);
#endif
char buf[128]; char buf[128];
const std::tm ttime = Common::LocalTime(static_cast<std::time_t>(value));
std::strftime(buf, std::size(buf), format, &ttime); std::strftime(buf, std::size(buf), format, &ttime);
ret.assign(buf); ret.assign(buf);
} }

@ -34,6 +34,7 @@
#include "common/sha256_digest.h" #include "common/sha256_digest.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "common/threading.h" #include "common/threading.h"
#include "common/time_helpers.h"
#include "common/timer.h" #include "common/timer.h"
#include "fmt/format.h" #include "fmt/format.h"
@ -604,15 +605,8 @@ std::string Host::FormatNumber(NumberFormatType type, s64 value)
DefaultCaseIsUnreachable(); DefaultCaseIsUnreachable();
} }
struct tm ttime = {};
const std::time_t tvalue = static_cast<std::time_t>(value);
#ifdef _MSC_VER
localtime_s(&ttime, &tvalue);
#else
localtime_r(&tvalue, &ttime);
#endif
char buf[128]; char buf[128];
const std::tm ttime = Common::LocalTime(static_cast<std::time_t>(value));
std::strftime(buf, std::size(buf), format, &ttime); std::strftime(buf, std::size(buf), format, &ttime);
ret.assign(buf); ret.assign(buf);
} }

@ -10,6 +10,7 @@
#include "common/file_system.h" #include "common/file_system.h"
#include "common/progress_callback.h" #include "common/progress_callback.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "common/time_helpers.h"
#include "fmt/format.h" #include "fmt/format.h"
@ -572,14 +573,8 @@ std::string IsoReader::ISODirectoryEntryDateTime::GetFormattedTime() const
const s32 uts_offset = static_cast<s32>(gmt_offset) * 3600; const s32 uts_offset = static_cast<s32>(gmt_offset) * 3600;
const time_t uts = std::mktime(&utime) + uts_offset; const time_t uts = std::mktime(&utime) + uts_offset;
struct tm ltime;
#ifdef _MSC_VER
localtime_s(&ltime, &uts);
#else
localtime_r(&uts, &ltime);
#endif
char buf[128]; char buf[128];
const std::tm ltime = Common::LocalTime(uts);
const size_t len = std::strftime(buf, std::size(buf), "%c", &ltime); const size_t len = std::strftime(buf, std::size(buf), "%c", &ltime);
return std::string(buf, len); return std::string(buf, len);
} }

Loading…
Cancel
Save