diff --git a/Core/HLE/sceRtc.cpp b/Core/HLE/sceRtc.cpp index 2bf86513dd..3b1afe051d 100644 --- a/Core/HLE/sceRtc.cpp +++ b/Core/HLE/sceRtc.cpp @@ -68,6 +68,86 @@ void __RtcTmToPspTime(ScePspDateTime &t, tm *val) t.second = val->tm_sec; } +//based on http://stackoverflow.com/a/11197532 +void __RtcTicksToPspTime(ScePspDateTime &t, u64 ticks) +{ + u64 sec; + u16 quadricentennials, centennials, quadrennials, annuals/*1-ennial?*/; + u16 year, leap; + u16 yday, hour, min; + u16 month, mday, wday; + static const u16 daysSinceJan1st[2][13]= + { + {0,31,59,90,120,151,181,212,243,273,304,334,365}, // 365 days, non-leap + {0,31,60,91,121,152,182,213,244,274,305,335,366} // 366 days, leap + }; + sec = ticks / 1000000UL; + wday = (u16)((sec / 86400 + 1) % 7); // day of week + + // Remove multiples of 400 years (incl. 97 leap days) + quadricentennials = (u16)(sec / 12622780800ULL); // 400*365.2425*24*3600 + sec %= 12622780800ULL; + + // Remove multiples of 100 years (incl. 24 leap days), can't be more than 3 + // (because multiples of 4*100=400 years (incl. leap days) have been removed) + centennials = (u16)(sec / 3155673600ULL); // 100*(365+24/100)*24*3600 + if (centennials > 3) + { + centennials = 3; + } + sec -= centennials * 3155673600ULL; + + // Remove multiples of 4 years (incl. 1 leap day), can't be more than 24 + // (because multiples of 25*4=100 years (incl. leap days) have been removed) + quadrennials = (u16)(sec / 126230400); // 4*(365+1/4)*24*3600 + if (quadrennials > 24) + { + quadrennials = 24; + } + sec -= quadrennials * 126230400ULL; + + // Remove multiples of years (incl. 0 leap days), can't be more than 3 + // (because multiples of 4 years (incl. leap days) have been removed) + annuals = (u16)(sec / 31536000); // 365*24*3600 + if (annuals > 3) + { + annuals = 3; + } + sec -= annuals * 31536000ULL; + + // Calculate the year and find out if it's leap + year = 1 + quadricentennials * 400 + centennials * 100 + quadrennials * 4 + annuals; + leap = !(year % 4) && (year % 100 || !(year % 400)); + + // Calculate the day of the year and the time + yday = sec / 86400; + sec %= 86400; + hour = sec / 3600; + sec %= 3600; + min = sec / 60; + sec %= 60; + + // Calculate the month + for (mday = month = 1; month < 13; month++) + { + if (yday < daysSinceJan1st[leap][month]) + { + mday += yday - daysSinceJan1st[leap][month - 1]; + break; + } + } + + t.year = year; + t.month = month; + t.day = mday; + t.hour = hour; + t.minute = min; + t.second = sec; + t.microsecond = ticks % 1000000; +} + + + bool __RtcValidatePspTime(ScePspDateTime &t) { return t.year > 0; @@ -140,13 +220,13 @@ u32 sceRtcGetCurrentClockLocalTime(u32 pspTimePtr) u32 sceRtcSetTick(u32 pspTimePtr, u32 tickPtr) { - DEBUG_LOG(HLE, "HACK sceRtcSetTick(%08x, %08x)", pspTimePtr, tickPtr); + DEBUG_LOG(HLE, "sceRtcSetTick(%08x, %08x)", pspTimePtr, tickPtr); if (Memory::IsValidAddress(pspTimePtr) && Memory::IsValidAddress(tickPtr)) { - time_t sec = (time_t)Memory::Read_U64(tickPtr); - tm *local = localtime(&sec); + time_t seconds = Memory::Read_U64(tickPtr); + ScePspDateTime ret; - __RtcTmToPspTime(ret, local); + __RtcTicksToPspTime(ret, seconds); Memory::WriteStruct(pspTimePtr, &ret); } return 0; @@ -273,4 +353,3 @@ void Register_sceRtc() { RegisterModule("sceRtc", ARRAY_SIZE(sceRtc), sceRtc); } -