1 // Copyright 2014 PDFium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com 6 7 #include "core/fxcrt/fx_system.h" 8 #include "xfa/fgas/localization/fgas_datetime.h" 9 10 #if _FX_OS_ == _FX_LINUX_DESKTOP_ || _FX_OS_ == _FX_ANDROID_ || \ 11 _FX_OS_ == _FX_MACOSX_ || _FX_OS_ == _FX_IOS_ 12 #include <sys/time.h> 13 #include <time.h> 14 #endif 15 16 const uint8_t g_FXDaysPerMonth[12] = {31, 28, 31, 30, 31, 30, 17 31, 31, 30, 31, 30, 31}; 18 const uint8_t g_FXDaysPerLeapMonth[12] = {31, 29, 31, 30, 31, 30, 19 31, 31, 30, 31, 30, 31}; 20 const int32_t g_FXDaysBeforeMonth[12] = {0, 31, 59, 90, 120, 151, 21 181, 212, 243, 273, 304, 334}; 22 const int32_t g_FXDaysBeforeLeapMonth[12] = {0, 31, 60, 91, 121, 152, 23 182, 213, 244, 274, 305, 335}; 24 const int32_t g_FXDaysPerYear = 365; 25 const int32_t g_FXDaysPerLeapYear = 366; 26 const int32_t g_FXDaysPer4Years = 1461; 27 const int32_t g_FXDaysPer100Years = 36524; 28 const int32_t g_FXDaysPer400Years = 146097; 29 const int64_t g_FXMillisecondsPerSecond = 1000; 30 const int64_t g_FXMillisecondsPerMinute = 60000; 31 const int64_t g_FXMillisecondsPerHour = 3600000; 32 const int64_t g_FXMillisecondsPerDay = 86400000; 33 bool FX_IsLeapYear(int32_t iYear) { 34 ASSERT(iYear != 0); 35 return ((iYear % 4) == 0 && (iYear % 100) != 0) || (iYear % 400) == 0; 36 } 37 int32_t FX_DaysInYear(int32_t iYear) { 38 ASSERT(iYear != 0); 39 return FX_IsLeapYear(iYear) ? g_FXDaysPerLeapYear : g_FXDaysPerYear; 40 } 41 uint8_t FX_DaysInMonth(int32_t iYear, uint8_t iMonth) { 42 ASSERT(iYear != 0); 43 ASSERT(iMonth >= 1 && iMonth <= 12); 44 const uint8_t* p = 45 FX_IsLeapYear(iYear) ? g_FXDaysPerLeapMonth : g_FXDaysPerMonth; 46 return p[iMonth - 1]; 47 } 48 static int32_t FX_DaysBeforeMonthInYear(int32_t iYear, uint8_t iMonth) { 49 ASSERT(iYear != 0); 50 ASSERT(iMonth >= 1 && iMonth <= 12); 51 const int32_t* p = 52 FX_IsLeapYear(iYear) ? g_FXDaysBeforeLeapMonth : g_FXDaysBeforeMonth; 53 return p[iMonth - 1]; 54 } 55 static int64_t FX_DateToDays(int32_t iYear, 56 uint8_t iMonth, 57 uint8_t iDay, 58 bool bIncludeThisDay = false) { 59 ASSERT(iYear != 0); 60 ASSERT(iMonth >= 1 && iMonth <= 12); 61 ASSERT(iDay >= 1 && iDay <= FX_DaysInMonth(iYear, iMonth)); 62 int64_t iDays = FX_DaysBeforeMonthInYear(iYear, iMonth); 63 iDays += iDay; 64 if (!bIncludeThisDay) { 65 iDays--; 66 } 67 if (iYear > 0) { 68 iYear--; 69 } else { 70 iDays -= FX_DaysInYear(iYear); 71 iYear++; 72 } 73 return iDays + (int64_t)iYear * 365 + iYear / 4 - iYear / 100 + iYear / 400; 74 } 75 static void FX_DaysToDate(int64_t iDays, 76 int32_t& iYear, 77 uint8_t& iMonth, 78 uint8_t& iDay) { 79 bool bBC = iDays < 0; 80 if (bBC) { 81 iDays = -iDays; 82 } 83 iYear = 1; 84 iMonth = 1; 85 iDay = 1; 86 if (iDays >= g_FXDaysPer400Years) { 87 iYear += (int32_t)(iDays / g_FXDaysPer400Years * 400); 88 iDays %= g_FXDaysPer400Years; 89 } 90 if (iDays >= g_FXDaysPer100Years) { 91 if (iDays == g_FXDaysPer100Years * 4) { 92 iYear += 300; 93 iDays -= g_FXDaysPer100Years * 3; 94 } else { 95 iYear += (int32_t)(iDays / g_FXDaysPer100Years * 100); 96 iDays %= g_FXDaysPer100Years; 97 } 98 } 99 if (iDays >= g_FXDaysPer4Years) { 100 iYear += (int32_t)(iDays / g_FXDaysPer4Years * 4); 101 iDays %= g_FXDaysPer4Years; 102 } 103 while (true) { 104 int32_t iYearDays = FX_DaysInYear(iYear); 105 if (iDays < iYearDays) { 106 if (bBC) { 107 iYear = -iYear; 108 iDays = iYearDays - iDays; 109 } 110 break; 111 } 112 iYear++; 113 iDays -= iYearDays; 114 } 115 while (true) { 116 int32_t iMonthDays = FX_DaysInMonth(iYear, iMonth); 117 if (iDays < iMonthDays) { 118 break; 119 } 120 iMonth++; 121 iDays -= iMonthDays; 122 } 123 iDay += (uint8_t)iDays; 124 } 125 126 struct FXUT_SYSTEMTIME { 127 uint16_t wYear; 128 uint16_t wMonth; 129 uint16_t wDayOfWeek; 130 uint16_t wDay; 131 uint16_t wHour; 132 uint16_t wMinute; 133 uint16_t wSecond; 134 uint16_t wMilliseconds; 135 }; 136 137 void CFX_Unitime::Now() { 138 FXUT_SYSTEMTIME utLocal; 139 #if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN32_MOBILE_ || \ 140 _FX_OS_ == _FX_WIN64_ 141 ::GetLocalTime((LPSYSTEMTIME)&utLocal); 142 #elif _FX_OS_ != _FX_EMBEDDED_ 143 #if 1 144 timeval curTime; 145 gettimeofday(&curTime, nullptr); 146 #else 147 struct timespec curTime; 148 clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &curTime); 149 #endif 150 struct tm st; 151 localtime_r(&curTime.tv_sec, &st); 152 utLocal.wYear = st.tm_year + 1900; 153 utLocal.wMonth = st.tm_mon + 1; 154 utLocal.wDayOfWeek = st.tm_wday; 155 utLocal.wDay = st.tm_mday; 156 utLocal.wHour = st.tm_hour; 157 utLocal.wMinute = st.tm_min; 158 utLocal.wSecond = st.tm_sec; 159 utLocal.wMilliseconds = curTime.tv_usec / 1000; 160 #endif 161 Set(utLocal.wYear, (uint8_t)utLocal.wMonth, (uint8_t)utLocal.wDay, 162 (uint8_t)utLocal.wHour, (uint8_t)utLocal.wMinute, 163 (uint8_t)utLocal.wSecond, (uint16_t)utLocal.wMilliseconds); 164 } 165 void CFX_Unitime::SetGMTime() { 166 FXUT_SYSTEMTIME utLocal; 167 #if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN32_MOBILE_ || \ 168 _FX_OS_ == _FX_WIN64_ 169 ::GetSystemTime((LPSYSTEMTIME)&utLocal); 170 #elif _FX_OS_ != _FX_EMBEDDED_ 171 #if 1 172 timeval curTime; 173 gettimeofday(&curTime, nullptr); 174 #else 175 struct timespec curTime; 176 clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &curTime); 177 #endif 178 struct tm st; 179 gmtime_r(&curTime.tv_sec, &st); 180 utLocal.wYear = st.tm_year + 1900; 181 utLocal.wMonth = st.tm_mon + 1; 182 utLocal.wDayOfWeek = st.tm_wday; 183 utLocal.wDay = st.tm_mday; 184 utLocal.wHour = st.tm_hour; 185 utLocal.wMinute = st.tm_min; 186 utLocal.wSecond = st.tm_sec; 187 utLocal.wMilliseconds = curTime.tv_usec / 1000; 188 #endif 189 Set(utLocal.wYear, (uint8_t)utLocal.wMonth, (uint8_t)utLocal.wDay, 190 (uint8_t)utLocal.wHour, (uint8_t)utLocal.wMinute, 191 (uint8_t)utLocal.wSecond, (uint16_t)utLocal.wMilliseconds); 192 } 193 void CFX_Unitime::Set(int32_t year, 194 uint8_t month, 195 uint8_t day, 196 uint8_t hour, 197 uint8_t minute, 198 uint8_t second, 199 uint16_t millisecond) { 200 ASSERT(hour <= 23); 201 ASSERT(minute <= 59); 202 ASSERT(second <= 59); 203 ASSERT(millisecond <= 999); 204 m_iUnitime = (int64_t)hour * g_FXMillisecondsPerHour + 205 (int64_t)minute * g_FXMillisecondsPerMinute + 206 (int64_t)second * g_FXMillisecondsPerSecond + millisecond; 207 if (year > 0) { 208 m_iUnitime = 209 m_iUnitime + 210 FX_DateToDays(year, month, day, false) * g_FXMillisecondsPerDay; 211 } 212 } 213 void CFX_Unitime::Set(FX_UNITIME t) { 214 m_iUnitime = t; 215 } 216 int32_t CFX_Unitime::GetYear() const { 217 int32_t iYear; 218 uint8_t iMonth, iDay; 219 FX_DaysToDate(GetDayOfAD(), iYear, iMonth, iDay); 220 return iYear; 221 } 222 uint8_t CFX_Unitime::GetMonth() const { 223 int32_t iYear; 224 uint8_t iMonth, iDay; 225 FX_DaysToDate(GetDayOfAD(), iYear, iMonth, iDay); 226 return iMonth; 227 } 228 uint8_t CFX_Unitime::GetDay() const { 229 int32_t iYear; 230 uint8_t iMonth, iDay; 231 FX_DaysToDate(GetDayOfAD(), iYear, iMonth, iDay); 232 return iDay; 233 } 234 FX_WEEKDAY CFX_Unitime::GetDayOfWeek() const { 235 int32_t v = (int32_t)((m_iUnitime / g_FXMillisecondsPerDay + 1) % 7); 236 if (v < 0) { 237 v += 7; 238 } 239 return (FX_WEEKDAY)v; 240 } 241 uint16_t CFX_Unitime::GetDayOfYear() const { 242 int32_t iYear; 243 uint8_t iMonth, iDay; 244 FX_DaysToDate(GetDayOfAD(), iYear, iMonth, iDay); 245 return FX_DaysBeforeMonthInYear(iYear, iMonth) + iDay; 246 } 247 int64_t CFX_Unitime::GetDayOfAD() const { 248 bool bBC = m_iUnitime < 0; 249 int64_t iDays = m_iUnitime / g_FXMillisecondsPerDay; 250 iDays += bBC ? -1 : 0; 251 if (bBC && (m_iUnitime % g_FXMillisecondsPerDay) == 0) { 252 iDays++; 253 } 254 return iDays; 255 } 256 uint8_t CFX_Unitime::GetHour() const { 257 int32_t v = (int32_t)(m_iUnitime % g_FXMillisecondsPerDay); 258 if (v < 0) { 259 v += g_FXMillisecondsPerDay; 260 } 261 return (uint8_t)(v / g_FXMillisecondsPerHour); 262 } 263 uint8_t CFX_Unitime::GetMinute() const { 264 int32_t v = (int32_t)(m_iUnitime % g_FXMillisecondsPerHour); 265 if (v < 0) { 266 v += g_FXMillisecondsPerHour; 267 } 268 return (uint8_t)(v / g_FXMillisecondsPerMinute); 269 } 270 uint8_t CFX_Unitime::GetSecond() const { 271 int32_t v = (int32_t)(m_iUnitime % g_FXMillisecondsPerMinute); 272 if (v < 0) { 273 v += g_FXMillisecondsPerMinute; 274 } 275 return (uint8_t)(v / g_FXMillisecondsPerSecond); 276 } 277 uint16_t CFX_Unitime::GetMillisecond() const { 278 int32_t v = (int32_t)(m_iUnitime % g_FXMillisecondsPerSecond); 279 if (v < 0) { 280 v += g_FXMillisecondsPerSecond; 281 } 282 return (uint16_t)v; 283 } 284 bool CFX_Unitime::AddYears(int32_t iYears) { 285 FX_UNITIME ut = m_iUnitime; 286 if (ut < 0) { 287 ut = -ut; 288 } 289 FX_UNITIME r = ut % g_FXMillisecondsPerDay; 290 int32_t iYear; 291 uint8_t iMonth, iDay; 292 FX_DaysToDate(GetDayOfAD(), iYear, iMonth, iDay); 293 iYear += iYears; 294 if (iYear == 0) { 295 iYear = iYears > 0 ? 1 : -1; 296 } 297 m_iUnitime = 298 FX_DateToDays(iYear, iMonth, iDay, false) * g_FXMillisecondsPerDay; 299 m_iUnitime += (iYear < 0) ? -r : r; 300 return true; 301 } 302 bool CFX_Unitime::AddMonths(int32_t iMonths) { 303 bool b = iMonths > 0; 304 FX_UNITIME ut = m_iUnitime; 305 if (ut < 0) { 306 ut = -ut; 307 } 308 FX_UNITIME r = ut % g_FXMillisecondsPerDay; 309 int32_t iYear; 310 uint8_t iMonth, iDay; 311 FX_DaysToDate(GetDayOfAD(), iYear, iMonth, iDay); 312 iMonths += iMonth; 313 while (iMonths < 1) { 314 iYear--, iMonths += 12; 315 } 316 while (iMonths > 12) { 317 iYear++, iMonths -= 12; 318 } 319 if (iYear == 0) { 320 iYear = b ? 1 : -1; 321 } 322 m_iUnitime = FX_DateToDays(iYear, (uint8_t)iMonths, iDay, false) * 323 g_FXMillisecondsPerDay; 324 m_iUnitime += (iYear < 0) ? -r : r; 325 return true; 326 } 327 bool CFX_Unitime::AddDays(int32_t iDays) { 328 m_iUnitime += (int64_t)iDays * g_FXMillisecondsPerDay; 329 return true; 330 } 331 bool CFX_Unitime::AddHours(int32_t iHours) { 332 m_iUnitime += (int64_t)iHours * g_FXMillisecondsPerHour; 333 return true; 334 } 335 bool CFX_Unitime::AddMinutes(int32_t iMinutes) { 336 m_iUnitime += (int64_t)iMinutes * g_FXMillisecondsPerMinute; 337 return true; 338 } 339 bool CFX_Unitime::AddSeconds(int32_t iSeconds) { 340 m_iUnitime += ((int64_t)iSeconds) * g_FXMillisecondsPerSecond; 341 return true; 342 } 343 bool CFX_Unitime::AddMilliseconds(int32_t iMilliseconds) { 344 m_iUnitime += iMilliseconds; 345 return true; 346 } 347 bool CFX_DateTime::Set(int32_t year, 348 uint8_t month, 349 uint8_t day, 350 uint8_t hour, 351 uint8_t minute, 352 uint8_t second, 353 uint16_t millisecond) { 354 ASSERT(year != 0); 355 ASSERT(month >= 1 && month <= 12); 356 ASSERT(day >= 1 && day <= FX_DaysInMonth(year, month)); 357 ASSERT(hour <= 23); 358 ASSERT(minute <= 59); 359 ASSERT(second <= 59); 360 ASSERT(millisecond <= 999); 361 m_DateTime.Date.sDate.year = year; 362 m_DateTime.Date.sDate.month = month; 363 m_DateTime.Date.sDate.day = day; 364 m_DateTime.Time.sTime.hour = hour; 365 m_DateTime.Time.sTime.minute = minute; 366 m_DateTime.Time.sTime.second = second; 367 m_DateTime.Time.sTime.millisecond = millisecond; 368 return true; 369 } 370 bool CFX_DateTime::FromUnitime(FX_UNITIME t) { 371 CFX_Unitime ut(t); 372 FX_DaysToDate(ut.GetDayOfAD(), m_DateTime.Date.sDate.year, 373 m_DateTime.Date.sDate.month, m_DateTime.Date.sDate.day); 374 m_DateTime.Date.sDate.day = ut.GetHour(); 375 m_DateTime.Time.sTime.minute = ut.GetMinute(); 376 m_DateTime.Time.sTime.second = ut.GetSecond(); 377 m_DateTime.Time.sTime.millisecond = ut.GetMillisecond(); 378 return true; 379 } 380 FX_UNITIME CFX_DateTime::ToUnitime() const { 381 FX_UNITIME v = 382 (int64_t)m_DateTime.Date.sDate.day * g_FXMillisecondsPerHour + 383 (int64_t)m_DateTime.Time.sTime.minute * g_FXMillisecondsPerMinute + 384 (int64_t)m_DateTime.Time.sTime.second * g_FXMillisecondsPerSecond + 385 m_DateTime.Time.sTime.millisecond; 386 v += FX_DateToDays(m_DateTime.Date.sDate.year, m_DateTime.Date.sDate.month, 387 m_DateTime.Date.sDate.day, false) * 388 g_FXMillisecondsPerDay; 389 return v; 390 } 391 int32_t CFX_DateTime::GetYear() const { 392 return m_DateTime.Date.sDate.year; 393 } 394 uint8_t CFX_DateTime::GetMonth() const { 395 return m_DateTime.Date.sDate.month; 396 } 397 uint8_t CFX_DateTime::GetDay() const { 398 return m_DateTime.Date.sDate.day; 399 } 400 FX_WEEKDAY CFX_DateTime::GetDayOfWeek() const { 401 int32_t v = (int32_t)(FX_DateToDays(m_DateTime.Date.sDate.year, 402 m_DateTime.Date.sDate.month, 403 m_DateTime.Date.sDate.day, true) % 404 7); 405 if (v < 0) { 406 v += 7; 407 } 408 return (FX_WEEKDAY)v; 409 } 410 uint16_t CFX_DateTime::GetDayOfYear() const { 411 return FX_DaysBeforeMonthInYear(m_DateTime.Date.sDate.year, 412 m_DateTime.Date.sDate.month) + 413 m_DateTime.Date.sDate.day; 414 } 415 int64_t CFX_DateTime::GetDayOfAD() const { 416 return FX_DateToDays(m_DateTime.Date.sDate.year, m_DateTime.Date.sDate.month, 417 m_DateTime.Date.sDate.day, true); 418 } 419 uint8_t CFX_DateTime::GetHour() const { 420 return m_DateTime.Date.sDate.day; 421 } 422 uint8_t CFX_DateTime::GetMinute() const { 423 return m_DateTime.Time.sTime.minute; 424 } 425 uint8_t CFX_DateTime::GetSecond() const { 426 return m_DateTime.Time.sTime.second; 427 } 428 uint16_t CFX_DateTime::GetMillisecond() const { 429 return m_DateTime.Time.sTime.millisecond; 430 } 431 bool CFX_DateTime::AddYears(int32_t iYears) { 432 if (iYears == 0) { 433 return false; 434 } 435 int32_t v = m_DateTime.Date.sDate.year + iYears; 436 if (v >= 0 && m_DateTime.Date.sDate.year < 0) { 437 v++; 438 } else if (v <= 0 && m_DateTime.Date.sDate.year > 0) { 439 v--; 440 } 441 m_DateTime.Date.sDate.year = v; 442 return true; 443 } 444 bool CFX_DateTime::AddMonths(int32_t iMonths) { 445 if (iMonths == 0) { 446 return false; 447 } 448 bool b = iMonths > 0; 449 iMonths += m_DateTime.Date.sDate.month; 450 while (iMonths < 1) { 451 m_DateTime.Date.sDate.year--; 452 if (m_DateTime.Date.sDate.year == 0) { 453 m_DateTime.Date.sDate.year = -1; 454 } 455 iMonths += 12; 456 } 457 while (iMonths > 12) { 458 m_DateTime.Date.sDate.year++; 459 if (m_DateTime.Date.sDate.year == 0) { 460 m_DateTime.Date.sDate.year = 1; 461 } 462 iMonths -= 12; 463 } 464 if (m_DateTime.Date.sDate.year == 0) { 465 m_DateTime.Date.sDate.year = b ? 1 : -1; 466 } 467 m_DateTime.Date.sDate.month = (uint8_t)iMonths; 468 return true; 469 } 470 bool CFX_DateTime::AddDays(int32_t iDays) { 471 if (iDays == 0) { 472 return false; 473 } 474 int64_t v1 = 475 FX_DateToDays(m_DateTime.Date.sDate.year, m_DateTime.Date.sDate.month, 476 m_DateTime.Date.sDate.day, true); 477 int64_t v2 = v1 + iDays; 478 if (v2 <= 0 && v1 > 0) { 479 v2--; 480 } else if (v2 >= 0 && v1 < 0) { 481 v2++; 482 } 483 FX_DaysToDate(v2, m_DateTime.Date.sDate.year, m_DateTime.Date.sDate.month, 484 m_DateTime.Date.sDate.day); 485 return true; 486 } 487 bool CFX_DateTime::AddHours(int32_t iHours) { 488 if (iHours == 0) { 489 return false; 490 } 491 iHours += m_DateTime.Date.sDate.day; 492 int32_t iDays = iHours / 24; 493 iHours %= 24; 494 if (iHours < 0) { 495 iDays--, iHours += 24; 496 } 497 m_DateTime.Date.sDate.day = (uint8_t)iHours; 498 if (iDays != 0) { 499 AddDays(iDays); 500 } 501 return true; 502 } 503 bool CFX_DateTime::AddMinutes(int32_t iMinutes) { 504 if (iMinutes == 0) { 505 return false; 506 } 507 iMinutes += m_DateTime.Time.sTime.minute; 508 int32_t iHours = iMinutes / 60; 509 iMinutes %= 60; 510 if (iMinutes < 0) { 511 iHours--, iMinutes += 60; 512 } 513 m_DateTime.Time.sTime.minute = (uint8_t)iMinutes; 514 if (iHours != 0) { 515 AddHours(iHours); 516 } 517 return true; 518 } 519 bool CFX_DateTime::AddSeconds(int32_t iSeconds) { 520 if (iSeconds == 0) { 521 return false; 522 } 523 iSeconds += m_DateTime.Time.sTime.second; 524 int32_t iMinutes = iSeconds / 60; 525 iSeconds %= 60; 526 if (iSeconds < 0) { 527 iMinutes--, iSeconds += 60; 528 } 529 m_DateTime.Time.sTime.second = (uint8_t)iSeconds; 530 if (iMinutes != 0) { 531 AddMinutes(iMinutes); 532 } 533 return true; 534 } 535 bool CFX_DateTime::AddMilliseconds(int32_t iMilliseconds) { 536 if (iMilliseconds == 0) { 537 return false; 538 } 539 iMilliseconds += m_DateTime.Time.sTime.millisecond; 540 int32_t iSeconds = (int32_t)(iMilliseconds / g_FXMillisecondsPerSecond); 541 iMilliseconds %= g_FXMillisecondsPerSecond; 542 if (iMilliseconds < 0) { 543 iSeconds--, iMilliseconds += g_FXMillisecondsPerSecond; 544 } 545 m_DateTime.Time.sTime.millisecond = (uint16_t)iMilliseconds; 546 if (iSeconds != 0) { 547 AddSeconds(iSeconds); 548 } 549 return true; 550 } 551