1 /*---------------------------------------------------------------------------* 2 Project: Horizon 3 File: fnd_DateTime.cpp 4 5 Copyright (C)2009-2012 Nintendo Co., Ltd. All rights reserved. 6 7 These coded instructions, statements, and computer programs contain 8 proprietary information of Nintendo of America Inc. and/or Nintendo 9 Company Ltd., and are protected by Federal copyright law. They may 10 not be disclosed to third parties or copied or duplicated in any form, 11 in whole or in part, without the prior written consent of Nintendo. 12 13 $Rev: 47227 $ 14 *---------------------------------------------------------------------------*/ 15 16 #include <nn/fnd/fnd_DateTime.h> 17 #include <nn/os/os_SharedInfo.h> 18 #include <nn/assert.h> 19 #include <nn/ptm/CTR/ptm_Rtc.h> 20 #include <algorithm> 21 22 namespace 23 { 24 static const s32 MILLISECONDS_DAY = 1000 * 60 * 60 * 24; 25 Modulo32(s32 a,s32 b)26 inline s32 Modulo32(s32 a, s32 b) 27 { 28 return (((a % b) + b) % b); 29 } 30 AlignedDays(s64 milliSeconds)31 inline s32 AlignedDays(s64 milliSeconds) 32 { 33 s64 ms = milliSeconds + ( 730119LL * MILLISECONDS_DAY); 34 return ms / MILLISECONDS_DAY - 730119LL; 35 } 36 MilliSecondsOnDay(s64 milliSeconds)37 inline s32 MilliSecondsOnDay(s64 milliSeconds) 38 { 39 s64 ms = milliSeconds + (730119LL * MILLISECONDS_DAY); 40 return ms % MILLISECONDS_DAY; 41 } 42 } 43 44 namespace nn { namespace fnd { 45 46 const DateTime DateTime::MAX_DATETIME = DateTime(DateTime::MAX_MILLISECONDS); 47 const DateTime DateTime::MIN_DATETIME = DateTime(DateTime::MIN_MILLISECONDS); 48 IsLeapYear(s32 year)49 s32 DateTime::IsLeapYear(s32 year) 50 { 51 if ( year % 400 == 0 ) 52 { 53 return 1; 54 } 55 else if ( year % 100 == 0 ) 56 { 57 return 0; 58 } 59 else if ( year % 4 == 0 ) 60 { 61 return 1; 62 } 63 else 64 { 65 return 0; 66 } 67 } 68 IsValidDate(s32 year,s32 month,s32 day)69 bool DateTime::IsValidDate(s32 year, s32 month, s32 day) 70 { 71 const s32 monthdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 72 const s64 startYear = DateTime(MIN_MILLISECONDS).GetYear(); 73 const s64 endYear = DateTime(MAX_MILLISECONDS).GetYear(); 74 75 if ( !(startYear <= year && year <= endYear) ) 76 { 77 return false; 78 } 79 80 if ( !(1 <= month && month <= 12) ) 81 { 82 return false; 83 } 84 85 s32 mdays; 86 if ( month == 2 ) 87 { 88 mdays = monthdays[month-1] + IsLeapYear(year); 89 } 90 else 91 { 92 mdays = monthdays[month-1]; 93 } 94 95 return 1 <= day && day <= mdays; 96 } 97 IsValidParameters(s32 year,s32 month,s32 day,s32 hour,s32 minute,s32 second,s32 millisecond)98 bool DateTime::IsValidParameters(s32 year, s32 month, s32 day, s32 hour, s32 minute, s32 second, s32 millisecond) 99 { 100 return IsValidDate(year,month,day) 101 && 0 <= hour && hour < 24 102 && 0 <= minute && minute < 60 103 && 0 <= second && second < 60 104 && 0 <= millisecond && millisecond < 1000; 105 } 106 IsValidParameters(const DateTimeParameters & dateTimeParameters)107 bool DateTime::IsValidParameters(const DateTimeParameters &dateTimeParameters) 108 { 109 return IsValidParameters( 110 dateTimeParameters.year, 111 dateTimeParameters.month, 112 dateTimeParameters.day, 113 dateTimeParameters.hour, 114 dateTimeParameters.minute, 115 dateTimeParameters.second, 116 dateTimeParameters.milliSecond) 117 && dateTimeParameters.week 118 == DaysToWeekday(DateToDays( 119 dateTimeParameters.year, 120 dateTimeParameters.month, 121 dateTimeParameters.day)); 122 } 123 DateToDays(s32 year,s32 month,s32 day)124 s32 DateTime::DateToDays(s32 year, s32 month, s32 day) 125 { 126 NN_TASSERT_(DateTime::IsValidDate(year,month,day)); 127 128 day -= 1; 129 year -= 2000; 130 131 if ( month <= 2 ){ 132 month += (12 - 3); 133 year -= 1; 134 } 135 else{ 136 month -= 3; 137 } 138 139 int offset = 1; 140 141 if ( year < 0 ) 142 { 143 offset = IsLeapYear(year); 144 } 145 146 return ((((365 * 4 + 1) * 25 - 1) * 4 + 1) * (year / 100) / 4) 147 + (( 365 * 4 + 1) * (year % 100) / 4) 148 + (153 * month + 2) / 5 149 + day + (31 + 28) 150 + offset; 151 } 152 DaysToDate(s32 * pYear,s32 * pMonth,s32 * pDay,s32 days)153 void DateTime::DaysToDate(s32 *pYear, s32 *pMonth, s32 *pDay, s32 days) 154 { 155 const s32 c4days = (((365 * 4 + 1) * 25 - 1) * 4 + 1); 156 const s32 c1days = ((365 * 4 + 1) * 25 - 1); 157 const s32 y4days = (365 * 4 + 1); 158 const s32 y1days = 365; 159 s32 year, month, day; 160 161 days -= 31 + 29; 162 163 s32 c4 = days / c4days; 164 s32 c4ds = days % c4days; 165 166 if ( c4ds < 0) 167 { 168 c4ds += c4days; 169 c4 -= 1; 170 } 171 172 s32 c1 = c4ds / c1days; 173 s32 c1ds = c4ds % c1days; 174 s32 y4 = c1ds / y4days; 175 s32 y4ds = c1ds % y4days; 176 s32 y1 = y4ds / y1days; 177 s32 ydays = y4ds % y1days; 178 179 year = 2000 + c4 * 400 + c1 * 100 + y4 * 4 + y1; 180 month = (5 * ydays + 2) / 153; 181 day = ydays - (153 * month + 2) / 5 + 1; 182 183 if (y1 == 4 || c1 == 4) 184 { 185 month = 2 + (12 - 3); 186 day = 29; 187 year -= 1; 188 } 189 190 if ( month <= (12-3) ) 191 { 192 month += 3; 193 } 194 else 195 { 196 month -= 12 - 3; 197 year += 1; 198 } 199 200 if ( pYear ) 201 { 202 *pYear = year; 203 } 204 if ( pMonth ) 205 { 206 *pMonth = month; 207 } 208 if ( pDay ) 209 { 210 *pDay = day; 211 } 212 } 213 DaysToWeekday(s32 days)214 Week DateTime::DaysToWeekday(s32 days) 215 { 216 return static_cast<Week>(Modulo32((days + WEEK_SATURDAY), WEEK_MAX)); 217 } 218 DateTime(s32 year,s32 month,s32 day,s32 hour,s32 minute,s32 second,s32 millisecond)219 DateTime::DateTime(s32 year, s32 month, s32 day, s32 hour, s32 minute, s32 second, s32 millisecond) 220 :m_MilliSeconds( 221 DateTime::FromParameters(year,month,day,hour,minute,second,millisecond).m_MilliSeconds) 222 { 223 NN_TASSERT_(MIN_MILLISECONDS <= m_MilliSeconds && m_MilliSeconds <= MAX_MILLISECONDS); 224 } 225 226 GetYear() const227 s32 DateTime::GetYear() const 228 { 229 s32 year; 230 DaysToDate( 231 &year, 232 NULL, 233 NULL, 234 AlignedDays(m_MilliSeconds)); 235 return year; 236 } 237 GetMonth() const238 s32 DateTime::GetMonth() const 239 { 240 s32 month; 241 DaysToDate( 242 NULL, 243 &month, 244 NULL, 245 AlignedDays(m_MilliSeconds)); 246 return month; 247 } 248 GetDay() const249 s32 DateTime::GetDay() const 250 { 251 s32 day; 252 DaysToDate( 253 NULL, 254 NULL, 255 &day, 256 AlignedDays(m_MilliSeconds)); 257 return day; 258 } 259 GetWeek() const260 Week DateTime::GetWeek() const 261 { 262 return DaysToWeekday( 263 AlignedDays(m_MilliSeconds)); 264 } 265 GetHour() const266 s32 DateTime::GetHour() const 267 { 268 return MilliSecondsOnDay(m_MilliSeconds) / 1000 / 60 / 60 % 24; 269 } 270 GetMinute() const271 s32 DateTime::GetMinute() const 272 { 273 return MilliSecondsOnDay(m_MilliSeconds) / 1000 / 60 % 60; 274 } 275 GetSecond() const276 s32 DateTime::GetSecond() const 277 { 278 return MilliSecondsOnDay(m_MilliSeconds) / 1000 % 60; 279 } 280 GetMilliSecond() const281 s32 DateTime::GetMilliSecond() const 282 { 283 return MilliSecondsOnDay(m_MilliSeconds) % 1000; 284 } 285 FromParameters(s32 year,s32 month,s32 day,s32 hour,s32 minute,s32 second,s32 millisecond)286 DateTime DateTime::FromParameters(s32 year, s32 month, s32 day, s32 hour, s32 minute, s32 second, s32 millisecond) 287 { 288 NN_TASSERT_(IsValidParameters(year, month, day, hour, minute, second, millisecond)); 289 DateTime datetime; 290 datetime.m_MilliSeconds = 291 millisecond 292 + 1000LL * second 293 + 1000LL * 60 * minute 294 + 1000LL * 60 * 60 * hour 295 + 1000LL * 60 * 60 * 24 * static_cast<s64>(DateToDays(year,month,day)); 296 return datetime; 297 } 298 FromParameters(const DateTimeParameters & dateTimeParameters)299 DateTime DateTime::FromParameters(const DateTimeParameters &dateTimeParameters) 300 { 301 return FromParameters( 302 dateTimeParameters.year, 303 dateTimeParameters.month, 304 dateTimeParameters.day, 305 dateTimeParameters.hour, 306 dateTimeParameters.minute, 307 dateTimeParameters.second, 308 dateTimeParameters.milliSecond); 309 } 310 ReplaceMilliSecond(s32 millisecond) const311 DateTime DateTime::ReplaceMilliSecond(s32 millisecond) const 312 { 313 NN_TASSERT_(0 <= millisecond && millisecond < 1000); 314 return *this + TimeSpan::FromMilliSeconds(millisecond - GetMilliSecond()); 315 } 316 ReplaceSecond(s32 second) const317 DateTime DateTime::ReplaceSecond(s32 second) const 318 { 319 NN_TASSERT_(0 <= second && second < 60); 320 return *this + TimeSpan::FromSeconds(second - GetSecond()); 321 } 322 ReplaceMinute(s32 minute) const323 DateTime DateTime::ReplaceMinute(s32 minute) const 324 { 325 NN_TASSERT_(0 <= minute && minute < 60); 326 return *this + TimeSpan::FromMinutes(minute - GetMinute()); 327 } 328 ReplaceHour(s32 hour) const329 DateTime DateTime::ReplaceHour(s32 hour) const 330 { 331 NN_TASSERT_(0 <= hour && hour < 24); 332 return *this + TimeSpan::FromHours(hour - GetHour()); 333 } 334 ReplaceDay(s32 day) const335 DateTime DateTime::ReplaceDay(s32 day) const 336 { 337 s32 year,month; 338 DaysToDate( 339 &year, 340 &month, 341 NULL, 342 AlignedDays(m_MilliSeconds)); 343 return FromParameters( 344 year, 345 month, 346 day, 347 GetHour(), 348 GetMinute(), 349 GetSecond(), 350 GetMilliSecond()); 351 } 352 ReplaceMonth(s32 month) const353 DateTime DateTime::ReplaceMonth(s32 month) const 354 { 355 s32 year,day; 356 DaysToDate( 357 &year, 358 NULL, 359 &day, 360 AlignedDays(m_MilliSeconds)); 361 return FromParameters( 362 year, 363 month, 364 day, 365 GetHour(), 366 GetMinute(), 367 GetSecond(), 368 GetMilliSecond()); 369 } 370 ReplaceYear(s32 year) const371 DateTime DateTime::ReplaceYear(s32 year) const 372 { 373 s32 month,day; 374 DaysToDate( 375 NULL, 376 &month, 377 &day, 378 AlignedDays(m_MilliSeconds)); 379 return FromParameters( 380 year, 381 month, 382 day, 383 GetHour(), 384 GetMinute(), 385 GetSecond(), 386 GetMilliSecond()); 387 } 388 GetNow()389 DateTime DateTime::GetNow() 390 { 391 return nn::fnd::DateTime::MIN_DATETIME 392 #ifdef NN_PROCESSOR_ARM11MPCORE 393 + nn::fnd::TimeSpan::FromMilliSeconds(nn::ptm::CTR::detail::GetSwcMilliSeconds()) 394 #endif 395 ; 396 } 397 GetParameters() const398 DateTimeParameters DateTime::GetParameters() const 399 { 400 DateTimeParameters parameters; 401 402 s32 msec = MilliSecondsOnDay(m_MilliSeconds); 403 s32 days = AlignedDays(m_MilliSeconds); 404 s32 year,month,day; 405 406 DaysToDate(&year,&month,&day, days); 407 408 parameters.year = year; 409 parameters.month = month; 410 parameters.day = day; 411 parameters.week = DaysToWeekday(days); 412 parameters.hour = msec / (1000 * 60 * 60); 413 parameters.minute = msec / (1000 * 60) % 60; 414 parameters.second = msec / 1000 % 60; 415 parameters.milliSecond = msec % 1000; 416 417 return parameters; 418 } 419 }} 420 421 /*---------------------------------------------------------------------------* 422 End of file 423 *---------------------------------------------------------------------------*/ 424