diff --git a/rpcs3/Loader/ISO.cpp b/rpcs3/Loader/ISO.cpp index 43d5b9d93b..de0937c2c2 100644 --- a/rpcs3/Loader/ISO.cpp +++ b/rpcs3/Loader/ISO.cpp @@ -6,6 +6,7 @@ #include "Emu/System.h" #include "Crypto/utils.h" +#include #include #include #include @@ -839,19 +840,21 @@ static std::optional iso_read_directory_entry(fs::file& entry, const u32 start_sector = retrieve_endian_int(header.start_sector); const u32 file_size = retrieve_endian_int(header.file_size); - std::tm file_date = {}; + // The recorded ECMA-119 date holds the local time of the recorder, paired with its offset from GMT. + // std::chrono::sys_days is anchored to the UNIX epoch, so the host time zone never enters the result. + const std::chrono::year_month_day file_date + { + std::chrono::year{1900 + header.year}, + std::chrono::month{header.month}, + std::chrono::day{header.day} + }; - file_date.tm_year = header.year; - file_date.tm_mon = header.month - 1; - file_date.tm_mday = header.day; - file_date.tm_hour = header.hour; - file_date.tm_min = header.minute; - file_date.tm_sec = header.second; + // The offset from GMT is stored as a signed number of 15 minute intervals (ECMA-119 9.1.5), + // so it has to be subtracted from the recorded local time in order to obtain UTC + const auto file_time = std::chrono::sys_days{file_date} + std::chrono::hours{header.hour} + std::chrono::minutes{header.minute} + + std::chrono::seconds{header.second} - std::chrono::minutes{static_cast(header.timezone_value) * 15}; - const s16 timezone_value = header.timezone_value; - const s16 timezone_offset = (timezone_value - 50) * 15 * 60; - - const std::time_t date_time = std::mktime(&file_date) + timezone_offset; + const std::time_t date_time = static_cast(file_time.time_since_epoch().count()); // 2nd flag bit indicates whether a given fs node is a directory const bool is_directory = header.flags & 0b00000010;