SuperMarioOdysseyOnline/source/sead/time/seadDateTime.cpp

219 lines
6.1 KiB
C++

#include <nn/time.h>
#include "sead/basis/seadRawPrint.h"
#include "sead/time/seadDateTime.h"
#include "sead/time/seadDateUtil.h"
namespace sead
{
namespace
{
constexpr u32 sDaysOfMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
constexpr u32 sDaysSinceJan1[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
u32 convertCalendarDateToDaysSince1970(const CalendarTime::Date& date)
{
// 0-indexed day.
const u32 d0 = date.mDay.getValue() - 1;
const u32 m = date.mMonth.getValueOneOrigin();
SEAD_ASSERT_MSG(1 <= m && m <= 12, "wrong month. correct range is [1, 12]. your param %d", m);
const u32 y = date.mYear.getValue();
SEAD_ASSERT_MSG(y >= 1970, "wrong year. your param %d, must after 1970.", y);
const u32 days_since_jan1 = sDaysSinceJan1[m - 1];
u32 num_days = d0 + days_since_jan1;
if (m >= 3 && DateUtil::isLeapYear(date.mYear.getValue()))
num_days = d0 + days_since_jan1 + 1;
u32 num_days_since_1970 = num_days + 365 * (date.mYear.getValue() - 1970);
if (date.mYear.getValue() > 1970)
{
u32 year = 1970;
do
{
num_days_since_1970 += DateUtil::isLeapYear(year);
++year;
} while (year < date.mYear.getValue());
}
return num_days_since_1970;
}
u64 convertCalendarTimeToSeconds(const CalendarTime::Time& time)
{
return 60 * (60 * time.mHour.getValue() + time.mMinute.getValue()) + time.mSecond.getValue();
}
u64 convertCalendarDateTimeToSeconds(const CalendarTime::Date& date, const CalendarTime::Time& time)
{
const u32 y = date.mYear.getValue();
const s32 m = date.mMonth.getValueOneOrigin();
const u32 m_idx = m - 1;
SEAD_ASSERT_MSG(1 <= m && m <= 12, "wrong month. correct range is [1, 12]. your param %d", m);
u32 num_days;
if (m == 2 && DateUtil::isLeapYear(y))
num_days = sDaysOfMonth[m_idx] + 1;
else
num_days = sDaysOfMonth[m_idx];
const u32 d = date.mDay.getValue();
SEAD_ASSERT_MSG(d <= num_days, "wrong day, correct range is [1, %d] (when year %4d month %2d)",
num_days, y, m);
const u32 days_since_1970 = convertCalendarDateToDaysSince1970(date);
return 3600 * 24 * days_since_1970 + convertCalendarTimeToSeconds(time);
}
u32 convertDaysToYears(u32* days)
{
u32 days_to_remove;
u32 i = 0;
u32 year = 1969;
do
{
++year;
days_to_remove = i;
i += DateUtil::isLeapYear(year) ? 366 : 365;
} while (i <= *days);
*days -= days_to_remove;
return year;
}
s32 convertDaysToMonth(u32* days, u32 year)
{
SEAD_ASSERT_MSG(*days <= 365, "wrong days. correct range is [0, 365]. your param %d", *days);
u32 days_to_remove;
u32 month_idx = 0;
u32 i = 0;
do
{
days_to_remove = i;
i += (month_idx == 1 && DateUtil::isLeapYear(year)) ? 29 : sDaysOfMonth[month_idx];
if (*days < i)
break;
++month_idx;
} while (month_idx < 12);
*days -= days_to_remove - 1;
return 1 + month_idx;
}
} // namespace
bool DateTime::mIsInitialized = false;
DateTime::DateTime(u64 unix_time)
{
mUnixTime = unix_time;
}
DateTime::DateTime(const CalendarTime& time)
{
setUnixTime(time);
}
DateTime::DateTime(const CalendarTime::Year& year, const CalendarTime::Month& month,
const CalendarTime::Day& day, const CalendarTime::Hour& hour,
const CalendarTime::Minute& minute, const CalendarTime::Second& second)
{
setUnixTime(year, month, day, hour, minute, second);
}
u64 DateTime::setNow()
{
initializeSystemTimeModule();
nn::time::PosixTime now;
nn::time::CalendarTime ctime;
nn::time::StandardUserSystemClock::GetCurrentTime(&now);
nn::time::ToCalendarTime(&ctime, nullptr, now);
const auto year = CalendarTime::Year(ctime.year);
const auto month = CalendarTime::Month::makeFromValueOneOrigin(ctime.month);
const auto day = CalendarTime::Day(ctime.day);
const auto hour = CalendarTime::Hour(ctime.hour);
const auto minute = CalendarTime::Minute(ctime.minute);
const auto second = CalendarTime::Second(ctime.second);
setUnixTime(year, month, day, hour, minute, second);
return mUnixTime;
}
u64 DateTime::setUnixTime(const CalendarTime& time)
{
mUnixTime = convertCalendarDateTimeToSeconds(time.getDate(), time.getTime());
return mUnixTime;
}
u64 DateTime::setUnixTime(const CalendarTime::Year& year, const CalendarTime::Month& month,
const CalendarTime::Day& day, const CalendarTime::Hour& hour,
const CalendarTime::Minute& minute, const CalendarTime::Second& second)
{
CalendarTime::Date date(year, month, day);
CalendarTime::Time time(hour, minute, second);
mUnixTime = convertCalendarDateTimeToSeconds(date, time);
return mUnixTime;
}
void DateTime::getCalendarTime(CalendarTime* calendar) const
{
u32 d = mUnixTime / (3600 * 24);
const u32 y = convertDaysToYears(&d);
const u32 m = convertDaysToMonth(&d, y);
CalendarTime::Time time;
const auto reduced_time = mUnixTime % (3600 * 24);
time.mHour.setValue(reduced_time / 3600);
time.mMinute.setValue((reduced_time % 3600) / 60);
time.mSecond.setValue(reduced_time % 60);
if (calendar)
{
calendar->setDate(CalendarTime::Date(y, CalendarTime::Month::makeFromValueOneOrigin(m), d));
calendar->setTime(time);
}
}
DateSpan DateTime::diff(DateTime time) const
{
return DateSpan(mUnixTime - time.mUnixTime);
}
DateSpan DateTime::diffToNow() const
{
DateTime now(0);
now.setNow();
return now.diff(*this);
}
void DateTime::initializeSystemTimeModule()
{
if (mIsInitialized)
return;
#ifdef NNSDK
if (!nn::time::IsInitialized())
nn::time::Initialize();
#endif
mIsInitialized = true;
}
DateSpan operator-(DateTime lhs, DateTime rhs)
{
return DateSpan(lhs.getUnixTime() - rhs.getUnixTime());
}
DateTime operator-(DateTime time, DateSpan span)
{
return DateTime(time.getUnixTime() - span.getSpan());
}
DateTime operator+(DateTime time, DateSpan span)
{
return DateTime(time.getUnixTime() + span.getSpan());
}
} // namespace sead