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