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