1#ifdef NNSDK
2#include <nn/time.h>
3#else
4#error "Unknown platform"
5#endif
6
7#include "basis/seadRawPrint.h"
8#include "time/seadDateTime.h"
9#include "time/seadDateUtil.h"
10
11namespace sead
12{
13namespace
14{
15constexpr u32 sDaysOfMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
16constexpr u32 sDaysSinceJan1[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
17
18u32 convertCalendarDateToDaysSince1970(const CalendarTime::Date& date)
19{
20 // 0-indexed day.
21 const u32 d0 = date.mDay.getValue() - 1;
22
23 const u32 m = date.mMonth.getValueOneOrigin();
24 SEAD_ASSERT_MSG(1 <= m && m <= 12, "wrong month. correct range is [1, 12]. your param %d", m);
25
26 const u32 y = date.mYear.getValue();
27 SEAD_ASSERT_MSG(y >= 1970, "wrong year. your param %d, must after 1970.", y);
28
29 const u32 days_since_jan1 = sDaysSinceJan1[m - 1];
30
31 u32 num_days = d0 + days_since_jan1;
32 if (m >= 3 && DateUtil::isLeapYear(year: date.mYear.getValue()))
33 num_days = d0 + days_since_jan1 + 1;
34
35 u32 num_days_since_1970 = num_days + 365 * (date.mYear.getValue() - 1970);
36 if (date.mYear.getValue() > 1970)
37 {
38 u32 year = 1970;
39 do
40 {
41 num_days_since_1970 += DateUtil::isLeapYear(year);
42 ++year;
43 } while (year < date.mYear.getValue());
44 }
45
46 return num_days_since_1970;
47}
48
49u64 convertCalendarTimeToSeconds(const CalendarTime::Time& time)
50{
51 return 60 * (60 * time.mHour.getValue() + time.mMinute.getValue()) + time.mSecond.getValue();
52}
53
54u64 convertCalendarDateTimeToSeconds(const CalendarTime::Date& date, const CalendarTime::Time& time)
55{
56 const u32 y = date.mYear.getValue();
57
58 const s32 m = date.mMonth.getValueOneOrigin();
59 const u32 m_idx = m - 1;
60 SEAD_ASSERT_MSG(1 <= m && m <= 12, "wrong month. correct range is [1, 12]. your param %d", m);
61
62 u32 num_days;
63 if (m == 2 && DateUtil::isLeapYear(year: y))
64 num_days = sDaysOfMonth[m_idx] + 1;
65 else
66 num_days = sDaysOfMonth[m_idx];
67
68 const u32 d = date.mDay.getValue();
69 SEAD_ASSERT_MSG(d <= num_days, "wrong day, correct range is [1, %d] (when year %4d month %2d)",
70 num_days, y, m);
71
72 const u32 days_since_1970 = convertCalendarDateToDaysSince1970(date);
73 return 3600 * 24 * days_since_1970 + convertCalendarTimeToSeconds(time);
74}
75
76u32 convertDaysToYears(u32* days)
77{
78 u32 days_to_remove;
79 u32 i = 0;
80 u32 year = 1969;
81 do
82 {
83 ++year;
84 days_to_remove = i;
85 i += DateUtil::isLeapYear(year) ? 366 : 365;
86 } while (i <= *days);
87 *days -= days_to_remove;
88 return year;
89}
90
91s32 convertDaysToMonth(u32* days, u32 year)
92{
93 SEAD_ASSERT_MSG(*days <= 365, "wrong days. correct range is [0, 365]. your param %d", *days);
94 u32 days_to_remove;
95 u32 month_idx = 0;
96 u32 i = 0;
97 do
98 {
99 days_to_remove = i;
100 i += (month_idx == 1 && DateUtil::isLeapYear(year)) ? 29 : sDaysOfMonth[month_idx];
101 if (*days < i)
102 break;
103 ++month_idx;
104 } while (month_idx < 12);
105 *days -= days_to_remove - 1;
106 return 1 + month_idx;
107}
108} // namespace
109
110bool DateTime::mIsInitialized = false;
111
112DateTime::DateTime(u64 unix_time)
113{
114 mUnixTime = unix_time;
115}
116
117DateTime::DateTime(const CalendarTime& time)
118{
119 setUnixTime(time);
120}
121
122DateTime::DateTime(const CalendarTime::Year& year, const CalendarTime::Month& month,
123 const CalendarTime::Day& day, const CalendarTime::Hour& hour,
124 const CalendarTime::Minute& minute, const CalendarTime::Second& second)
125{
126 setUnixTime(year, month, day, hour, minute, second);
127}
128
129u64 DateTime::setNow()
130{
131#ifdef NNSDK
132 initializeSystemTimeModule();
133
134 nn::time::PosixTime now;
135 nn::time::CalendarTime ctime;
136 nn::time::StandardUserSystemClock::GetCurrentTime(&now);
137 nn::time::ToCalendarTime(&ctime, nullptr, now);
138
139 const auto year = CalendarTime::Year(ctime.year);
140 const auto month = CalendarTime::Month::makeFromValueOneOrigin(month: ctime.month);
141 const auto day = CalendarTime::Day(ctime.day);
142 const auto hour = CalendarTime::Hour(ctime.hour);
143 const auto minute = CalendarTime::Minute(ctime.minute);
144 const auto second = CalendarTime::Second(ctime.second);
145 setUnixTime(year, month, day, hour, minute, second);
146#endif
147 return mUnixTime;
148}
149
150u64 DateTime::setUnixTime(const CalendarTime& time)
151{
152 mUnixTime = convertCalendarDateTimeToSeconds(date: time.getDate(), time: time.getTime());
153 return mUnixTime;
154}
155
156u64 DateTime::setUnixTime(const CalendarTime::Year& year, const CalendarTime::Month& month,
157 const CalendarTime::Day& day, const CalendarTime::Hour& hour,
158 const CalendarTime::Minute& minute, const CalendarTime::Second& second)
159{
160 CalendarTime::Date date(year, month, day);
161 CalendarTime::Time time(hour, minute, second);
162 mUnixTime = convertCalendarDateTimeToSeconds(date, time);
163 return mUnixTime;
164}
165
166void DateTime::getCalendarTime(CalendarTime* calendar) const
167{
168 u32 d = mUnixTime / (3600 * 24);
169 const u32 y = convertDaysToYears(days: &d);
170 const u32 m = convertDaysToMonth(days: &d, year: y);
171
172 CalendarTime::Time time;
173 const auto reduced_time = mUnixTime % (3600 * 24);
174 time.mHour.setValue(reduced_time / 3600);
175 time.mMinute.setValue((reduced_time % 3600) / 60);
176 time.mSecond.setValue(reduced_time % 60);
177
178 if (calendar)
179 {
180 calendar->setDate(CalendarTime::Date(y, CalendarTime::Month::makeFromValueOneOrigin(month: m), d));
181 calendar->setTime(time);
182 }
183}
184
185DateSpan DateTime::diff(DateTime time) const
186{
187 return DateSpan(mUnixTime - time.mUnixTime);
188}
189
190DateSpan DateTime::diffToNow() const
191{
192 DateTime now(0);
193 now.setNow();
194 return now.diff(time: *this);
195}
196
197void DateTime::initializeSystemTimeModule()
198{
199 if (mIsInitialized)
200 return;
201
202#ifdef NNSDK
203 if (!nn::time::IsInitialized())
204 nn::time::Initialize();
205#endif
206
207 mIsInitialized = true;
208}
209
210DateSpan operator-(DateTime lhs, DateTime rhs)
211{
212 return DateSpan(lhs.getUnixTime() - rhs.getUnixTime());
213}
214
215DateTime operator-(DateTime time, DateSpan span)
216{
217 return DateTime(time.getUnixTime() - span.getSpan());
218}
219
220DateTime operator+(DateTime time, DateSpan span)
221{
222 return DateTime(time.getUnixTime() + span.getSpan());
223}
224} // namespace sead
225