1 // Copyright 2016 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 "fpdfsdk/cpdfsdk_datetime.h"
8
9 #include "core/fxcrt/fx_ext.h"
10
11 namespace {
12
GetTimeZoneInSeconds(int8_t tzhour,uint8_t tzminute)13 int GetTimeZoneInSeconds(int8_t tzhour, uint8_t tzminute) {
14 return (int)tzhour * 3600 + (int)tzminute * (tzhour >= 0 ? 60 : -60);
15 }
16
IsLeapYear(int16_t year)17 bool IsLeapYear(int16_t year) {
18 return ((year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0)));
19 }
20
GetYearDays(int16_t year)21 uint16_t GetYearDays(int16_t year) {
22 return (IsLeapYear(year) ? 366 : 365);
23 }
24
GetMonthDays(int16_t year,uint8_t month)25 uint8_t GetMonthDays(int16_t year, uint8_t month) {
26 uint8_t mDays;
27 switch (month) {
28 case 1:
29 case 3:
30 case 5:
31 case 7:
32 case 8:
33 case 10:
34 case 12:
35 mDays = 31;
36 break;
37
38 case 4:
39 case 6:
40 case 9:
41 case 11:
42 mDays = 30;
43 break;
44
45 case 2:
46 if (IsLeapYear(year))
47 mDays = 29;
48 else
49 mDays = 28;
50 break;
51
52 default:
53 mDays = 0;
54 break;
55 }
56
57 return mDays;
58 }
59
60 } // namespace
61
CPDFSDK_DateTime()62 CPDFSDK_DateTime::CPDFSDK_DateTime() {
63 ResetDateTime();
64 }
65
CPDFSDK_DateTime(const CFX_ByteString & dtStr)66 CPDFSDK_DateTime::CPDFSDK_DateTime(const CFX_ByteString& dtStr) {
67 ResetDateTime();
68 FromPDFDateTimeString(dtStr);
69 }
70
CPDFSDK_DateTime(const CPDFSDK_DateTime & that)71 CPDFSDK_DateTime::CPDFSDK_DateTime(const CPDFSDK_DateTime& that)
72 : m_year(that.m_year),
73 m_month(that.m_month),
74 m_day(that.m_day),
75 m_hour(that.m_hour),
76 m_minute(that.m_minute),
77 m_second(that.m_second),
78 m_tzHour(that.m_tzHour),
79 m_tzMinute(that.m_tzMinute) {}
80
CPDFSDK_DateTime(const FX_SYSTEMTIME & st)81 CPDFSDK_DateTime::CPDFSDK_DateTime(const FX_SYSTEMTIME& st) {
82 tzset();
83
84 m_year = static_cast<int16_t>(st.wYear);
85 m_month = static_cast<uint8_t>(st.wMonth);
86 m_day = static_cast<uint8_t>(st.wDay);
87 m_hour = static_cast<uint8_t>(st.wHour);
88 m_minute = static_cast<uint8_t>(st.wMinute);
89 m_second = static_cast<uint8_t>(st.wSecond);
90 }
91
ResetDateTime()92 void CPDFSDK_DateTime::ResetDateTime() {
93 tzset();
94
95 time_t curTime;
96 time(&curTime);
97
98 struct tm* newtime = localtime(&curTime);
99 m_year = newtime->tm_year + 1900;
100 m_month = newtime->tm_mon + 1;
101 m_day = newtime->tm_mday;
102 m_hour = newtime->tm_hour;
103 m_minute = newtime->tm_min;
104 m_second = newtime->tm_sec;
105 }
106
operator ==(const CPDFSDK_DateTime & that) const107 bool CPDFSDK_DateTime::operator==(const CPDFSDK_DateTime& that) const {
108 return m_year == that.m_year && m_month == that.m_month &&
109 m_day == that.m_day && m_hour == that.m_hour &&
110 m_minute == that.m_minute && m_second == that.m_second &&
111 m_tzHour == that.m_tzHour && m_tzMinute == that.m_tzMinute;
112 }
113
operator !=(const CPDFSDK_DateTime & datetime) const114 bool CPDFSDK_DateTime::operator!=(const CPDFSDK_DateTime& datetime) const {
115 return !(*this == datetime);
116 }
117
ToTime_t() const118 time_t CPDFSDK_DateTime::ToTime_t() const {
119 struct tm newtime;
120
121 newtime.tm_year = m_year - 1900;
122 newtime.tm_mon = m_month - 1;
123 newtime.tm_mday = m_day;
124 newtime.tm_hour = m_hour;
125 newtime.tm_min = m_minute;
126 newtime.tm_sec = m_second;
127
128 return mktime(&newtime);
129 }
130
FromPDFDateTimeString(const CFX_ByteString & dtStr)131 CPDFSDK_DateTime& CPDFSDK_DateTime::FromPDFDateTimeString(
132 const CFX_ByteString& dtStr) {
133 int strLength = dtStr.GetLength();
134 if (strLength <= 0)
135 return *this;
136
137 int i = 0;
138 while (i < strLength && !std::isdigit(dtStr[i]))
139 ++i;
140
141 if (i >= strLength)
142 return *this;
143
144 int j = 0;
145 int k = 0;
146 FX_CHAR ch;
147 while (i < strLength && j < 4) {
148 ch = dtStr[i];
149 k = k * 10 + FXSYS_toDecimalDigit(ch);
150 j++;
151 if (!std::isdigit(ch))
152 break;
153 i++;
154 }
155 m_year = static_cast<int16_t>(k);
156 if (i >= strLength || j < 4)
157 return *this;
158
159 j = 0;
160 k = 0;
161 while (i < strLength && j < 2) {
162 ch = dtStr[i];
163 k = k * 10 + FXSYS_toDecimalDigit(ch);
164 j++;
165 if (!std::isdigit(ch))
166 break;
167 i++;
168 }
169 m_month = static_cast<uint8_t>(k);
170 if (i >= strLength || j < 2)
171 return *this;
172
173 j = 0;
174 k = 0;
175 while (i < strLength && j < 2) {
176 ch = dtStr[i];
177 k = k * 10 + FXSYS_toDecimalDigit(ch);
178 j++;
179 if (!std::isdigit(ch))
180 break;
181 i++;
182 }
183 m_day = static_cast<uint8_t>(k);
184 if (i >= strLength || j < 2)
185 return *this;
186
187 j = 0;
188 k = 0;
189 while (i < strLength && j < 2) {
190 ch = dtStr[i];
191 k = k * 10 + FXSYS_toDecimalDigit(ch);
192 j++;
193 if (!std::isdigit(ch))
194 break;
195 i++;
196 }
197 m_hour = static_cast<uint8_t>(k);
198 if (i >= strLength || j < 2)
199 return *this;
200
201 j = 0;
202 k = 0;
203 while (i < strLength && j < 2) {
204 ch = dtStr[i];
205 k = k * 10 + FXSYS_toDecimalDigit(ch);
206 j++;
207 if (!std::isdigit(ch))
208 break;
209 i++;
210 }
211 m_minute = static_cast<uint8_t>(k);
212 if (i >= strLength || j < 2)
213 return *this;
214
215 j = 0;
216 k = 0;
217 while (i < strLength && j < 2) {
218 ch = dtStr[i];
219 k = k * 10 + FXSYS_toDecimalDigit(ch);
220 j++;
221 if (!std::isdigit(ch))
222 break;
223 i++;
224 }
225 m_second = static_cast<uint8_t>(k);
226 if (i >= strLength || j < 2)
227 return *this;
228
229 ch = dtStr[i++];
230 if (ch != '-' && ch != '+')
231 return *this;
232 if (ch == '-')
233 m_tzHour = -1;
234 else
235 m_tzHour = 1;
236 j = 0;
237 k = 0;
238 while (i < strLength && j < 2) {
239 ch = dtStr[i];
240 k = k * 10 + FXSYS_toDecimalDigit(ch);
241 j++;
242 if (!std::isdigit(ch))
243 break;
244 i++;
245 }
246 m_tzHour *= static_cast<int8_t>(k);
247 if (i >= strLength || j < 2)
248 return *this;
249
250 if (dtStr[i++] != '\'')
251 return *this;
252 j = 0;
253 k = 0;
254 while (i < strLength && j < 2) {
255 ch = dtStr[i];
256 k = k * 10 + FXSYS_toDecimalDigit(ch);
257 j++;
258 if (!std::isdigit(ch))
259 break;
260 i++;
261 }
262 m_tzMinute = static_cast<uint8_t>(k);
263 return *this;
264 }
265
ToCommonDateTimeString()266 CFX_ByteString CPDFSDK_DateTime::ToCommonDateTimeString() {
267 CFX_ByteString str1;
268 str1.Format("%04d-%02u-%02u %02u:%02u:%02u ", m_year, m_month, m_day, m_hour,
269 m_minute, m_second);
270 if (m_tzHour < 0)
271 str1 += "-";
272 else
273 str1 += "+";
274 CFX_ByteString str2;
275 str2.Format("%02d:%02u", std::abs(static_cast<int>(m_tzHour)), m_tzMinute);
276 return str1 + str2;
277 }
278
ToPDFDateTimeString()279 CFX_ByteString CPDFSDK_DateTime::ToPDFDateTimeString() {
280 CFX_ByteString dtStr;
281 char tempStr[32];
282 memset(tempStr, 0, sizeof(tempStr));
283 FXSYS_snprintf(tempStr, sizeof(tempStr) - 1, "D:%04d%02u%02u%02u%02u%02u",
284 m_year, m_month, m_day, m_hour, m_minute, m_second);
285 dtStr = CFX_ByteString(tempStr);
286 if (m_tzHour < 0)
287 dtStr += CFX_ByteString("-");
288 else
289 dtStr += CFX_ByteString("+");
290 memset(tempStr, 0, sizeof(tempStr));
291 FXSYS_snprintf(tempStr, sizeof(tempStr) - 1, "%02d'%02u'",
292 std::abs(static_cast<int>(m_tzHour)), m_tzMinute);
293 dtStr += CFX_ByteString(tempStr);
294 return dtStr;
295 }
296
ToSystemTime(FX_SYSTEMTIME & st)297 void CPDFSDK_DateTime::ToSystemTime(FX_SYSTEMTIME& st) {
298 time_t t = this->ToTime_t();
299 struct tm* pTime = localtime(&t);
300
301 if (!pTime)
302 return;
303
304 st.wYear = static_cast<uint16_t>(pTime->tm_year) + 1900;
305 st.wMonth = static_cast<uint16_t>(pTime->tm_mon) + 1;
306 st.wDay = static_cast<uint16_t>(pTime->tm_mday);
307 st.wDayOfWeek = static_cast<uint16_t>(pTime->tm_wday);
308 st.wHour = static_cast<uint16_t>(pTime->tm_hour);
309 st.wMinute = static_cast<uint16_t>(pTime->tm_min);
310 st.wSecond = static_cast<uint16_t>(pTime->tm_sec);
311 st.wMilliseconds = 0;
312 }
313
ToGMT() const314 CPDFSDK_DateTime CPDFSDK_DateTime::ToGMT() const {
315 CPDFSDK_DateTime new_dt = *this;
316 new_dt.AddSeconds(-GetTimeZoneInSeconds(new_dt.m_tzHour, new_dt.m_tzMinute));
317 new_dt.m_tzHour = 0;
318 new_dt.m_tzMinute = 0;
319 return new_dt;
320 }
321
AddDays(short days)322 CPDFSDK_DateTime& CPDFSDK_DateTime::AddDays(short days) {
323 if (days == 0)
324 return *this;
325
326 int16_t y = m_year;
327 uint8_t m = m_month;
328 uint8_t d = m_day;
329
330 int ldays = days;
331 if (ldays > 0) {
332 int16_t yy = y;
333 if ((static_cast<uint16_t>(m) * 100 + d) > 300)
334 yy++;
335 int ydays = GetYearDays(yy);
336 int mdays;
337 while (ldays >= ydays) {
338 y++;
339 ldays -= ydays;
340 yy++;
341 mdays = GetMonthDays(y, m);
342 if (d > mdays) {
343 m++;
344 d -= mdays;
345 }
346 ydays = GetYearDays(yy);
347 }
348 mdays = GetMonthDays(y, m) - d + 1;
349 while (ldays >= mdays) {
350 ldays -= mdays;
351 m++;
352 d = 1;
353 mdays = GetMonthDays(y, m);
354 }
355 d += ldays;
356 } else {
357 ldays *= -1;
358 int16_t yy = y;
359 if ((static_cast<uint16_t>(m) * 100 + d) < 300)
360 yy--;
361 int ydays = GetYearDays(yy);
362 while (ldays >= ydays) {
363 y--;
364 ldays -= ydays;
365 yy--;
366 int mdays = GetMonthDays(y, m);
367 if (d > mdays) {
368 m++;
369 d -= mdays;
370 }
371 ydays = GetYearDays(yy);
372 }
373 while (ldays >= d) {
374 ldays -= d;
375 m--;
376 d = GetMonthDays(y, m);
377 }
378 d -= ldays;
379 }
380
381 m_year = y;
382 m_month = m;
383 m_day = d;
384
385 return *this;
386 }
387
AddSeconds(int seconds)388 CPDFSDK_DateTime& CPDFSDK_DateTime::AddSeconds(int seconds) {
389 if (seconds == 0)
390 return *this;
391
392 int n;
393 int days;
394
395 n = m_hour * 3600 + m_minute * 60 + m_second + seconds;
396 if (n < 0) {
397 days = (n - 86399) / 86400;
398 n -= days * 86400;
399 } else {
400 days = n / 86400;
401 n %= 86400;
402 }
403 m_hour = static_cast<uint8_t>(n / 3600);
404 m_hour %= 24;
405 n %= 3600;
406 m_minute = static_cast<uint8_t>(n / 60);
407 m_second = static_cast<uint8_t>(n % 60);
408 if (days != 0)
409 AddDays(days);
410
411 return *this;
412 }
413