mirror of
https://github.com/CraftyBoss/SuperMarioOdysseyOnline.git
synced 2024-11-25 20:55:17 +00:00
196 lines
5.2 KiB
C++
196 lines
5.2 KiB
C++
#include <sead/prim/seadStringUtil.h>
|
|
#include <sead/time/seadCalendarSpan.h>
|
|
#include <sead/time/seadDateUtil.h>
|
|
|
|
namespace sead
|
|
{
|
|
namespace DateUtil
|
|
{
|
|
bool isLeapYear(u32 year)
|
|
{
|
|
#ifdef MATCHING_HACK_NX_CLANG
|
|
bool div100, div4;
|
|
return (div100 = year % 100 == 0, div4 = year % 4 == 0, !div100 & div4) | (year % 400 == 0);
|
|
#else
|
|
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
|
|
#endif
|
|
}
|
|
|
|
CalendarTime::Week calcWeekDay(const CalendarTime::Year& year, const CalendarTime::Month& month,
|
|
const CalendarTime::Day& day)
|
|
{
|
|
int y = year.getValue();
|
|
int m = month.getValueOneOrigin();
|
|
int d = day.getValue();
|
|
if (m < 3)
|
|
{
|
|
y -= 1;
|
|
m += 12;
|
|
}
|
|
d += y + (y / 4) - (y / 100) + (y / 400);
|
|
d += (26 * m + 16) / 10;
|
|
return CalendarTime::Week(d % 7);
|
|
}
|
|
|
|
void calcSecondToCalendarSpan(CalendarSpan* out_span, u64 sec)
|
|
{
|
|
if (!out_span)
|
|
return;
|
|
out_span->setDays(sec / (3600 * 24));
|
|
out_span->setHours((sec % (3600 * 24)) / 3600);
|
|
out_span->setMinutes((sec % 3600) / 60);
|
|
out_span->setSeconds(sec % 60);
|
|
}
|
|
|
|
bool parseW3CDTFSubString(bool* ok, u32* value, SafeString* str, s32* str_length,
|
|
char* out_separator, s32 parse_length, const SafeString& separators,
|
|
bool allow_null_separator, u32 value_min, u32 value_max)
|
|
{
|
|
if (*str_length < parse_length)
|
|
{
|
|
*ok = false;
|
|
return true;
|
|
}
|
|
|
|
const char c = str->at(parse_length);
|
|
if (!separators.include(c) && (!allow_null_separator || c != SafeString::cNullChar))
|
|
{
|
|
*ok = false;
|
|
return true;
|
|
}
|
|
|
|
FixedSafeString<8> buffer;
|
|
buffer.copy(*str, parse_length);
|
|
|
|
if (!StringUtil::tryParseU32(value, buffer, StringUtil::CardinalNumber::Base10) ||
|
|
*value < value_min || *value > value_max)
|
|
{
|
|
*ok = false;
|
|
return true;
|
|
}
|
|
|
|
if (c == SafeString::cNullChar)
|
|
{
|
|
*ok = true;
|
|
return true;
|
|
}
|
|
|
|
*str = str->getPart(parse_length + 1);
|
|
*str_length -= parse_length + 1;
|
|
if (out_separator)
|
|
*out_separator = c;
|
|
return false;
|
|
}
|
|
|
|
static bool parseW3CDTFStringImpl(u32* year, u32* month, u32* day, u32* hour, u32* minute,
|
|
u32* second, s32* tz_hour, s32* tz_minute,
|
|
const SafeString& string)
|
|
{
|
|
s32 len = string.calcLength();
|
|
bool ok = true;
|
|
SafeString substr = string;
|
|
char separator;
|
|
|
|
if (parseW3CDTFSubString(&ok, year, &substr, &len, &separator, 4, "-", true, 0, 0xFFFFFFFF))
|
|
return ok;
|
|
if (parseW3CDTFSubString(&ok, month, &substr, &len, &separator, 2, "-", true, 1, 12))
|
|
return ok;
|
|
if (parseW3CDTFSubString(&ok, day, &substr, &len, &separator, 2, "T", true, 1, 31))
|
|
return ok;
|
|
if (parseW3CDTFSubString(&ok, hour, &substr, &len, &separator, 2, ":", false, 0, 23))
|
|
return ok;
|
|
if (parseW3CDTFSubString(&ok, minute, &substr, &len, &separator, 2, ":+-Z", true, 0, 59))
|
|
return ok;
|
|
|
|
if (separator == ':')
|
|
{
|
|
if (parseW3CDTFSubString(&ok, second, &substr, &len, &separator, 2, ".+-Z", true, 0, 59))
|
|
return ok;
|
|
|
|
if (separator == '.')
|
|
{
|
|
if (len == 0)
|
|
return false;
|
|
|
|
auto it = substr.tokenBegin("+-Z");
|
|
++it;
|
|
auto end = substr.tokenEnd("+-Z");
|
|
|
|
// No timezone information
|
|
if (it == end)
|
|
{
|
|
*tz_hour = 0;
|
|
*tz_minute = 0;
|
|
return true;
|
|
}
|
|
|
|
separator = substr.at(it.getIndex() - 1);
|
|
substr = substr.getPart(it.getIndex());
|
|
len -= it.getIndex();
|
|
}
|
|
}
|
|
|
|
if (separator != '+' && separator != '-')
|
|
checkLength:
|
|
return len == 0;
|
|
|
|
bool done;
|
|
u32 tz_hour_abs = 0;
|
|
done = parseW3CDTFSubString(&ok, &tz_hour_abs, &substr, &len, nullptr, 2, ":", false, 0, 11);
|
|
if (ok)
|
|
{
|
|
*tz_hour = tz_hour_abs;
|
|
if (separator == '-')
|
|
*tz_hour = -tz_hour_abs;
|
|
}
|
|
if (done)
|
|
return ok;
|
|
|
|
u32 tz_minute_abs = 0;
|
|
done = parseW3CDTFSubString(&ok, &tz_minute_abs, &substr, &len, nullptr, 2, "", true, 0, 59);
|
|
if (ok)
|
|
{
|
|
*tz_minute = tz_minute_abs;
|
|
if (separator == '-')
|
|
*tz_minute = -tz_minute_abs;
|
|
|
|
if (done)
|
|
{
|
|
len -= 2;
|
|
goto checkLength;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool parseW3CDTFString(CalendarTime* out_time, CalendarSpan* time_zone, const SafeString& string)
|
|
{
|
|
u32 year = 1970;
|
|
u32 month = 1;
|
|
u32 day = 1;
|
|
u32 hour = 0;
|
|
u32 minute = 0;
|
|
u32 second = 0;
|
|
|
|
s32 tz_hour = 0;
|
|
s32 tz_minute = 0;
|
|
|
|
const bool ret = parseW3CDTFStringImpl(&year, &month, &day, &hour, &minute, &second, &tz_hour,
|
|
&tz_minute, string);
|
|
|
|
if (ret)
|
|
{
|
|
out_time->setDate({year, CalendarTime::Month::makeFromValueOneOrigin(month), day});
|
|
out_time->setTime({hour, minute, second});
|
|
|
|
time_zone->setDays(0);
|
|
time_zone->setHours(tz_hour);
|
|
time_zone->setMinutes(tz_minute);
|
|
time_zone->setSeconds(0);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
} // namespace DateUtil
|
|
} // namespace sead
|