diff --git a/nx/include/switch/services/time.h b/nx/include/switch/services/time.h index 8f16f1ba..4649c614 100644 --- a/nx/include/switch/services/time.h +++ b/nx/include/switch/services/time.h @@ -17,6 +17,24 @@ typedef enum { TimeType_Default = TimeType_UserSystemClock, } TimeType; +typedef struct { + u16 year; + u8 month; + u8 day; + u8 hour; + u8 minute; + u8 second; + u8 pad; +} TimeCalendarTime; + +typedef struct { + u32 wday; ///< 0-based day-of-week. + u32 yday; ///< 0-based day-of-year. + char timezoneName[8]; ///< Timezone name string. + u32 DST; ///< 0 = no DST, 1 = DST. + s32 offset; ///< Seconds relative to UTC for this timezone. +} TimeCalendarAdditionalInfo; + Result timeInitialize(void); void timeExit(void); @@ -31,3 +49,6 @@ Result timeGetCurrentTime(TimeType type, u64 *timestamp); * @return Result code. */ Result timeSetCurrentTime(TimeType type, u64 timestamp); + +Result timeToCalendarTimeWithMyRule(u64 timestamp, TimeCalendarTime *caltime, TimeCalendarAdditionalInfo *info); + diff --git a/nx/source/runtime/newlib.c b/nx/source/runtime/newlib.c index 710b5dbd..443a23d2 100644 --- a/nx/source/runtime/newlib.c +++ b/nx/source/runtime/newlib.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include #include @@ -31,12 +33,17 @@ static struct _reent* __libnx_get_reent(void) { return tv->reent; } -//TODO: timeGetCurrentTime() returns UTC time. How to handle timezones? static u64 __boottime; static u64 __bootticks; // setup boot time variables void __libnx_init_time(void) { + TimeCalendarAdditionalInfo info; + char envstr[64]; + char *strptr; + bool is_west=0; + s32 tmp_offset, hour, minute, second; + Result rc = timeGetCurrentTime(__nx_time_type, &__boottime); if (R_FAILED(rc) && __nx_time_type != TimeType_Default) rc = timeGetCurrentTime(TimeType_Default, &__boottime); if (R_FAILED(rc)) { @@ -44,6 +51,43 @@ void __libnx_init_time(void) { } else { __bootticks = armGetSystemTick(); } + + if (R_SUCCEEDED(rc)) rc = timeToCalendarTimeWithMyRule(__boottime, NULL, &info); + + if (R_SUCCEEDED(rc)) { + info.timezoneName[7] = 0; + tmp_offset = info.offset; + if (tmp_offset < 0) { + is_west = 1; + tmp_offset = -tmp_offset; + } + + second = tmp_offset % 60; + tmp_offset /= 60; + minute = tmp_offset % 60; + tmp_offset /= 60; + hour = tmp_offset % 24; + + memset(envstr, 0, sizeof(envstr)); + + //Avoid using *printf. + strncpy(envstr, info.timezoneName, sizeof(envstr)-1); + strptr = &envstr[strlen(envstr)]; + *strptr++ = is_west ? '+' : '-'; + + *strptr++ = '0' + (hour / 10); + *strptr++ = '0' + (hour % 10); + *strptr++ = ':'; + + *strptr++ = '0' + (minute / 10); + *strptr++ = '0' + (minute % 10); + *strptr++ = ':'; + + *strptr++ = '0' + (second / 10); + *strptr++ = '0' + (second % 10); + + setenv("TZ", envstr, 0); + } } static const u64 nsec_clockres = 1000000000ULL / 19200000ULL; diff --git a/nx/source/services/time.c b/nx/source/services/time.c index e710e993..c3aeb70f 100644 --- a/nx/source/services/time.c +++ b/nx/source/services/time.c @@ -191,3 +191,41 @@ Result timeSetCurrentTime(TimeType type, u64 timestamp) { return rc; } +Result timeToCalendarTimeWithMyRule(u64 timestamp, TimeCalendarTime *caltime, TimeCalendarAdditionalInfo *info) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u64 timestamp; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 101; + raw->timestamp = timestamp; + + Result rc = serviceIpcDispatch(&g_timeTimeZoneService); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct { + u64 magic; + u64 result; + TimeCalendarTime caltime; + TimeCalendarAdditionalInfo info; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc) && caltime) memcpy(caltime, &resp->caltime, sizeof(TimeCalendarTime)); + if (R_SUCCEEDED(rc) && info) memcpy(info, &resp->info, sizeof(TimeCalendarAdditionalInfo)); + } + + return rc; +} +