From 9787f931c517b4f5eb06dda54ea8f9ed5773f8e0 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Fri, 9 Jan 2026 23:27:19 +0200 Subject: [PATCH 01/13] timeformat,timezone,summertime --- src/core/libraries/system/systemservice.cpp | 44 +++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/core/libraries/system/systemservice.cpp b/src/core/libraries/system/systemservice.cpp index ce5542fc8..9f0a302f6 100644 --- a/src/core/libraries/system/systemservice.cpp +++ b/src/core/libraries/system/systemservice.cpp @@ -11,6 +11,10 @@ #include "core/libraries/system/systemservice_error.h" #include "emulator.h" +#ifdef WIN32 +#include +#endif + namespace Libraries::SystemService { bool g_splash_status{true}; @@ -1909,6 +1913,19 @@ int PS4_SYSV_ABI sceSystemServiceNavigateToGoHome() { return ORBIS_OK; } +#ifdef WIN32 +struct SwTimezone { + int tz_minuteswest; + int tz_dsttime; +}; +static void Swgettimezone(SwTimezone* z) { + TIME_ZONE_INFORMATION tz{}; + DWORD state = GetTimeZoneInformation(&tz); + + z->tz_minuteswest = tz.Bias; + z->tz_dsttime = (state == TIME_ZONE_ID_DAYLIGHT) ? 1 : 0; +} +#endif s32 PS4_SYSV_ABI sceSystemServiceParamGetInt(OrbisSystemServiceParamId param_id, int* value) { // TODO this probably should be stored in config for UI configuration LOG_DEBUG(Lib_SystemService, "called param_id {}", u32(param_id)); @@ -1923,6 +1940,32 @@ s32 PS4_SYSV_ABI sceSystemServiceParamGetInt(OrbisSystemServiceParamId param_id, case OrbisSystemServiceParamId::DateFormat: *value = u32(OrbisSystemParamDateFormat::FmtDDMMYYYY); break; +#ifdef WIN32 + case OrbisSystemServiceParamId::TimeFormat: { + char format[2] = {0}; + + GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ILDATE, format, sizeof(format)); + + if (format[0] == '0') { + *value = u32(OrbisSystemParamTimeFormat::Fmt12Hour); + } else { + *value = u32(OrbisSystemParamTimeFormat::Fmt24Hour); + } + break; + } + case OrbisSystemServiceParamId::TimeZone: { + SwTimezone z{}; + Swgettimezone(&z); + *value = z.tz_minuteswest; + break; + } + case OrbisSystemServiceParamId::Summertime: { + SwTimezone z{}; + Swgettimezone(&z); + *value = z.tz_dsttime; + break; + } +#else case OrbisSystemServiceParamId::TimeFormat: *value = u32(OrbisSystemParamTimeFormat::Fmt24Hour); break; @@ -1932,6 +1975,7 @@ s32 PS4_SYSV_ABI sceSystemServiceParamGetInt(OrbisSystemServiceParamId param_id, case OrbisSystemServiceParamId::Summertime: *value = 1; break; +#endif case OrbisSystemServiceParamId::GameParentalLevel: *value = u32(OrbisSystemParamGameParentalLevel::Off); break; From 27803d99d13dcb57e0a840de17ab810bd8ec2d74 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Fri, 9 Jan 2026 23:45:31 +0200 Subject: [PATCH 02/13] linux , macos try --- src/core/libraries/system/systemservice.cpp | 31 ++++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/core/libraries/system/systemservice.cpp b/src/core/libraries/system/systemservice.cpp index 9f0a302f6..828c727ee 100644 --- a/src/core/libraries/system/systemservice.cpp +++ b/src/core/libraries/system/systemservice.cpp @@ -13,6 +13,9 @@ #ifdef WIN32 #include +#else // Linux / macOS +#include +#include #endif namespace Libraries::SystemService { @@ -1926,6 +1929,7 @@ static void Swgettimezone(SwTimezone* z) { z->tz_dsttime = (state == TIME_ZONE_ID_DAYLIGHT) ? 1 : 0; } #endif + s32 PS4_SYSV_ABI sceSystemServiceParamGetInt(OrbisSystemServiceParamId param_id, int* value) { // TODO this probably should be stored in config for UI configuration LOG_DEBUG(Lib_SystemService, "called param_id {}", u32(param_id)); @@ -1943,9 +1947,7 @@ s32 PS4_SYSV_ABI sceSystemServiceParamGetInt(OrbisSystemServiceParamId param_id, #ifdef WIN32 case OrbisSystemServiceParamId::TimeFormat: { char format[2] = {0}; - GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ILDATE, format, sizeof(format)); - if (format[0] == '0') { *value = u32(OrbisSystemParamTimeFormat::Fmt12Hour); } else { @@ -1967,14 +1969,29 @@ s32 PS4_SYSV_ABI sceSystemServiceParamGetInt(OrbisSystemServiceParamId param_id, } #else case OrbisSystemServiceParamId::TimeFormat: - *value = u32(OrbisSystemParamTimeFormat::Fmt24Hour); + *value = + u32(OrbisSystemParamTimeFormat::Fmt24Hour); // don't see a way to check that on linux break; - case OrbisSystemServiceParamId::TimeZone: - *value = +120; + case OrbisSystemServiceParamId::TimeZone: { + std::time_t now = std::time(nullptr); + std::tm local{}; + std::tm utc{}; + localtime_r(&now, &local); + gmtime_r(&now, &utc); + int offset = (local.tm_hour - utc.tm_hour) * 60 + (local.tm_min - utc.tm_min); + if (local.tm_yday != utc.tm_yday) { + offset += (local.tm_yday > utc.tm_yday) ? 1440 : -1440; + } + *value = offset; break; - case OrbisSystemServiceParamId::Summertime: - *value = 1; + } + case OrbisSystemServiceParamId::Summertime: { + std::time_t now = std::time(nullptr); + std::tm local{}; + localtime_r(&now, &local); + *value = (local.tm_isdst > 0) ? 1 : 0; break; + } #endif case OrbisSystemServiceParamId::GameParentalLevel: *value = u32(OrbisSystemParamGameParentalLevel::Off); From 2bac57caedc16ca43be6c34938428962831558a7 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Fri, 9 Jan 2026 23:57:13 +0200 Subject: [PATCH 03/13] timeformat for macOS,linux --- src/core/libraries/system/systemservice.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/core/libraries/system/systemservice.cpp b/src/core/libraries/system/systemservice.cpp index 828c727ee..c0be33ca7 100644 --- a/src/core/libraries/system/systemservice.cpp +++ b/src/core/libraries/system/systemservice.cpp @@ -15,7 +15,9 @@ #include #else // Linux / macOS #include +#include #include +#include #endif namespace Libraries::SystemService { @@ -1968,10 +1970,15 @@ s32 PS4_SYSV_ABI sceSystemServiceParamGetInt(OrbisSystemServiceParamId param_id, break; } #else - case OrbisSystemServiceParamId::TimeFormat: - *value = - u32(OrbisSystemParamTimeFormat::Fmt24Hour); // don't see a way to check that on linux + case OrbisSystemServiceParamId::TimeFormat: { + setlocale(LC_TIME, ""); + const char* fmt = nl_langinfo(T_FMT); + bool is24h = !fmt || std::strstr(fmt, "%I") == nullptr; + + *value = is24h ? u32(OrbisSystemParamTimeFormat::Fmt24Hour) + : u32(OrbisSystemParamTimeFormat::Fmt12Hour); break; + } case OrbisSystemServiceParamId::TimeZone: { std::time_t now = std::time(nullptr); std::tm local{}; From 067029717fe03d0c898d0480df2dce355e4aa56e Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Sat, 10 Jan 2026 00:50:32 +0200 Subject: [PATCH 04/13] fixed sceRtcGetCurrentClockLocalTime (thanks @red_prig) --- src/core/libraries/rtc/rtc.cpp | 36 +++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/core/libraries/rtc/rtc.cpp b/src/core/libraries/rtc/rtc.cpp index ca63d2f4d..59e090488 100644 --- a/src/core/libraries/rtc/rtc.cpp +++ b/src/core/libraries/rtc/rtc.cpp @@ -428,28 +428,32 @@ int PS4_SYSV_ABI sceRtcGetCurrentClock(OrbisRtcDateTime* pTime, int timeZone) { int PS4_SYSV_ABI sceRtcGetCurrentClockLocalTime(OrbisRtcDateTime* pTime) { LOG_TRACE(Lib_Rtc, "called"); - if (pTime == nullptr) - return ORBIS_RTC_ERROR_DATETIME_UNINITIALIZED; + return ORBIS_RTC_ERROR_INVALID_POINTER; - Kernel::OrbisKernelTimezone timeZone; - int returnValue = Kernel::sceKernelGettimezone(&timeZone); + Kernel::OrbisKernelTimespec ts{}; + int result = Kernel::sceKernelClockGettime(0, &ts); + if (result < 0) + return result; - if (returnValue >= 0) { - Kernel::OrbisKernelTimespec clocktime; + uint64_t tick_utc = (uint64_t(ts.tv_sec) * 1000000ULL) + (uint64_t(ts.tv_nsec) / 1000ULL); - // calculate total timezone offset for converting UTC to local time - uint64_t tzOffset = -(timeZone.tz_minuteswest - (timeZone.tz_dsttime * 60)); + uint64_t tick = tick_utc + 0xDCBFFEFF2BC000ULL; - if (returnValue >= 0) { - OrbisRtcTick newTick; - sceRtcGetCurrentTick(&newTick); - sceRtcTickAddMinutes(&newTick, &newTick, tzOffset); - sceRtcSetTick(pTime, &newTick); - } - } + time_t local_time{}; + Kernel::OrbisTimesec tzsec{}; - return returnValue; + result = sceKernelConvertUtcToLocaltime(tick_utc / 1000000ULL, &local_time, &tzsec, nullptr); + + if (result < 0) + return result; + + OrbisRtcTick newTick; + sceRtcGetCurrentTick(&newTick); + sceRtcTickAddMinutes(&newTick, &newTick, (tzsec.dst_sec + tzsec.west_sec) / 60); + sceRtcSetTick(pTime, &newTick); + + return ORBIS_OK; } int PS4_SYSV_ABI sceRtcGetCurrentDebugNetworkTick(OrbisRtcTick* pTick) { From 4791aab97f4608b2f9ea2f991dcf01f45db8e0ff Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Sat, 10 Jan 2026 01:00:48 +0200 Subject: [PATCH 05/13] again? --- src/core/libraries/rtc/rtc.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/core/libraries/rtc/rtc.cpp b/src/core/libraries/rtc/rtc.cpp index 59e090488..7b519b6e8 100644 --- a/src/core/libraries/rtc/rtc.cpp +++ b/src/core/libraries/rtc/rtc.cpp @@ -448,10 +448,9 @@ int PS4_SYSV_ABI sceRtcGetCurrentClockLocalTime(OrbisRtcDateTime* pTime) { if (result < 0) return result; - OrbisRtcTick newTick; - sceRtcGetCurrentTick(&newTick); - sceRtcTickAddMinutes(&newTick, &newTick, (tzsec.dst_sec + tzsec.west_sec) / 60); - sceRtcSetTick(pTime, &newTick); + OrbisRtcTick rtcTick{tick}; + sceRtcTickAddMinutes(&rtcTick, &rtcTick, (tzsec.dst_sec + tzsec.west_sec) / 60); + sceRtcSetTick(pTime, &rtcTick); return ORBIS_OK; } From 34aac5f4e4b72a1224056d0a0359bbdf514d9fcc Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Sat, 10 Jan 2026 11:16:31 +0200 Subject: [PATCH 06/13] rewrote sceRtcConvertLocalTimeToUtc,sceRtcConvertUtcToLocalTime,sceRtcGetDosTime, --- src/core/libraries/rtc/rtc.cpp | 103 ++++++++++++++++++++++++--------- 1 file changed, 75 insertions(+), 28 deletions(-) diff --git a/src/core/libraries/rtc/rtc.cpp b/src/core/libraries/rtc/rtc.cpp index 7b519b6e8..fd051122d 100644 --- a/src/core/libraries/rtc/rtc.cpp +++ b/src/core/libraries/rtc/rtc.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-FileCopyrightText: Copyright 2024-2026 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include @@ -12,7 +12,38 @@ #include "core/libraries/rtc/rtc_error.h" namespace Libraries::Rtc { +/* + * Internal code + */ +int _sceRtcTickSubMicroseconds(OrbisRtcTick* pTick0, const OrbisRtcTick* pTick1, + int64_t lSub) { // FUN_01003270 + if (!pTick0 || !pTick1) + return ORBIS_RTC_ERROR_INVALID_POINTER; + if (lSub == 0) { + pTick0->tick = pTick1->tick; + return ORBIS_OK; + } + + uint64_t t1 = pTick1->tick; + + if (lSub < 0) { + if (t1 < static_cast(-lSub)) + return ORBIS_RTC_ERROR_INVALID_VALUE; + } else { + if ((~t1) < static_cast(lSub)) + return ORBIS_RTC_ERROR_INVALID_VALUE; + } + + t1 += lSub; + pTick0->tick = t1; + + return ORBIS_OK; +} + +/* + * Module code + */ int PS4_SYSV_ABI sceRtcCheckValid(OrbisRtcDateTime* pTime) { LOG_TRACE(Lib_Rtc, "called"); @@ -69,36 +100,42 @@ int PS4_SYSV_ABI sceRtcCompareTick(OrbisRtcTick* pTick1, OrbisRtcTick* pTick2) { int PS4_SYSV_ABI sceRtcConvertLocalTimeToUtc(OrbisRtcTick* pTickLocal, OrbisRtcTick* pTickUtc) { LOG_TRACE(Lib_Rtc, "called"); - if (pTickLocal == nullptr) + if (!pTickLocal) return ORBIS_RTC_ERROR_INVALID_POINTER; - time_t seconds; - Kernel::OrbisKernelTimezone timezone; + time_t utc_time{}; + Kernel::OrbisKernelTimezone tz{}; - int convertValue = Kernel::sceKernelConvertLocaltimeToUtc( - (pTickLocal->tick - UNIX_EPOCH_TICKS) / 1000000, 0xffffffff, &seconds, &timezone, 0); + int result = Kernel::sceKernelConvertLocaltimeToUtc((pTickLocal->tick + 0xFF23400100D44000ULL) / + 1000000ULL, + 0xFFFFFFFF, &utc_time, &tz, nullptr); - if (convertValue >= 0) { - convertValue = sceRtcTickAddMinutes( - pTickUtc, pTickLocal, -(((timezone.tz_dsttime * 60) - timezone.tz_minuteswest))); + if (result >= 0) { + int64_t offset_minutes = tz.tz_dsttime + tz.tz_minuteswest; + result = sceRtcTickAddMinutes(pTickUtc, pTickLocal, -offset_minutes); } - return convertValue; + return result; } int PS4_SYSV_ABI sceRtcConvertUtcToLocalTime(OrbisRtcTick* pTickUtc, OrbisRtcTick* pTickLocal) { LOG_TRACE(Lib_Rtc, "called"); - if (pTickUtc == nullptr) return ORBIS_RTC_ERROR_INVALID_POINTER; - Kernel::OrbisKernelTimezone timeZone; - int returnValue = Kernel::sceKernelGettimezone(&timeZone); + Kernel::OrbisTimesec tsec{}; + time_t local_time{}; - sceRtcTickAddMinutes(pTickLocal, pTickUtc, - -(timeZone.tz_minuteswest - (timeZone.tz_dsttime * 60))); + // Convert PS4 UTC tick → Unix seconds + uint64_t utc_micro = (pTickUtc->tick + 0xFF23400100D44000ULL) / 1000000ULL; + s32 result = Kernel::sceKernelConvertUtcToLocaltime(utc_micro, &local_time, &tsec, nullptr); + if (result < 0) + return result; - return 0; + // Apply timezone + DST offset + const int64_t offset_us = ((tsec.dst_sec + tsec.west_sec) / 60) * 60000000LL; + + return _sceRtcTickSubMicroseconds(pTickLocal, pTickUtc, offset_us); } int PS4_SYSV_ABI sceRtcEnd() { @@ -585,19 +622,29 @@ int PS4_SYSV_ABI sceRtcGetDosTime(OrbisRtcDateTime* pTime, u32* dosTime) { if (pTime == nullptr || dosTime == nullptr) return ORBIS_RTC_ERROR_INVALID_POINTER; - int isValid = sceRtcCheckValid(pTime); - if (isValid != ORBIS_OK) { - return isValid; + // Check if the RTC time is valid + int result = sceRtcCheckValid(pTime); + if (result != ORBIS_OK) + return result; + + uint16_t year = pTime->year; + uint8_t month = pTime->month; + uint8_t day = pTime->day; + + if (year < 1980) { + *dosTime = 0; + return ORBIS_OK; + } else if (year < 2108) { + *dosTime = ((pTime->second >> 1) & 0x1F) | // seconds / 2 + ((pTime->minute & 0x3F) << 5) | // minutes + ((pTime->hour & 0x1F) << 11) | // hours + ((((month & 0x0F) * 0x20 + 0x8800 + (year * 0x200)) | (day & 0x1F)) + << 16); // day/month/year + return ORBIS_OK; + } else { + *dosTime = 0xFF9FBF7D; + return ORBIS_RTC_ERROR_INVALID_YEAR; } - - *dosTime |= (pTime->second / 2) & 0x1F; - *dosTime |= (pTime->minute & 0x3F) << 5; - *dosTime |= (pTime->hour & 0x1F) << 11; - *dosTime |= (pTime->day & 0x1F) << 16; - *dosTime |= (pTime->month & 0x0F) << 21; - *dosTime |= ((pTime->year - 1980) & 0x7F) << 25; - - return ORBIS_OK; } int PS4_SYSV_ABI sceRtcGetTick(OrbisRtcDateTime* pTime, OrbisRtcTick* pTick) { From d66ee66146dab18db7087809a3c8e60ed0c2acc1 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Sat, 10 Jan 2026 16:47:18 +0200 Subject: [PATCH 07/13] some more rtc fixes --- src/core/libraries/rtc/rtc.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/core/libraries/rtc/rtc.cpp b/src/core/libraries/rtc/rtc.cpp index fd051122d..9e056da90 100644 --- a/src/core/libraries/rtc/rtc.cpp +++ b/src/core/libraries/rtc/rtc.cpp @@ -1090,7 +1090,7 @@ int PS4_SYSV_ABI sceRtcTickAddHours(OrbisRtcTick* pTick1, OrbisRtcTick* pTick2, if (pTick1 == nullptr || pTick2 == nullptr) return ORBIS_RTC_ERROR_INVALID_POINTER; - pTick1->tick = (lAdd * 3600000000) + pTick2->tick; + pTick1->tick = (int64_t(lAdd) * 3600000000LL) + pTick2->tick; return ORBIS_OK; } @@ -1199,7 +1199,7 @@ int PS4_SYSV_ABI sceRtcTickAddWeeks(OrbisRtcTick* pTick1, OrbisRtcTick* pTick2, if (pTick1 == nullptr || pTick2 == nullptr) return ORBIS_RTC_ERROR_INVALID_POINTER; - pTick1->tick = (lAdd * 604800000000) + pTick2->tick; + pTick1->tick = (int64_t(lAdd) * 604800000000LL) + pTick2->tick; return ORBIS_OK; } @@ -1210,24 +1210,21 @@ int PS4_SYSV_ABI sceRtcTickAddYears(OrbisRtcTick* pTick1, OrbisRtcTick* pTick2, if (pTick1 == nullptr || pTick2 == nullptr) return ORBIS_RTC_ERROR_INVALID_POINTER; - OrbisRtcDateTime time; - if (lAdd == 0) { pTick1->tick = pTick2->tick; return ORBIS_OK; } - sceRtcSetTick(&time, pTick1); + OrbisRtcDateTime time{}; + sceRtcSetTick(&time, pTick2); time.year += lAdd; - int timeIsValid = sceRtcCheckValid(&time); - if (timeIsValid == ORBIS_OK) { - sceRtcGetTick(&time, pTick1); - } else { - return timeIsValid; - } + int result = sceRtcCheckValid(&time); + if (result != ORBIS_OK) + return result; + sceRtcGetTick(&time, pTick1); return ORBIS_OK; } From d469af3bd9e2a4667bc70be41c75265031183c6e Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Sat, 10 Jan 2026 17:45:56 +0200 Subject: [PATCH 08/13] sceRtcGetDayOfWeek,sceRtcGetDaysInMonth,sceRtcTickAddMinutes --- src/core/libraries/rtc/rtc.cpp | 75 ++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 25 deletions(-) diff --git a/src/core/libraries/rtc/rtc.cpp b/src/core/libraries/rtc/rtc.cpp index 9e056da90..90588e69d 100644 --- a/src/core/libraries/rtc/rtc.cpp +++ b/src/core/libraries/rtc/rtc.cpp @@ -41,6 +41,22 @@ int _sceRtcTickSubMicroseconds(OrbisRtcTick* pTick0, const OrbisRtcTick* pTick1, return ORBIS_OK; } +static const int MonthDays[2][13] = { + {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, // non-leap + {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} // leap +}; + +// Leap-year calculation +inline bool leap_year(int year) { + if (year == (((year >> 4) / 19) * 400)) { + return true; + } else if (year == (((year >> 2) / 19) * 100)) { + return false; + } else { + return (year & 3) == 0; + } +} + /* * Module code */ @@ -566,37 +582,35 @@ int PS4_SYSV_ABI sceRtcGetDayOfWeek(int year, int month, int day) { LOG_TRACE(Lib_Rtc, "called"); int sdk_version = 0; - int sdkResult = Kernel::sceKernelGetCompiledSdkVersion(&sdk_version); - if (sdkResult != ORBIS_OK) { + if (Kernel::sceKernelGetCompiledSdkVersion(&sdk_version) != ORBIS_OK) sdk_version = 0; - } + // Year/month validation if (sdk_version < 0x3000000) { - if (year < 1) { + if (year < 1) return ORBIS_RTC_ERROR_INVALID_YEAR; - } - if (month > 12 || month <= 0) { + if (month <= 0 || month > 12) return ORBIS_RTC_ERROR_INVALID_MONTH; - } } else { - if (year > 9999 || year < 1) { + if (year < 1 || year > 9999) return ORBIS_RTC_ERROR_INVALID_YEAR; - } - if (month > 12 || month <= 0) { + if (month <= 0 || month > 12) return ORBIS_RTC_ERROR_INVALID_MONTH; - } } int daysInMonth = sceRtcGetDaysInMonth(year, month); - if (day <= 0 || day > daysInMonth) return ORBIS_RTC_ERROR_INVALID_DAY; - std::chrono::sys_days chrono_time{std::chrono::year(year) / std::chrono::month(month) / - std::chrono::day(day)}; - std::chrono::weekday chrono_weekday{chrono_time}; + // Zeller's congruence adjustment + if (month < 3) { + month += 12; + year -= 1; + } - return chrono_weekday.c_encoding(); + int weekday = + ((13 * month + 8) / 5 - (year / 100) + year + (year / 4) + (year / 400) + day) % 7; + return weekday; } int PS4_SYSV_ABI sceRtcGetDaysInMonth(int year, int month) { @@ -604,16 +618,11 @@ int PS4_SYSV_ABI sceRtcGetDaysInMonth(int year, int month) { if (year <= 0) return ORBIS_RTC_ERROR_INVALID_YEAR; - if (month <= 0 || month > 12) return ORBIS_RTC_ERROR_INVALID_MONTH; - std::chrono::year chronoYear = std::chrono::year(year); - std::chrono::month chronoMonth = std::chrono::month(month); - int lastDay = static_cast(unsigned( - std::chrono::year_month_day_last{chronoYear / chronoMonth / std::chrono::last}.day())); - - return lastDay; + bool isLeap = leap_year(year); + return MonthDays[isLeap ? 1 : 0][month]; } int PS4_SYSV_ABI sceRtcGetDosTime(OrbisRtcDateTime* pTime, u32* dosTime) { @@ -1110,10 +1119,26 @@ int PS4_SYSV_ABI sceRtcTickAddMicroseconds(OrbisRtcTick* pTick1, OrbisRtcTick* p int PS4_SYSV_ABI sceRtcTickAddMinutes(OrbisRtcTick* pTick1, OrbisRtcTick* pTick2, int64_t lAdd) { LOG_TRACE(Lib_Rtc, "called"); - if (pTick1 == nullptr || pTick2 == nullptr) + if (!pTick1 || !pTick2) return ORBIS_RTC_ERROR_INVALID_POINTER; - pTick1->tick = (lAdd * 60000000) + pTick2->tick; + if (lAdd == 0) { + pTick1->tick = pTick2->tick; + return ORBIS_OK; + } + + uint64_t t1 = pTick2->tick; + int64_t ladd_mul = lAdd * 60000000LL; + + if (lAdd < 0) { + if (t1 < static_cast(-ladd_mul)) + return ORBIS_RTC_ERROR_INVALID_VALUE; + } else { + if ((~t1) < static_cast(ladd_mul)) + return ORBIS_RTC_ERROR_INVALID_VALUE; + } + + pTick1->tick = t1 + ladd_mul; return ORBIS_OK; } From 2af195658f411d2310b84df7b2640ca785f605f0 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Sat, 10 Jan 2026 17:59:58 +0200 Subject: [PATCH 09/13] one more --- src/core/libraries/rtc/rtc.cpp | 31 +++++++------------------------ 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/src/core/libraries/rtc/rtc.cpp b/src/core/libraries/rtc/rtc.cpp index 90588e69d..957b4e99f 100644 --- a/src/core/libraries/rtc/rtc.cpp +++ b/src/core/libraries/rtc/rtc.cpp @@ -485,24 +485,23 @@ int PS4_SYSV_ABI sceRtcGetCurrentClockLocalTime(OrbisRtcDateTime* pTime) { return ORBIS_RTC_ERROR_INVALID_POINTER; Kernel::OrbisKernelTimespec ts{}; - int result = Kernel::sceKernelClockGettime(0, &ts); + int result = Kernel::sceKernelClockGettime(Kernel::ORBIS_CLOCK_REALTIME, &ts); if (result < 0) return result; - uint64_t tick_utc = (uint64_t(ts.tv_sec) * 1000000ULL) + (uint64_t(ts.tv_nsec) / 1000ULL); - - uint64_t tick = tick_utc + 0xDCBFFEFF2BC000ULL; + uint64_t tick_utc = + static_cast(ts.tv_sec) * 1000000ULL + static_cast(ts.tv_nsec) / 1000ULL; + uint64_t tick = tick_utc + UNIX_EPOCH_TICKS; time_t local_time{}; Kernel::OrbisTimesec tzsec{}; - result = sceKernelConvertUtcToLocaltime(tick_utc / 1000000ULL, &local_time, &tzsec, nullptr); - if (result < 0) return result; OrbisRtcTick rtcTick{tick}; - sceRtcTickAddMinutes(&rtcTick, &rtcTick, (tzsec.dst_sec + tzsec.west_sec) / 60); + int64_t offset_minutes = (tzsec.dst_sec + tzsec.west_sec) / 60; + sceRtcTickAddMinutes(&rtcTick, &rtcTick, offset_minutes); sceRtcSetTick(pTime, &rtcTick); return ORBIS_OK; @@ -1122,23 +1121,7 @@ int PS4_SYSV_ABI sceRtcTickAddMinutes(OrbisRtcTick* pTick1, OrbisRtcTick* pTick2 if (!pTick1 || !pTick2) return ORBIS_RTC_ERROR_INVALID_POINTER; - if (lAdd == 0) { - pTick1->tick = pTick2->tick; - return ORBIS_OK; - } - - uint64_t t1 = pTick2->tick; - int64_t ladd_mul = lAdd * 60000000LL; - - if (lAdd < 0) { - if (t1 < static_cast(-ladd_mul)) - return ORBIS_RTC_ERROR_INVALID_VALUE; - } else { - if ((~t1) < static_cast(ladd_mul)) - return ORBIS_RTC_ERROR_INVALID_VALUE; - } - - pTick1->tick = t1 + ladd_mul; + pTick1->tick = pTick2->tick + (lAdd * 60000000ULL); return ORBIS_OK; } From aa9daebe0fd82f4f2fee0bfbf730b9e6f54c0f8f Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Sat, 10 Jan 2026 18:07:31 +0200 Subject: [PATCH 10/13] redone sceRtcGetCurrentClockLocalTime --- src/core/libraries/rtc/rtc.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/core/libraries/rtc/rtc.cpp b/src/core/libraries/rtc/rtc.cpp index 957b4e99f..848bd3ed4 100644 --- a/src/core/libraries/rtc/rtc.cpp +++ b/src/core/libraries/rtc/rtc.cpp @@ -481,7 +481,7 @@ int PS4_SYSV_ABI sceRtcGetCurrentClock(OrbisRtcDateTime* pTime, int timeZone) { int PS4_SYSV_ABI sceRtcGetCurrentClockLocalTime(OrbisRtcDateTime* pTime) { LOG_TRACE(Lib_Rtc, "called"); - if (pTime == nullptr) + if (!pTime) return ORBIS_RTC_ERROR_INVALID_POINTER; Kernel::OrbisKernelTimespec ts{}; @@ -489,13 +489,13 @@ int PS4_SYSV_ABI sceRtcGetCurrentClockLocalTime(OrbisRtcDateTime* pTime) { if (result < 0) return result; - uint64_t tick_utc = + uint64_t _tick = static_cast(ts.tv_sec) * 1000000ULL + static_cast(ts.tv_nsec) / 1000ULL; - uint64_t tick = tick_utc + UNIX_EPOCH_TICKS; + uint64_t tick = _tick + UNIX_EPOCH_TICKS; time_t local_time{}; Kernel::OrbisTimesec tzsec{}; - result = sceKernelConvertUtcToLocaltime(tick_utc / 1000000ULL, &local_time, &tzsec, nullptr); + result = sceKernelConvertUtcToLocaltime(_tick / 1000000ULL, &local_time, &tzsec, nullptr); if (result < 0) return result; @@ -503,7 +503,6 @@ int PS4_SYSV_ABI sceRtcGetCurrentClockLocalTime(OrbisRtcDateTime* pTime) { int64_t offset_minutes = (tzsec.dst_sec + tzsec.west_sec) / 60; sceRtcTickAddMinutes(&rtcTick, &rtcTick, offset_minutes); sceRtcSetTick(pTime, &rtcTick); - return ORBIS_OK; } From be38a26eb957cc8f06d48dc694419f9aa0827131 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Sat, 10 Jan 2026 18:11:36 +0200 Subject: [PATCH 11/13] even one more fix --- src/core/libraries/rtc/rtc.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/core/libraries/rtc/rtc.cpp b/src/core/libraries/rtc/rtc.cpp index 848bd3ed4..b96033c73 100644 --- a/src/core/libraries/rtc/rtc.cpp +++ b/src/core/libraries/rtc/rtc.cpp @@ -500,10 +500,14 @@ int PS4_SYSV_ABI sceRtcGetCurrentClockLocalTime(OrbisRtcDateTime* pTime) { return result; OrbisRtcTick rtcTick{tick}; + int64_t offset_minutes = (tzsec.dst_sec + tzsec.west_sec) / 60; - sceRtcTickAddMinutes(&rtcTick, &rtcTick, offset_minutes); - sceRtcSetTick(pTime, &rtcTick); - return ORBIS_OK; + result = sceRtcTickAddMinutes(&rtcTick, &rtcTick, offset_minutes); + if (result < 0) + return result; + + result = sceRtcSetTick(pTime, &rtcTick); + return result; } int PS4_SYSV_ABI sceRtcGetCurrentDebugNetworkTick(OrbisRtcTick* pTick) { From 16d1485eb8f54226d3365de9fff15b1edb0b7089 Mon Sep 17 00:00:00 2001 From: Stephen Miller <56742918+StevenMiller123@users.noreply.github.com> Date: Sat, 10 Jan 2026 11:53:38 -0600 Subject: [PATCH 12/13] Fix sceRtcGetCurrentClockLocalTime Fixes time issues in anywhereVR --- src/core/libraries/rtc/rtc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/libraries/rtc/rtc.cpp b/src/core/libraries/rtc/rtc.cpp index b96033c73..fb391c728 100644 --- a/src/core/libraries/rtc/rtc.cpp +++ b/src/core/libraries/rtc/rtc.cpp @@ -501,7 +501,7 @@ int PS4_SYSV_ABI sceRtcGetCurrentClockLocalTime(OrbisRtcDateTime* pTime) { OrbisRtcTick rtcTick{tick}; - int64_t offset_minutes = (tzsec.dst_sec + tzsec.west_sec) / 60; + int64_t offset_minutes = static_cast(tzsec.dst_sec + tzsec.west_sec) / 60; result = sceRtcTickAddMinutes(&rtcTick, &rtcTick, offset_minutes); if (result < 0) return result; From f9a551f749c3576d60950e287daeaf8cb265efe2 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Sun, 11 Jan 2026 22:54:33 +0200 Subject: [PATCH 13/13] some more rtc functions rewrite --- src/core/libraries/rtc/rtc.cpp | 52 ++++++++++++++-------------------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/src/core/libraries/rtc/rtc.cpp b/src/core/libraries/rtc/rtc.cpp index fb391c728..03fb1cda5 100644 --- a/src/core/libraries/rtc/rtc.cpp +++ b/src/core/libraries/rtc/rtc.cpp @@ -61,12 +61,12 @@ inline bool leap_year(int year) { * Module code */ int PS4_SYSV_ABI sceRtcCheckValid(OrbisRtcDateTime* pTime) { - LOG_TRACE(Lib_Rtc, "called"); - - if (pTime == nullptr) + if (pTime == NULL) return ORBIS_RTC_ERROR_INVALID_POINTER; - if (pTime->year == 0 || pTime->year > 9999) + uint32_t year = pTime->year; + + if (year == 0 || year > 9999) return ORBIS_RTC_ERROR_INVALID_YEAR; if (pTime->month == 0 || pTime->month > 12) @@ -75,13 +75,9 @@ int PS4_SYSV_ABI sceRtcCheckValid(OrbisRtcDateTime* pTime) { if (pTime->day == 0) return ORBIS_RTC_ERROR_INVALID_DAY; - using namespace std::chrono; - year chronoYear = year(pTime->year); - month chronoMonth = month(pTime->month); - int lastDay = - static_cast(unsigned(year_month_day_last{chronoYear / chronoMonth / last}.day())); + int leap = leap_year(year); - if (pTime->day > lastDay) + if (pTime->day > MonthDays[leap][pTime->month]) return ORBIS_RTC_ERROR_INVALID_DAY; if (pTime->hour >= 24) @@ -99,36 +95,32 @@ int PS4_SYSV_ABI sceRtcCheckValid(OrbisRtcDateTime* pTime) { return ORBIS_OK; } -int PS4_SYSV_ABI sceRtcCompareTick(OrbisRtcTick* pTick1, OrbisRtcTick* pTick2) { - LOG_TRACE(Lib_Rtc, "called"); - - if (pTick1 == nullptr || pTick2 == nullptr) +int PS4_SYSV_ABI sceRtcCompareTick(OrbisRtcTick* pTick0, OrbisRtcTick* pTick1) { + if (pTick0 == nullptr || pTick1 == nullptr) return ORBIS_RTC_ERROR_INVALID_POINTER; - if (pTick1->tick <= pTick2->tick) - return 1; - else - return 0; + int result = -1; - return ORBIS_FAIL; + if (pTick1->tick <= pTick0->tick) { + result = (-((int)(pTick1->tick < pTick0->tick))) & 1; + } + + return result; } -int PS4_SYSV_ABI sceRtcConvertLocalTimeToUtc(OrbisRtcTick* pTickLocal, OrbisRtcTick* pTickUtc) { - LOG_TRACE(Lib_Rtc, "called"); - - if (!pTickLocal) +int PS4_SYSV_ABI sceRtcConvertLocalTimeToUtc(OrbisRtcTick* pLocalTime, OrbisRtcTick* pUtc) { + if (pLocalTime == NULL) return ORBIS_RTC_ERROR_INVALID_POINTER; - time_t utc_time{}; - Kernel::OrbisKernelTimezone tz{}; + time_t utc_time; + Kernel::OrbisKernelTimezone tz; - int result = Kernel::sceKernelConvertLocaltimeToUtc((pTickLocal->tick + 0xFF23400100D44000ULL) / - 1000000ULL, - 0xFFFFFFFF, &utc_time, &tz, nullptr); + int result = Kernel::sceKernelConvertLocaltimeToUtc( + (pLocalTime->tick + 0xFF23400100D44000ULL) / 1000000ULL, 0xFFFFFFFF, &utc_time, &tz, NULL); if (result >= 0) { - int64_t offset_minutes = tz.tz_dsttime + tz.tz_minuteswest; - result = sceRtcTickAddMinutes(pTickUtc, pTickLocal, -offset_minutes); + int offset_minutes = tz.tz_dsttime + tz.tz_minuteswest; + result = sceRtcTickAddMinutes(pUtc, pLocalTime, -offset_minutes); } return result;