blob: ce22cae12fa1dc576254cc7ebfc410ff274b352d [file] [log] [blame]
jaepark27362762016-08-11 13:10:39 -07001// 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
dsinclair114e46a2016-09-29 17:18:21 -07007#include "fpdfsdk/cpdfsdk_datetime.h"
jaepark27362762016-08-11 13:10:39 -07008
Dan Sinclaircfb19442017-04-20 13:13:04 -04009#include "core/fxcrt/fx_extension.h"
jaepark27362762016-08-11 13:10:39 -070010
11namespace {
12
13int GetTimeZoneInSeconds(int8_t tzhour, uint8_t tzminute) {
14 return (int)tzhour * 3600 + (int)tzminute * (tzhour >= 0 ? 60 : -60);
15}
16
17bool IsLeapYear(int16_t year) {
18 return ((year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0)));
19}
20
21uint16_t GetYearDays(int16_t year) {
22 return (IsLeapYear(year) ? 366 : 365);
23}
24
25uint8_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
62CPDFSDK_DateTime::CPDFSDK_DateTime() {
63 ResetDateTime();
64}
65
Ryan Harrison275e2602017-09-18 14:23:18 -040066CPDFSDK_DateTime::CPDFSDK_DateTime(const ByteString& dtStr) {
jaepark27362762016-08-11 13:10:39 -070067 ResetDateTime();
jaepark27362762016-08-11 13:10:39 -070068 FromPDFDateTimeString(dtStr);
69}
70
tsepezb31ca712016-09-13 18:10:13 -070071CPDFSDK_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) {}
jaepark27362762016-08-11 13:10:39 -070080
81CPDFSDK_DateTime::CPDFSDK_DateTime(const FX_SYSTEMTIME& st) {
82 tzset();
83
tsepezb31ca712016-09-13 18:10:13 -070084 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);
jaepark27362762016-08-11 13:10:39 -070090}
91
92void CPDFSDK_DateTime::ResetDateTime() {
93 tzset();
94
95 time_t curTime;
96 time(&curTime);
jaepark27362762016-08-11 13:10:39 -070097
tsepezb31ca712016-09-13 18:10:13 -070098 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;
jaepark27362762016-08-11 13:10:39 -0700105}
106
tsepezb31ca712016-09-13 18:10:13 -0700107bool 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;
jaepark27362762016-08-11 13:10:39 -0700112}
113
114bool CPDFSDK_DateTime::operator!=(const CPDFSDK_DateTime& datetime) const {
115 return !(*this == datetime);
116}
117
118time_t CPDFSDK_DateTime::ToTime_t() const {
119 struct tm newtime;
120
tsepezb31ca712016-09-13 18:10:13 -0700121 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;
jaepark27362762016-08-11 13:10:39 -0700127
128 return mktime(&newtime);
129}
130
131CPDFSDK_DateTime& CPDFSDK_DateTime::FromPDFDateTimeString(
Ryan Harrison275e2602017-09-18 14:23:18 -0400132 const ByteString& dtStr) {
jaepark27362762016-08-11 13:10:39 -0700133 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;
Dan Sinclair812e96c2017-03-13 16:43:37 -0400146 char ch;
jaepark27362762016-08-11 13:10:39 -0700147 while (i < strLength && j < 4) {
148 ch = dtStr[i];
Lei Zhange8c1d412017-05-04 12:13:55 -0700149 k = k * 10 + FXSYS_DecimalCharToInt(ch);
jaepark27362762016-08-11 13:10:39 -0700150 j++;
151 if (!std::isdigit(ch))
152 break;
153 i++;
154 }
tsepezb31ca712016-09-13 18:10:13 -0700155 m_year = static_cast<int16_t>(k);
jaepark27362762016-08-11 13:10:39 -0700156 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];
Lei Zhange8c1d412017-05-04 12:13:55 -0700163 k = k * 10 + FXSYS_DecimalCharToInt(ch);
jaepark27362762016-08-11 13:10:39 -0700164 j++;
165 if (!std::isdigit(ch))
166 break;
167 i++;
168 }
tsepezb31ca712016-09-13 18:10:13 -0700169 m_month = static_cast<uint8_t>(k);
jaepark27362762016-08-11 13:10:39 -0700170 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];
Lei Zhange8c1d412017-05-04 12:13:55 -0700177 k = k * 10 + FXSYS_DecimalCharToInt(ch);
jaepark27362762016-08-11 13:10:39 -0700178 j++;
179 if (!std::isdigit(ch))
180 break;
181 i++;
182 }
tsepezb31ca712016-09-13 18:10:13 -0700183 m_day = static_cast<uint8_t>(k);
jaepark27362762016-08-11 13:10:39 -0700184 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];
Lei Zhange8c1d412017-05-04 12:13:55 -0700191 k = k * 10 + FXSYS_DecimalCharToInt(ch);
jaepark27362762016-08-11 13:10:39 -0700192 j++;
193 if (!std::isdigit(ch))
194 break;
195 i++;
196 }
tsepezb31ca712016-09-13 18:10:13 -0700197 m_hour = static_cast<uint8_t>(k);
jaepark27362762016-08-11 13:10:39 -0700198 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];
Lei Zhange8c1d412017-05-04 12:13:55 -0700205 k = k * 10 + FXSYS_DecimalCharToInt(ch);
jaepark27362762016-08-11 13:10:39 -0700206 j++;
207 if (!std::isdigit(ch))
208 break;
209 i++;
210 }
tsepezb31ca712016-09-13 18:10:13 -0700211 m_minute = static_cast<uint8_t>(k);
jaepark27362762016-08-11 13:10:39 -0700212 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];
Lei Zhange8c1d412017-05-04 12:13:55 -0700219 k = k * 10 + FXSYS_DecimalCharToInt(ch);
jaepark27362762016-08-11 13:10:39 -0700220 j++;
221 if (!std::isdigit(ch))
222 break;
223 i++;
224 }
tsepezb31ca712016-09-13 18:10:13 -0700225 m_second = static_cast<uint8_t>(k);
jaepark27362762016-08-11 13:10:39 -0700226 if (i >= strLength || j < 2)
227 return *this;
228
229 ch = dtStr[i++];
230 if (ch != '-' && ch != '+')
231 return *this;
232 if (ch == '-')
tsepezb31ca712016-09-13 18:10:13 -0700233 m_tzHour = -1;
jaepark27362762016-08-11 13:10:39 -0700234 else
tsepezb31ca712016-09-13 18:10:13 -0700235 m_tzHour = 1;
jaepark27362762016-08-11 13:10:39 -0700236 j = 0;
237 k = 0;
238 while (i < strLength && j < 2) {
239 ch = dtStr[i];
Lei Zhange8c1d412017-05-04 12:13:55 -0700240 k = k * 10 + FXSYS_DecimalCharToInt(ch);
jaepark27362762016-08-11 13:10:39 -0700241 j++;
242 if (!std::isdigit(ch))
243 break;
244 i++;
245 }
tsepezb31ca712016-09-13 18:10:13 -0700246 m_tzHour *= static_cast<int8_t>(k);
jaepark27362762016-08-11 13:10:39 -0700247 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];
Lei Zhange8c1d412017-05-04 12:13:55 -0700256 k = k * 10 + FXSYS_DecimalCharToInt(ch);
jaepark27362762016-08-11 13:10:39 -0700257 j++;
258 if (!std::isdigit(ch))
259 break;
260 i++;
261 }
tsepezb31ca712016-09-13 18:10:13 -0700262 m_tzMinute = static_cast<uint8_t>(k);
jaepark27362762016-08-11 13:10:39 -0700263 return *this;
264}
265
Ryan Harrison275e2602017-09-18 14:23:18 -0400266ByteString CPDFSDK_DateTime::ToCommonDateTimeString() {
267 ByteString str1;
tsepezb31ca712016-09-13 18:10:13 -0700268 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)
jaepark27362762016-08-11 13:10:39 -0700271 str1 += "-";
272 else
273 str1 += "+";
Ryan Harrison275e2602017-09-18 14:23:18 -0400274 ByteString str2;
tsepezb31ca712016-09-13 18:10:13 -0700275 str2.Format("%02d:%02u", std::abs(static_cast<int>(m_tzHour)), m_tzMinute);
jaepark27362762016-08-11 13:10:39 -0700276 return str1 + str2;
277}
278
Ryan Harrison275e2602017-09-18 14:23:18 -0400279ByteString CPDFSDK_DateTime::ToPDFDateTimeString() {
280 ByteString dtStr;
jaepark27362762016-08-11 13:10:39 -0700281 char tempStr[32];
282 memset(tempStr, 0, sizeof(tempStr));
283 FXSYS_snprintf(tempStr, sizeof(tempStr) - 1, "D:%04d%02u%02u%02u%02u%02u",
tsepezb31ca712016-09-13 18:10:13 -0700284 m_year, m_month, m_day, m_hour, m_minute, m_second);
Ryan Harrison275e2602017-09-18 14:23:18 -0400285 dtStr = ByteString(tempStr);
tsepezb31ca712016-09-13 18:10:13 -0700286 if (m_tzHour < 0)
Ryan Harrison275e2602017-09-18 14:23:18 -0400287 dtStr += ByteString("-");
jaepark27362762016-08-11 13:10:39 -0700288 else
Ryan Harrison275e2602017-09-18 14:23:18 -0400289 dtStr += ByteString("+");
jaepark27362762016-08-11 13:10:39 -0700290 memset(tempStr, 0, sizeof(tempStr));
291 FXSYS_snprintf(tempStr, sizeof(tempStr) - 1, "%02d'%02u'",
tsepezb31ca712016-09-13 18:10:13 -0700292 std::abs(static_cast<int>(m_tzHour)), m_tzMinute);
Ryan Harrison275e2602017-09-18 14:23:18 -0400293 dtStr += ByteString(tempStr);
jaepark27362762016-08-11 13:10:39 -0700294 return dtStr;
295}
296
297void 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
314CPDFSDK_DateTime CPDFSDK_DateTime::ToGMT() const {
315 CPDFSDK_DateTime new_dt = *this;
tsepezb31ca712016-09-13 18:10:13 -0700316 new_dt.AddSeconds(-GetTimeZoneInSeconds(new_dt.m_tzHour, new_dt.m_tzMinute));
317 new_dt.m_tzHour = 0;
318 new_dt.m_tzMinute = 0;
jaepark27362762016-08-11 13:10:39 -0700319 return new_dt;
320}
321
322CPDFSDK_DateTime& CPDFSDK_DateTime::AddDays(short days) {
323 if (days == 0)
324 return *this;
325
tsepezb31ca712016-09-13 18:10:13 -0700326 int16_t y = m_year;
327 uint8_t m = m_month;
328 uint8_t d = m_day;
jaepark27362762016-08-11 13:10:39 -0700329
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
tsepezb31ca712016-09-13 18:10:13 -0700381 m_year = y;
382 m_month = m;
383 m_day = d;
jaepark27362762016-08-11 13:10:39 -0700384
385 return *this;
386}
387
388CPDFSDK_DateTime& CPDFSDK_DateTime::AddSeconds(int seconds) {
389 if (seconds == 0)
390 return *this;
391
392 int n;
393 int days;
394
tsepezb31ca712016-09-13 18:10:13 -0700395 n = m_hour * 3600 + m_minute * 60 + m_second + seconds;
jaepark27362762016-08-11 13:10:39 -0700396 if (n < 0) {
397 days = (n - 86399) / 86400;
398 n -= days * 86400;
399 } else {
400 days = n / 86400;
401 n %= 86400;
402 }
tsepezb31ca712016-09-13 18:10:13 -0700403 m_hour = static_cast<uint8_t>(n / 3600);
404 m_hour %= 24;
jaepark27362762016-08-11 13:10:39 -0700405 n %= 3600;
tsepezb31ca712016-09-13 18:10:13 -0700406 m_minute = static_cast<uint8_t>(n / 60);
407 m_second = static_cast<uint8_t>(n % 60);
jaepark27362762016-08-11 13:10:39 -0700408 if (days != 0)
409 AddDays(days);
410
411 return *this;
412}