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_extension.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 ByteString & dtStr)66 CPDFSDK_DateTime::CPDFSDK_DateTime(const 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 ByteString & dtStr)131 CPDFSDK_DateTime& CPDFSDK_DateTime::FromPDFDateTimeString(
132 const 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 char ch;
147 while (i < strLength && j < 4) {
148 ch = dtStr[i];
149 k = k * 10 + FXSYS_DecimalCharToInt(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_DecimalCharToInt(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_DecimalCharToInt(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_DecimalCharToInt(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_DecimalCharToInt(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_DecimalCharToInt(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_DecimalCharToInt(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_DecimalCharToInt(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 ByteString CPDFSDK_DateTime::ToCommonDateTimeString() {
267 return ByteString::Format("%04d-%02u-%02u %02u:%02u:%02u ", m_year, m_month,
268 m_day, m_hour, m_minute, m_second) +
269 (m_tzHour < 0 ? "-" : "+") +
270 ByteString::Format("%02d:%02u", std::abs(static_cast<int>(m_tzHour)),
271 m_tzMinute);
272 }
273
ToPDFDateTimeString()274 ByteString CPDFSDK_DateTime::ToPDFDateTimeString() {
275 ByteString dtStr;
276 char tempStr[32];
277 memset(tempStr, 0, sizeof(tempStr));
278 FXSYS_snprintf(tempStr, sizeof(tempStr) - 1, "D:%04d%02u%02u%02u%02u%02u",
279 m_year, m_month, m_day, m_hour, m_minute, m_second);
280 dtStr = ByteString(tempStr);
281 if (m_tzHour < 0)
282 dtStr += ByteString("-");
283 else
284 dtStr += ByteString("+");
285 memset(tempStr, 0, sizeof(tempStr));
286 FXSYS_snprintf(tempStr, sizeof(tempStr) - 1, "%02d'%02u'",
287 std::abs(static_cast<int>(m_tzHour)), m_tzMinute);
288 dtStr += ByteString(tempStr);
289 return dtStr;
290 }
291
ToSystemTime(FX_SYSTEMTIME & st)292 void CPDFSDK_DateTime::ToSystemTime(FX_SYSTEMTIME& st) {
293 time_t t = this->ToTime_t();
294 struct tm* pTime = localtime(&t);
295
296 if (!pTime)
297 return;
298
299 st.wYear = static_cast<uint16_t>(pTime->tm_year) + 1900;
300 st.wMonth = static_cast<uint16_t>(pTime->tm_mon) + 1;
301 st.wDay = static_cast<uint16_t>(pTime->tm_mday);
302 st.wDayOfWeek = static_cast<uint16_t>(pTime->tm_wday);
303 st.wHour = static_cast<uint16_t>(pTime->tm_hour);
304 st.wMinute = static_cast<uint16_t>(pTime->tm_min);
305 st.wSecond = static_cast<uint16_t>(pTime->tm_sec);
306 st.wMilliseconds = 0;
307 }
308
ToGMT() const309 CPDFSDK_DateTime CPDFSDK_DateTime::ToGMT() const {
310 CPDFSDK_DateTime new_dt = *this;
311 new_dt.AddSeconds(-GetTimeZoneInSeconds(new_dt.m_tzHour, new_dt.m_tzMinute));
312 new_dt.m_tzHour = 0;
313 new_dt.m_tzMinute = 0;
314 return new_dt;
315 }
316
AddDays(short days)317 CPDFSDK_DateTime& CPDFSDK_DateTime::AddDays(short days) {
318 if (days == 0)
319 return *this;
320
321 int16_t y = m_year;
322 uint8_t m = m_month;
323 uint8_t d = m_day;
324
325 int ldays = days;
326 if (ldays > 0) {
327 int16_t yy = y;
328 if ((static_cast<uint16_t>(m) * 100 + d) > 300)
329 yy++;
330 int ydays = GetYearDays(yy);
331 int mdays;
332 while (ldays >= ydays) {
333 y++;
334 ldays -= ydays;
335 yy++;
336 mdays = GetMonthDays(y, m);
337 if (d > mdays) {
338 m++;
339 d -= mdays;
340 }
341 ydays = GetYearDays(yy);
342 }
343 mdays = GetMonthDays(y, m) - d + 1;
344 while (ldays >= mdays) {
345 ldays -= mdays;
346 m++;
347 d = 1;
348 mdays = GetMonthDays(y, m);
349 }
350 d += ldays;
351 } else {
352 ldays *= -1;
353 int16_t yy = y;
354 if ((static_cast<uint16_t>(m) * 100 + d) < 300)
355 yy--;
356 int ydays = GetYearDays(yy);
357 while (ldays >= ydays) {
358 y--;
359 ldays -= ydays;
360 yy--;
361 int mdays = GetMonthDays(y, m);
362 if (d > mdays) {
363 m++;
364 d -= mdays;
365 }
366 ydays = GetYearDays(yy);
367 }
368 while (ldays >= d) {
369 ldays -= d;
370 m--;
371 d = GetMonthDays(y, m);
372 }
373 d -= ldays;
374 }
375
376 m_year = y;
377 m_month = m;
378 m_day = d;
379
380 return *this;
381 }
382
AddSeconds(int seconds)383 CPDFSDK_DateTime& CPDFSDK_DateTime::AddSeconds(int seconds) {
384 if (seconds == 0)
385 return *this;
386
387 int n;
388 int days;
389
390 n = m_hour * 3600 + m_minute * 60 + m_second + seconds;
391 if (n < 0) {
392 days = (n - 86399) / 86400;
393 n -= days * 86400;
394 } else {
395 days = n / 86400;
396 n %= 86400;
397 }
398 m_hour = static_cast<uint8_t>(n / 3600);
399 m_hour %= 24;
400 n %= 3600;
401 m_minute = static_cast<uint8_t>(n / 60);
402 m_second = static_cast<uint8_t>(n % 60);
403 if (days != 0)
404 AddDays(days);
405
406 return *this;
407 }
408