Real Time Clock.
Module
| Version |
World |
Privilege
|
| 0.931.010-3.740.011 |
Non-secure |
Kernel
|
Libraries
Known NIDs
| Version |
Name |
World |
Visibility |
NID
|
| 0.920-3.740.011 |
SceRtcForDriver |
Non-secure |
Kernel |
0x0351D827
|
| 0.931.010-3.740.011 |
SceRtc |
Non-secure |
User |
0x3503487E
|
Types
typedef struct SceRtcTickBase { // size is 0x28-bytes
SceRtcTick tick_src_0;
SceRtcTick tick_dst_0;
int unk_0x10;
int unk_0x14;
int tick_flags_0;
int unk_0x1C;
int unk_0x20;
int unk_0x24;
} SceRtcTickBase;
// internal use. From SceRtc_data + 0x38
typedef struct SceRtcTickContext { // size is 0x140-bytes
SceRtcTickBase current_secure_tick;
SceRtcTickBase current_retained_network_tick;
SceRtcTickBase current_tool_secure_tick;
SceRtcTickBase current_gps_tick;
SceRtcTickBase current_debug_network_tick;
SceRtcTickBase unk_tick_5;
SceRtcTickBase unk_tick_6;
SceRtcTickBase unk_tick_7;
} SceRtcTickContext;
Rtc Tick
The Rtc Tick is a 64-bit integer that corresponds to the number of microseconds since 1/01/01 00:00:00.000000. A tick can be considered as the smallest unit of time usually used by PS Vita operating system and softwares.
Below are examples of Rtc Tick values and their human-readable "date-time" equivalent.
| Rtc Tick |
DateTime
|
| 0x0000000000000000 |
1/01/01 00:00:00.000000
|
| 0x0000000000000001 |
1/01/01 00:00:00.000001
|
| 0x00000000000F4240 |
1/01/01 00:00:01.000000
|
| 0x0000000003938700 |
1/01/01 00:01:00.000000
|
| 0x00000000D693A400 |
1/01/01 01:00:00.000000
|
| 0x000000141DD76000 |
1/01/02 00:00:00.000000
|
| 0x00DCBFFEFF2BC000 |
1970/01/01 00:00:00.000000
|
| 0x00E2156879BFC000 |
2017/07/29 00:00:00.000000
|
| 0x00E2CDD60F4CE000 |
2024/01/01 00:00:00.000000
|
| 0x8000000000000000 |
30134/01/10 04:00:54.775808
|
| 0xFFFFFFFFFFFFFFFF |
60267/01/19 08:01:49.551615
|
To convert a DateTime to a Rtc Tick, one can use the following approximate calculation.
#define RTC_SECOND (1 * 1000 * 1000)
#define RTC_MIN (60ull * RTC_SECOND)
#define RTC_HOUR (60ull * RTC_MIN)
#define RTC_DAY (24ull * RTC_HOUR)
#define RTC_YEAR (365ull * RTC_DAY)
rtc_tick = year * RTC_YEAR + day * RTC_DAY + hour * RTC_HOUR + min * RTC_MIN + second * RTC_SECOND + usec;
However, when you convert 1970/01/01 00:00:00.000000 to a Rtc Tick using this calculation, the result is 0xDCB731F0F1C000 (1969/09/11 00:00:00.000000), which is different from the result shown in some of the actual Rtc Tick examples.
// 0x00DCBFFEFF2BC000 - 0xDCB731F0F1C000 = 9676800000000 (just 112 day)
Up to this point, we have been doing simple calculations, but to accurately convert from DateTime to Rtc Tick, we need to take leap years into account. There were 478 leap years between 1/01/01 00:00:00.000000 and 1970/01/01 00:00:00.000000, but that not match the difference.
Therefore, to convert from DateTime to the correct Rtc Tick, the following complex calculation must be performed. Note that there is no proof yet that this calculation can convert to the correct Rtc Tick.
#define RTC_SECOND (1 * 1000 * 1000)
#define RTC_MIN (60ull * RTC_SECOND)
#define RTC_HOUR (60ull * RTC_MIN)
#define RTC_DAY (24ull * RTC_HOUR)
#define RTC_YEAR (365ull * RTC_DAY)
// O(year + month - 1)
int datetime2tick_v1(SceRtcTick *pTick, SceUInt32 year, SceUInt32 month, SceUInt32 day, SceUInt32 hour, SceUInt32 min, SceUInt32 second, SceUInt32 usec){
if(pTick == NULL || year < 1 || month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || min > 59 || second > 59 || usec > 999999){
return -1;
}
pTick->tick = 0ull;
SceBool target_year_is_leap = SCE_FALSE;
SceUInt32 leap_count = 0;
if((year % 400) == 0 || ((year % 4) == 0 && (year % 100) != 0)){
target_year_is_leap = SCE_TRUE;
}
for(int i=0;i<(year - 1);i++){
if((i % 400) == 0 || ((i % 4) == 0 && (i % 100) != 0)){
leap_count = leap_count + 1;
}
}
SceUInt64 year_diff = leap_count / 365;
SceUInt64 day_diff = leap_count % 365;
day_diff -= target_year_is_leap;
pTick->tick = (SceUInt64)(year - 1) * RTC_YEAR + year_diff * RTC_YEAR + day_diff * RTC_DAY;
for(int i=0;i<(month - 1);i++){
pTick->tick += g_month_list[target_year_is_leap * 12 + i] * RTC_DAY;
}
if((year % 4) >= 2 || ((year % 100) <= 1 && (year % 400) >= 2)){
pTick->tick -= RTC_DAY;
}
pTick->tick += (day - 1) * RTC_DAY;
pTick->tick += hour * RTC_HOUR;
pTick->tick += min * RTC_MIN;
pTick->tick += second * RTC_SECOND;
pTick->tick += usec;
return 0;
}
// O(1)
int datetime2tick_v2(SceRtcTick *pTick, const SceDateTime *pDateTime){
if(pTick == NULL){
return -1;
}
unsigned int year = pDateTime->year;
unsigned int month = pDateTime->month;
unsigned int day = pDateTime->day;
unsigned int hour = pDateTime->hour;
unsigned int minute = pDateTime->minute;
unsigned int second = pDateTime->second;
unsigned int usec = pDateTime->microsecond;
if(year < 1 || month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || minute > 59 || second > 59 || usec > 999999){
return -1;
}
pTick->tick = 0ull;
int target_year_is_leap = 0;
SceUInt32 leap_count = 0;
if((year % 400) == 0 || ((year % 4) == 0 && (year % 100) != 0)){
target_year_is_leap = 1;
}
leap_count = (year / 4) - (year / 100) + (year / 400);
SceUInt64 year_diff = leap_count / 365;
SceUInt64 day_diff = leap_count % 365;
day_diff -= target_year_is_leap;
pTick->tick = (SceUInt64)(year - 1) * RTC_YEAR + year_diff * RTC_YEAR + day_diff * RTC_DAY;
month -= 1;
SceUInt64 days_at_month = ((29 * month) + (month - 1) + (month >> 1)) - 1 + ((0x55444E >> (month * 2)) & 3) + ((0xFFC >> month) & target_year_is_leap);
pTick->tick += days_at_month * RTC_DAY;
pTick->tick += (day - 1) * RTC_DAY;
pTick->tick += hour * RTC_HOUR;
pTick->tick += minute * RTC_MIN;
pTick->tick += second * RTC_SECOND;
pTick->tick += usec;
return 0;
}
SceRtc Time Reversal Security
If some Rtc ticks in memory are lower than the constant set in SceRtc, those ticks are set to 0.
The Rtc tick constants vary per System Software version as they are updated with some System Software updates containing a newer SceRtc kernel module.
| System Software Version |
SceRtc Hardcoded Date
|
| < 1.00 |
?
|
| 1.00 - 1.67 ?1.692? |
2011/08/01
|
| 1.80 - 1.81 |
2012/06/01
|
| 2.00 - 2.61 |
2012/09/01
|
| 2.50 - 3.00 |
2013/01/01
|
| 3.30 - 3.36 |
2014/01/01
|
| 3.500.000 - 3.740.011 |
2015/01/01
|
SceRtcForDriver
Some RTC functions apparently not present on PS Vita even on 3.200.010 but present on PSP:
sceRtcTickAddMonths
sceRtcTickAddYears
sceRtcCompareTickForDriver
| Version |
NID
|
| 0.920-3.740.011 |
0x0EBB3F12
|
Returns 0 if tick_1 == tick_2, -1 if tick_1 < tick_2 and 1 else.
int sceRtcCompareTickForDriver(const SceRtcTick *tick_1, const SceRtcTick *tick_2);
sceRtcConvertLocalTimeToUtcForDriver
| Version |
NID
|
| 3.60 |
0xAD2F3544
|
sceRtcConvertUtcToLocalTimeForDriver
| Version |
NID
|
| 3.60 |
0xC6E03DD4
|
sceRtcFormatRFC2822ForDriver
| Version |
NID
|
| 3.60 |
0xBA3415F8
|
sceRtcFormatRFC2822LocalTimeForDriver
| Version |
NID
|
| 3.60 |
0x1F7FC209
|
sceRtcFormatRFC3339ForDriver
| Version |
NID
|
| 3.60 |
0xD32AC698
|
int sceRtcFormatRFC3339ForDriver(char *pszDateTime, const SceRtcTick *utc, int iTimeZoneMinutes);
sceRtcFormatRFC3339LocalTimeForDriver
| Version |
NID
|
| 3.60 |
0x35925318
|
sceRtcGetAccumulativeTimeForDriver
| Version |
NID
|
| 3.60 |
0x0A86FB04
|
Also present in PSP under the official names sceRtcGetAccumulativeTime and sceRtcGetAccumlativeTime.
SceULong64 sceRtcGetAccumulativeTimeForDriver(void);
sceRtcGetAlarmTickForDriver
| Version |
NID
|
| 3.60 |
0xC838275A
|
sceRtcGetCurrentAdNetworkTickForDriver
| Version |
NID
|
| 3.60 |
0x3E3C09A0
|
sceRtcGetCurrentClockForDriver
| Version |
NID
|
| 3.60 |
0xA930CD1A
|
sceRtcGetCurrentClockLocalTimeForDriver
| Version |
NID
|
| 3.60 |
0x7DC0DF93
|
sceRtcGetCurrentDebugNetworkTickForDriver
| Version |
NID
|
| 3.60 |
0xC141632A
|
sceRtcGetCurrentGpsTickForDriver
| Version |
NID
|
| 3.60 |
0xF69B610F
|
sceRtcGetCurrentNetworkTickForDriver
| Version |
NID
|
| 3.60 |
0xF1517B38
|
If the current NetworkTick is less than 2015/01/01, the system will ignore the registry setting and update the NetworkTick from the internet.
int sceRtcGetCurrentNetworkTickForDriver(SceRtcTick *tick);
sceRtcGetCurrentRetainedNetworkTickForDriver
| Version |
NID
|
| 3.60 |
0x40B4BCFF
|
sceRtcGetCurrentTickForDriver
| Version |
NID
|
| 3.60 |
0xDEC408D4
|
sceRtcGetCurrentSecureTickForDriver
| Version |
NID
|
| 1.03-3.60 |
0x401C0954
|
If the current SecureTick is less than 2015/01/01, it sets 0xDDDEF8B3A14000(1980/01/01 00:00:00 UTC) to the Secure Tick and returns error code 0x80251002.
int sceRtcGetCurrentSecureTickForDriver(SceRtcTick *tick);
sceRtcTickAddTicksForDriver
| Version |
NID
|
| 0.931.010-3.600.011 |
0xCE51C2A1
|
Adds time (in ticks) to a Rtc tick structure.
int sceRtcTickAddTicksForDriver(SceRtcTick *pDst, const SceRtcTick *pSrc, SceUInt64 num_ticks);
sceRtcTickAddMicrosecondsForDriver
| Version |
NID
|
| 3.200.010 |
0xA82AC5B3
|
Adds time (in microseconds) to a time structure (in nanosecond).
int sceRtcTickAddMicrosecondsForDriver(SceRtcTick *pDst, const SceRtcTick *pSrc, SceUInt64 microseconds);
sceRtcTickAddSecondsForDriver
| Version |
NID
|
| 0.931.010-3.600.011 |
0x9C8AF264
|
Adds time (in second) to a time structure (in nanosecond).
int sceRtcTickAddSecondsForDriver(SceRtcTick *pDst, const SceRtcTick *pSrc, SceUInt64 seconds);
sceRtcTickAddMinutesForDriver
| Version |
NID
|
| 3.60 |
0x0F9E02EF
|
int sceRtcTickAddMinutesForDriver(SceRtcTick *pDst, const SceRtcTick *pSrc, SceUInt64 seconds);
sceRtcTickAddHoursForDriver
| Version |
NID
|
| 3.200.010 |
0x32E50C36
|
int sceRtcTickAddHoursForDriver(SceRtcTick *pDst, const SceRtcTick *pSrc, SceUInt32 hours);
sceRtcTickAddDaysForDriver
| Version |
NID
|
| 3.60 |
0x0CB72FAF
|
Used by SceCompat#sceCompatSetUpdateState.
int sceRtcTickAddDaysForDriver(SceRtcTick *pDst, const SceRtcTick *pSrc, SceUInt32 days);
sceRtcTickAddWeeksForDriver
| Version |
NID
|
| 3.200.010 |
0x24209FBF
|
int sceRtcTickAddWeeksForDriver(SceRtcTick *pDst, const SceRtcTick *pSrc, SceUInt32 weeks);
sceRtcConvertDateTimeToTickForDriver
| Version |
NID
|
| 0.990.000-3.740.011 |
0xF139E359
|
This is a guessed name. This may be the reciprocal function of #sceRtcConvertTickToDateTimeForDriver.
int sceRtcConvertDateTimeToTickForDriver(const SceDateTime *dateTime, SceRtcTick *pTick);
sceRtcConvertTickToDateTimeForDriver
| Version |
NID
|
| 1.03-3.60 |
0x42A0DFCB
|
This is a guessed name. This may be the reciprocal function of #sceRtcConvertDateTimeToTickForDriver.
Used with the result of #sceRtcGetCurrentSecureTickForDriver. Used by SceCoredump, SceSblGcAuthMgr.
int sceRtcConvertTickToDateTimeForDriver(SceDateTime *pDateTime, const SceRtcTick *tick);
sceRtcConvertDateTimeToUnixTimeForDriver
| Version |
NID
|
| 3.60 |
0x497B5DC9
|
This is a guessed name. This may be the reciprocal function of #sceRtcConvertUnixTimeToDateTimeForDriver.
Used by SceCoredump.
int sceRtcConvertDateTimeToUnixTimeForDriver(const SceDateTime *dateTime, SceUInt64 *pMicroseconds);
sceRtcConvertUnixTimeToDateTimeForDriver
| Version |
NID
|
| 3.60 |
0xDE9F4515
|
This is a guessed name. This may be the reciprocal function of #sceRtcConvertDateTimeToUnixTimeForDriver.
This function does: microseconds * 1000000 + 0xdcbffeff2bc000. 0xdcbffeff2bc000 represents UNIX time i.e. the date 1970/01/01 00:00:00.000000. The microseconds is multiplied by 1000000 to convert from microseconds to seconds.
int sceRtcConvertUnixTimeToDateTimeForDriver(SceDateTime *pDateTime, const SceUInt32 microseconds);
sceRtcConvertDateTimeToFatTimeForDriver
| Version |
NID
|
| 3.200.010 |
0x09AF419B
|
This is a guessed name. Official name may be sceRtcFormatRFC3339LocalTimeForDriver (see PSP sceRtc).
int sceRtcConvertDateTimeToFatTimeForDriver(const SceDateTime *pDateTime, SceUInt32 *pFatTime);
sceRtcSetCurrentAuxTickForDriver
| Version |
NID
|
| 0.990.000-3.740.011 |
0xA7236656
|
int sceRtcSetCurrentAuxTickForDriver(SceRtcTick *tick);
sceRtcGetLastAdjustedTickForDriver
| Version |
NID
|
| 3.60 |
0x8A987573
|
sceRtcGetLastReincarnatedTickForDriver
| Version |
NID
|
| 3.60 |
0x3D614A9A
|
sceRtcGetSecureAlarmTickForDriver
| Version |
NID
|
| 3.60 |
0xBD53731C
|
sceRtcSynchronizeForDriver
| Version |
NID
|
| 3.60-3.74 |
0xA2D280B4
|
Initializes SceRtc internal flags.
int sceRtcSynchronizeForDriver(void);
SceRtcForDriver_ABA035B7
| Version |
NID
|
| 3.60 |
0xABA035B7
|
Reset all SceRtc internal flags to 0.
Returns 0.
int SceRtcForDriver_ABA035B7(void);
sceRtcGetCurrentToolSecureTickForDriver
| Version |
NID
|
| 0.990-3.60 |
0xA0D7899A
|
This is a guessed name.
Used on Tool only. Used when checking DevKit activation license expire date.
Creates a tick using SceKernelThreadMgr#sceKernelGetSystemTimeWideForDriver.
int sceRtcGetCurrentToolSecureTickForDriver(SceRtcTick *pTick);
sceRtcIsAlarmedForDriver
| Version |
NID
|
| 3.60 |
0xCD295F0C
|
sceRtcIsSecureAlarmedForDriver
| Version |
NID
|
| 3.60 |
0xE39F2ABE
|
sceRtcRegisterCallbackForDriver
| Version |
NID
|
| 3.60 |
0x5220870D
|
sceRtcRegisterSecureAlarmCallbackForDriver
| Version |
NID
|
| 3.60 |
0xCF84DFC0
|
sceRtcSetAlarmTickForDriver
| Version |
NID
|
| 3.60 |
0xD610C646
|
sceRtcSetConfForDriver
| Version |
NID
|
| 3.60 |
0xACFE5A9F
|
sceRtcSetCurrentDebugNetworkTickForDriver
| Version |
NID
|
| 3.60 |
0xAAB6053F
|
sceRtcSetCurrentNetworkTickForDriver
| Version |
NID
|
| 3.60 |
0x162E486E
|
sceRtcSetCurrentSecureTickForDriver
| Version |
NID
|
| 3.60 |
0x7D431C87
|
sceRtcSetCurrentTickForDriver
| Version |
NID
|
| 3.60 |
0x70A78CD2
|
sceRtcSetSecureAlarmTickForDriver
| Version |
NID
|
| 3.60 |
0x8333790D
|
sceRtcUnregisterCallbackForDriver
| Version |
NID
|
| 3.60 |
0x9546C68B
|
sceRtcUnregisterSecureAlarmCallbackForDriver
| Version |
NID
|
| 3.60 |
0xEDDC2325
|
SceRtcForDriver_FFD7A04F
| Version |
NID
|
| 3.60 |
0xFFD7A04F
|
Used indirectly by SceProcessmgr#sceKernelLibcTime.
SceRtcForDriver_9097EF0D
| Version |
NID
|
| 3.60 |
0x9097EF0D
|
Used indirectly by SceProcessmgr.
sceRtcGetDayOfWeekForDriver
| Version |
NID
|
| 3.60 |
0x0F800878
|
Used indirectly by SceProcessmgr.
int sceRtcGetDayOfWeekForDriver(SceUInt32 year, SceUInt32 month, SceUInt32 day)
sceRtcCheckValidForDriver
| Version |
NID
|
| 3.200.010 |
0xADF63D7C
|
int sceRtcCheckValidForDriver(const SceDateTime *pDateTime);
sceRtcGetTickResolutionForDriver
| Version |
NID
|
| 3.200.010-3.600.011 |
0x6965E5DF
|
Temp name was sceRtcGetOneSecondForDriver.
Returns hardcoded value 1000000 that corresponds to one second.
SceUInt32 sceRtcGetTickResolutionForDriver(void);
sceRtcIsLeapYearForDriver
| Version |
NID
|
| 3.200.010 |
0x6F96FAA5
|
SceBool sceRtcIsLeapYearForDriver(SceUInt32 year);
SceRtcForDriver_A1F41AE2
| Version |
NID
|
| 3.200.010 |
0xA1F41AE2
|
Official name may be either sceRtcGetWin32FileTime (see PSP sceRtc).
int SceRtcForDriver_A1F41AE2(SceRtcTick *pTick, const char *str);
SceRtcForDriver_BA14600F
| Version |
NID
|
| 3.200.010 |
0xBA14600F
|
Official name may be sceRtcSetWin32FileTime (see PSP sceRtc).
It may be related to FILETIME on Windows.
int SceRtcForDriver_BA14600F(SceRtcTick *pDst, SceUInt64 a2);
sceRtcGetDaysInMonthForDriver
| Version |
NID
|
| 3.200.010 |
0xC2DC38D9
|
Retrieves the number of days in the month of a specific year.
For example, in February 1970 there were 28 days versus 29 days in February 1972.
int sceRtcGetDaysInMonthForDriver(SceUInt32 year, SceUInt32 month);
SceRtc
_sceRtcGetCurrentNetworkTick
| Version |
NID
|
| 1.69-3.60 |
0x06F734FE
|
_sceRtcConvertLocalTimeToUtc
| Version |
NID
|
| 1.69-3.60 |
0x0FC8AC41
|
_sceRtcConvertUtcToLocalTime
| Version |
NID
|
| 1.69-3.60 |
0x1E61DDA4
|
_sceRtcGetCurrentTick
| Version |
NID
|
| 1.69-3.60 |
0x247EE33B
|
_sceRtcGetCurrentClock
| Version |
NID
|
| 1.69-3.60 |
0x24947354
|
sceRtcGetAccumulativeTime
| Version |
NID
|
| 1.69-3.60 |
0x258BE8EC
|
Also present in PSP under the official names sceRtcGetAccumulativeTime and sceRtcGetAccumlativeTime.
SceULong64 sceRtcGetAccumulativeTime(void);
_sceRtcFormatRFC2822
| Version |
NID
|
| 1.69-3.60 |
0x2CD6AC86
|
_sceRtcGetCurrentGpsTick
| Version |
NID
|
| 1.69-3.60 |
0x3BA820E5
|
_sceRtcGetCurrentClockLocalTime
| Version |
NID
|
| 1.69-3.60 |
0x41A6C861
|
_sceRtcFormatRFC3339LocalTime
| Version |
NID
|
| 1.69-3.60 |
0x4836474D
|
_sceRtcFormatRFC2822LocalTime
| Version |
NID
|
| 1.69-3.60 |
0x4C7ED349
|
_sceRtcFormatRFC3339
| Version |
NID
|
| 1.69-3.60 |
0x7EE2CBEF
|
_sceRtcGetCurrentRetainedNetworkTick
| Version |
NID
|
| 1.69-3.60 |
0xC17EA809
|
_sceRtcGetLastReincarnatedTick
| Version |
NID
|
| 1.69-3.60 |
0xE13D0FE5
|
_sceRtcGetLastAdjustedTick
| Version |
NID
|
| 1.69-3.60 |
0xEA157EC5
|
_sceRtcGetCurrentAdNetworkTick
| Version |
NID
|
| 3.60 |
0x76EFA8FE
|
_sceRtcGetCurrentDebugNetworkTick
| Version |
NID
|
| 3.60 |
0xBF639B21
|
How to get current time and date
See also Rtc Tick.
Getting the current time and date involves Syscon scratchpad and Syscon command 0x11. Syscon command 0x11 returns twice the number of seconds Syscon has been running since its power on. Syscon scratchpad contains at offset 0x10 the timestamp when Syscon "started" running. It is stored in the following format: microseconds since 01/01/0001 and divided by 2^19. By adding those values together, the OS obtains the current time and date.
In pseudocode:
last_reincarnated_tick = syscon_read_scratchpad(offset=0x10, size=5)
up_time_half_seconds = syscon_cmd_read(cmd=0x11, size=4)
UTC = timedelta(microseconds=last_reincarnated_tick * (1<<19)) + datetime(1, 1, 1) + timedelta(seconds=up_time_half_seconds*2)
See also