Branch data Line data Source code
1 : : /* -*- mode: C -*-
2 : : *
3 : : * File: pdf-time.c
4 : : * Date: Mon Apr 28 23:23:04 2008
5 : : *
6 : : * GNU PDF Library - Time Module source
7 : : *
8 : : */
9 : :
10 : : /* Copyright (C) 2008-2011 Free Software Foundation, Inc. */
11 : :
12 : : /* This program is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU General Public License as published by
14 : : * the Free Software Foundation, either version 3 of the License, or
15 : : * (at your option) any later version.
16 : : *
17 : : * This program is distributed in the hope that it will be useful,
18 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 : : * GNU General Public License for more details.
21 : : *
22 : : * You should have received a copy of the GNU General Public License
23 : : * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 : : */
25 : :
26 : : #include <config.h>
27 : :
28 : : #include <time.h>
29 : :
30 : : #include <pdf-alloc.h>
31 : : #include <pdf-time.h>
32 : : #include <pdf-time-context.h>
33 : : #include <pdf-time-string.h>
34 : :
35 : : /* Useful constants */
36 : :
37 : : #define PDF_SECS_PER_DAY 86400
38 : : #define PDF_SECS_PER_HOUR 3600
39 : : #define PDF_SECS_PER_MIN 60
40 : : #define PDF_MINS_PER_HOUR 60
41 : : #define PDF_HOURS_PER_DAY 24
42 : : #define PDF_MINS_PER_DAY 1440
43 : : #define PDF_DAYS_IN_YEAR 365
44 : : #define PDF_DAYS_IN_LEAP_YEAR 366
45 : :
46 : : enum pdf_time_cal_type_e {
47 : : PDF_TIME_CAL_LOCAL,
48 : : PDF_TIME_CAL_UTC
49 : : };
50 : :
51 : : enum pdf_time_month_e {
52 : : PDF_TIME_JANUARY = 1,
53 : : PDF_TIME_FEBRUARY = 2,
54 : : PDF_TIME_MARCH = 3,
55 : : PDF_TIME_APRIL = 4,
56 : : PDF_TIME_MAY = 5,
57 : : PDF_TIME_JUNE = 6,
58 : : PDF_TIME_JULY = 7,
59 : : PDF_TIME_AUGUST = 8,
60 : : PDF_TIME_SEPTEMBER = 9,
61 : : PDF_TIME_OCTOBER = 10,
62 : : PDF_TIME_NOVEMBER = 11,
63 : : PDF_TIME_DECEMBER = 12,
64 : : PDF_TIME_NMONTHS
65 : : };
66 : :
67 : : /* Returns PDF_TRUE if the Olimpic Games [were/will be] celebrated in the given
68 : : * year. A leap year is divisable by 4, but not by 100, except if divisable by
69 : : * 400 */
70 : : #define IS_LEAP_YEAR(year) \
71 : : (((year % 4 == 0) && \
72 : : ((year % 100 != 0) || \
73 : : (year % 400 == 0))) ? \
74 : : PDF_TRUE : PDF_FALSE)
75 : :
76 : : /* Returns number of days in the given month (year-dependent due to leap
77 : : * years) */
78 : : static pdf_u32_t
79 : 1749363 : pdf_time_get_days_in_month (const pdf_u32_t year,
80 : : const enum pdf_time_month_e month)
81 : : {
82 [ + + + - ]: 1749363 : switch (month)
83 : : {
84 : : case PDF_TIME_JANUARY:
85 : : case PDF_TIME_MARCH:
86 : : case PDF_TIME_MAY:
87 : : case PDF_TIME_JULY:
88 : : case PDF_TIME_AUGUST:
89 : : case PDF_TIME_OCTOBER:
90 : : case PDF_TIME_DECEMBER:
91 : 1012536 : return 31;
92 : : case PDF_TIME_APRIL:
93 : : case PDF_TIME_JUNE:
94 : : case PDF_TIME_SEPTEMBER:
95 : : case PDF_TIME_NOVEMBER:
96 : 481738 : return 30;
97 : : case PDF_TIME_FEBRUARY:
98 [ + + ][ + + ]: 255089 : return (IS_LEAP_YEAR (year) ? 29 : 28);
[ + - ]
99 : : default:
100 : 1749363 : return 0;
101 : : }
102 : : }
103 : :
104 : : /* Returns number of days before the given month */
105 : : static pdf_u32_t
106 : : pdf_time_get_days_before_month (const pdf_u32_t year,
107 : : const enum pdf_time_month_e month)
108 : : {
109 : 310134 : enum pdf_time_month_e walk = PDF_TIME_JANUARY;
110 : 310134 : pdf_u32_t sum = 0;
111 : :
112 [ + + ][ + + ]: 1948338 : while (walk != month) {
[ + + ]
113 : 1638204 : sum += pdf_time_get_days_in_month (year, walk++);
114 : : }
115 : :
116 : 310134 : return sum;
117 : : }
118 : :
119 : : /* Get Break-Down calendar from pdf_time_t */
120 : : static void
121 : 35505 : pdf_time_get_cal (const pdf_time_t *time_var,
122 : : const enum pdf_time_cal_type_e cal_type,
123 : : struct pdf_time_cal_s *cal_time)
124 : : {
125 : : /* Based on glibc's __offtime function */
126 : :
127 : : pdf_i32_t days;
128 : : pdf_i32_t remaining;
129 : : pdf_i32_t years;
130 : : pdf_i32_t months;
131 : : pdf_time_t new_time_var;
132 : :
133 : : /* Duplicate time var */
134 : 35505 : pdf_time_init_dup (&new_time_var, time_var);
135 : :
136 : : /* pdf_time_t always stores the date & time in UTC timescale, so we only need
137 : : * to modify the time_var IF gmt_offset is not zero, in order to move the
138 : : * date & time from UTC to local time specified by the offset */
139 [ + + + + ]: 35505 : if ((cal_type == PDF_TIME_CAL_LOCAL) &&
140 : 17313 : (time_var->gmt_offset != 0))
141 : : {
142 : 16876 : pdf_time_add_span (&new_time_var, time_var->gmt_offset);
143 : : }
144 : :
145 : : /* Get date as days */
146 : 35505 : days = (pdf_i32_t) (new_time_var.seconds / PDF_SECS_PER_DAY);
147 : : /* Get time in seconds */
148 : 35505 : remaining = (pdf_i32_t) (new_time_var.seconds % PDF_SECS_PER_DAY);
149 : : /* Get hours */
150 : 35505 : cal_time->hour = remaining / PDF_SECS_PER_HOUR;
151 : : /* Get remaining */
152 : 35505 : remaining = remaining % PDF_SECS_PER_HOUR;
153 : : /* Get minutes */
154 : 35505 : cal_time->minute = remaining / PDF_MINS_PER_HOUR;
155 : : /* Get seconds */
156 : 35505 : cal_time->second = remaining % PDF_MINS_PER_HOUR;
157 : :
158 : : /* Seems that Unix origin time was thursday */
159 : 35505 : cal_time->dow = ((days + 4) % 7);
160 : :
161 : 35505 : years = 1970;
162 : :
163 [ + + ][ + + ]: 120420 : while ((days < 0) ||
164 [ + + ][ + + ]: 59213 : (days >= (IS_LEAP_YEAR (years) ?
[ + - ]
165 : : (PDF_DAYS_IN_YEAR + 1) :
166 : : (PDF_DAYS_IN_YEAR))))
167 : : {
168 : : pdf_i32_t yg;
169 : :
170 : 25702 : yg = years;
171 : : /* Compute number of years (assuming all years of 365 days) between the
172 : : * origin and our date */
173 : 25702 : yg += (days / PDF_DAYS_IN_YEAR);
174 : : /* Get number of remaining days after having added the fixed-size years
175 : : If the number of remaining days is less than zero, go down 1 year */
176 : 25702 : yg -= ((days % PDF_DAYS_IN_YEAR) < 0);
177 : :
178 : : #define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
179 : : /* Remove number of days due to the leap years */
180 : 154212 : days -= (((yg - years)*PDF_DAYS_IN_YEAR) +
181 : 77106 : (LEAPS_THRU_END_OF (yg - 1)) -
182 : 77106 : (LEAPS_THRU_END_OF (years - 1)));
183 : 25702 : years = yg;
184 : : }
185 : :
186 : : /* Set year */
187 : 35505 : cal_time->year = years; /* - 1900; */
188 : :
189 [ + + ]: 256758 : for (months = 11;
190 : 221253 : days < pdf_time_get_days_before_month (cal_time->year,months);
191 : 185748 : --months)
192 : 185748 : continue;
193 : :
194 : 71010 : days -= pdf_time_get_days_before_month (cal_time->year,months);
195 : :
196 : : /* Set month and day of month */
197 : 35505 : cal_time->month = months;
198 [ + + ]: 35505 : if (pdf_time_get_days_in_month (cal_time->year,
199 : 71010 : cal_time->month) < (days + 1))
200 : : {
201 : 15841 : cal_time->day = days + 1 - pdf_time_get_days_in_month (cal_time->year,
202 : 15841 : cal_time->month);
203 : 15841 : cal_time->month += 1;
204 [ - + ]: 15841 : if (cal_time->month == 13)
205 : : {
206 : 0 : cal_time->month = 1;
207 : 0 : cal_time->year += 1;
208 : : }
209 : : }
210 : : else
211 : : {
212 : 19664 : cal_time->day = days + 1;
213 : : }
214 : :
215 : : /* Finally, set gmt offset */
216 : 35505 : cal_time->gmt_offset = new_time_var.gmt_offset;
217 : :
218 : 35505 : pdf_time_deinit (&new_time_var);
219 : 35505 : }
220 : :
221 : : /* Function to normalize a given date after having added YEARS */
222 : : static void
223 : : pdf_time_calendar_add_years (struct pdf_time_cal_s *p_calendar,
224 : : const pdf_i32_t delta_years)
225 : : {
226 : : pdf_i32_t years;
227 : :
228 [ + + ]: 5792 : if (delta_years == 0)
229 : : return;
230 : :
231 : : /* ADD years */
232 : 3632 : years = p_calendar->year + delta_years;
233 : :
234 : : /* The only thing to normalize is in case we reach Feb.29 in a non-leap
235 : : * year */
236 [ + + ][ + + ]: 3632 : if ((!IS_LEAP_YEAR (years)) &&
[ - + ][ - + ]
237 : : (p_calendar->month == PDF_TIME_FEBRUARY) &&
238 : : (p_calendar->day == 29))
239 : : {
240 : 0 : p_calendar->day = 28;
241 : : }
242 : :
243 [ - + ]: 3632 : PDF_ASSERT (years >= 0);
244 : 3632 : p_calendar->year = years;
245 : : }
246 : :
247 : : /* Function to normalize a given date after having added MONTHS */
248 : : static void
249 : 6032 : pdf_time_calendar_add_months (struct pdf_time_cal_s *p_calendar,
250 : : const pdf_i32_t delta_months)
251 : : {
252 [ + + ]: 6032 : if (delta_months == 0)
253 : : return;
254 : :
255 [ + + ]: 4256 : if (delta_months > 0)
256 : : {
257 : 3440 : p_calendar->month += delta_months;
258 [ - + ]: 3440 : while (p_calendar->month > 12)
259 : : {
260 : 0 : p_calendar->month -= 12;
261 : 0 : p_calendar->year++;
262 : : }
263 : : }
264 : : else
265 : : {
266 : : pdf_i32_t months;
267 : :
268 : 816 : months = p_calendar->month + delta_months;
269 [ + + ]: 1056 : while (months < 1)
270 : : {
271 : 240 : months += 12;
272 : 240 : p_calendar->year--;
273 : : }
274 : :
275 [ - + ]: 816 : PDF_ASSERT (months >= 1);
276 [ - + ]: 816 : PDF_ASSERT (months <= 12);
277 : 816 : p_calendar->month = months;
278 : : }
279 : :
280 : : /* After having added months, we could need to normalize the days */
281 [ + + ]: 4256 : if (pdf_time_get_days_in_month (p_calendar->year,
282 : 4256 : p_calendar->month) < p_calendar->day)
283 : : {
284 : 121 : p_calendar->day = pdf_time_get_days_in_month (p_calendar->year,
285 : 121 : p_calendar->month);
286 : : }
287 : :
288 [ - + ]: 4256 : PDF_ASSERT (p_calendar->month >= 1);
289 [ - + ]: 6032 : PDF_ASSERT (p_calendar->month <= 12);
290 : : }
291 : :
292 : : /* Function to normalize a given date after having added DAYS */
293 : : static void
294 : 7950 : pdf_time_calendar_add_days (struct pdf_time_cal_s *p_calendar,
295 : : const pdf_i32_t delta_days)
296 : : {
297 : 7950 : pdf_i32_t delta = delta_days;
298 : :
299 [ + + ]: 7950 : if (delta_days == 0)
300 : : return;
301 : :
302 : : /* ADD days */
303 [ + + ]: 2060 : if (delta_days > 0)
304 : : {
305 : : pdf_i32_t days_in_month;
306 : :
307 : : /* Initialize days in month */
308 : 1820 : days_in_month = pdf_time_get_days_in_month (p_calendar->year,
309 : : (enum pdf_time_month_e)p_calendar->month);
310 [ - + ]: 1820 : while (delta > (days_in_month - p_calendar->day))
311 : : {
312 : : /* Go to start of next month */
313 : 0 : p_calendar->day = 1;
314 : 0 : pdf_time_calendar_add_months (p_calendar, 1);
315 : :
316 : : /* Update remaining delta and new days_in_month */
317 : 0 : delta -= (days_in_month - p_calendar->day + 1);
318 : 0 : days_in_month = pdf_time_get_days_in_month (p_calendar->year,
319 : : (enum pdf_time_month_e)p_calendar->month);
320 : : }
321 : : /* Add final delta, which doesn't require month change */
322 : 1820 : p_calendar->day += delta;
323 : : }
324 : : /* SUBSTRACT days */
325 : : else
326 : : {
327 : : pdf_i32_t days_in_month;
328 : :
329 : : /* Initialize days in month */
330 : 240 : days_in_month = p_calendar->day - 1;
331 : :
332 [ + + ]: 480 : while (days_in_month <= (-delta))
333 : : {
334 : : /* Go to the begin of previous month */
335 : 240 : p_calendar->day = 1;
336 : 240 : pdf_time_calendar_add_months (p_calendar, -1);
337 : :
338 : : /* Update remaining delta and new days_in_month */
339 : 240 : delta += days_in_month;
340 : 240 : days_in_month = pdf_time_get_days_in_month (p_calendar->year,
341 : : (enum pdf_time_month_e)p_calendar->month);
342 : : }
343 : : /* Add final delta, which doesn't require month change */
344 : 240 : delta += days_in_month;
345 : 240 : p_calendar->day += delta;
346 : : }
347 : :
348 [ - + ]: 2060 : PDF_ASSERT (p_calendar->month >= 1);
349 [ - + ]: 7950 : PDF_ASSERT (p_calendar->month <= 12);
350 : : }
351 : :
352 : : /* Function to normalize a given date after having added HOURS */
353 : : static void
354 : 8400 : pdf_time_calendar_add_hours (struct pdf_time_cal_s *p_calendar,
355 : : const pdf_i32_t delta_hours)
356 : : {
357 : : pdf_i32_t hours;
358 : : pdf_i32_t days;
359 : : pdf_i32_t remaining_hours;
360 : :
361 [ + + ]: 8400 : if (delta_hours == 0)
362 : : return;
363 : :
364 : : /* No real problem with hours, as 1 day is always 24h */
365 : 2158 : days = delta_hours / PDF_HOURS_PER_DAY;
366 : 2158 : remaining_hours = delta_hours % PDF_HOURS_PER_DAY;
367 : :
368 : : /* Add remaining hours */
369 : 2158 : hours = p_calendar->hour + remaining_hours;
370 : :
371 : : /* If we went back to the previous day, correct time and add 1 day more
372 : : * to remove */
373 [ - + ]: 2158 : if (hours < 0)
374 : : {
375 : 0 : hours += PDF_HOURS_PER_DAY;
376 : 0 : days--;
377 : : }
378 : : /* If we went forward to the next day, correct time and add 1 day more
379 : : * to add */
380 [ - + ]: 2158 : else if (hours >= PDF_HOURS_PER_DAY)
381 : : {
382 : 0 : hours -= PDF_HOURS_PER_DAY;
383 : 0 : days++;
384 : : }
385 : :
386 [ - + ]: 2158 : PDF_ASSERT (hours >= 0);
387 [ - + ]: 2158 : PDF_ASSERT (hours < 24);
388 : 2158 : p_calendar->hour = hours;
389 : :
390 : : /* Add/Remove days... */
391 : 8400 : pdf_time_calendar_add_days (p_calendar, days);
392 : : }
393 : :
394 : : /* Function to normalize a given date after having added MINUTES */
395 : : static void
396 : 8760 : pdf_time_calendar_add_minutes (struct pdf_time_cal_s *p_calendar,
397 : : const pdf_i32_t delta_minutes)
398 : : {
399 : : pdf_i32_t minutes;
400 : : pdf_i32_t hours;
401 : : pdf_i32_t remaining_minutes;
402 : :
403 [ + + ]: 8760 : if (delta_minutes == 0)
404 : : return;
405 : :
406 : : /* No real problem with minutes, as 1 hour is always 60minutes */
407 : 2608 : hours = delta_minutes / PDF_MINS_PER_HOUR;
408 : 2608 : remaining_minutes = delta_minutes % PDF_MINS_PER_HOUR;
409 : :
410 : : /* Add remaining minutes */
411 : 2608 : minutes = p_calendar->minute + remaining_minutes;
412 : :
413 : : /* If we went back to the previous hour, correct time and add 1 hour more
414 : : * to remove */
415 [ - + ]: 2608 : if (minutes < 0)
416 : : {
417 : 0 : minutes += PDF_MINS_PER_HOUR;
418 : 0 : hours--;
419 : : }
420 : : /* If we went forward to the next day, correct time and add 1 hour more
421 : : * to add */
422 [ - + ]: 2608 : else if (minutes >= PDF_MINS_PER_HOUR)
423 : : {
424 : 0 : minutes -= PDF_MINS_PER_HOUR;
425 : 0 : hours++;
426 : : }
427 : :
428 [ - + ]: 2608 : PDF_ASSERT (minutes >= 0);
429 [ - + ]: 2608 : PDF_ASSERT (minutes < 60);
430 : 2608 : p_calendar->minute = minutes;
431 : :
432 : : /* Add/Remove hours... */
433 : 8760 : pdf_time_calendar_add_hours (p_calendar, hours);
434 : : }
435 : :
436 : : /* Function to normalize a given date after having added SECONDS */
437 : : static void
438 : : pdf_time_calendar_add_seconds (struct pdf_time_cal_s *p_calendar,
439 : : const pdf_i32_t delta_seconds)
440 : : {
441 : : pdf_i32_t seconds;
442 : : pdf_i32_t minutes;
443 : : pdf_i32_t remaining_seconds;
444 : :
445 [ + + ]: 5792 : if (delta_seconds == 0)
446 : : return;
447 : :
448 : : /* No real problem with minutes, as 1 hour is always 60minutes */
449 : 2968 : minutes = delta_seconds / PDF_SECS_PER_MIN;
450 : 2968 : remaining_seconds = delta_seconds % PDF_SECS_PER_MIN;
451 : :
452 : : /* Add remaining seconds */
453 : 2968 : seconds = p_calendar->second + remaining_seconds;
454 : :
455 : : /* If we went back to the previous minute, correct time and add 1 minute more
456 : : * to remove */
457 [ - + ]: 2968 : if (seconds < 0)
458 : : {
459 : 0 : seconds += PDF_SECS_PER_MIN;
460 : 0 : minutes--;
461 : : }
462 : : /* If we went forward to the next minute, correct time and add 1 minute more
463 : : * to add */
464 [ - + ]: 2968 : else if (seconds >= PDF_SECS_PER_MIN)
465 : : {
466 : 0 : seconds -= PDF_SECS_PER_MIN;
467 : 0 : minutes++;
468 : : }
469 : :
470 [ - + ]: 2968 : PDF_ASSERT (seconds >= 0);
471 [ - + ]: 2968 : PDF_ASSERT (seconds < 60);
472 : 2968 : p_calendar->second = seconds;
473 : :
474 : : /* Add/Remove minutes... */
475 : 2968 : pdf_time_calendar_add_minutes (p_calendar, minutes);
476 : : }
477 : :
478 : : /* --------------------- Time Module Initialization ------------------------- */
479 : :
480 : : /* Initialize Time module. */
481 : : pdf_bool_t
482 : 745 : pdf_time_module_init (pdf_error_t **error)
483 : : {
484 : : /* Start Time context */
485 : 745 : return pdf_time_context_init (error);
486 : : }
487 : :
488 : : /* --------------------- Time Creation and Destruction ---------------------- */
489 : :
490 : : static pdf_time_t *
491 : 6 : pdf_time_allocate (pdf_error_t **error)
492 : : {
493 : : pdf_time_t *time_var;
494 : :
495 : : /* Allocate object & Initialize all contents */
496 : 6 : time_var = (pdf_time_t *) pdf_alloc (sizeof(struct pdf_time_s));
497 [ - + ]: 6 : if (!time_var)
498 : : {
499 : 0 : pdf_set_error (error,
500 : : PDF_EDOMAIN_BASE_TIME,
501 : : PDF_ENOMEM,
502 : : "cannot create new time object: "
503 : : "couldn't allocate %lu bytes",
504 : : (unsigned long)sizeof (struct pdf_time_s));
505 : : }
506 : :
507 : 6 : return time_var;
508 : : }
509 : :
510 : : /* Create new pdf_time_t object in heap */
511 : : pdf_time_t *
512 : 4 : pdf_time_new (pdf_error_t **error)
513 : : {
514 : : pdf_time_t *time_var;
515 : :
516 : 4 : time_var = pdf_time_allocate (error);
517 [ + - ]: 4 : if (time_var)
518 : 4 : pdf_time_clear (time_var);
519 : :
520 : 4 : return time_var;
521 : : }
522 : :
523 : : /* Duplicate pdf_time_t object in heap */
524 : : pdf_time_t *
525 : 2 : pdf_time_dup (const pdf_time_t *time_var_orig,
526 : : pdf_error_t **error)
527 : : {
528 : : pdf_time_t *time_var;
529 : :
530 [ - + ]: 2 : PDF_ASSERT_POINTER_RETURN_VAL (time_var_orig, NULL);
531 : :
532 : 2 : time_var = pdf_time_allocate (error);
533 [ + - ]: 2 : if (time_var)
534 : 2 : pdf_time_copy (time_var, time_var_orig);
535 : :
536 : 2 : return time_var;
537 : : }
538 : :
539 : : /* Destroy a pdf_time_t object from heap */
540 : : void
541 : 6 : pdf_time_destroy (pdf_time_t *time_var)
542 : : {
543 [ + - ]: 6 : if (time_var)
544 : 6 : pdf_dealloc (time_var);
545 : 6 : }
546 : :
547 : : /* Initializes a preallocated (heap or stack) pdf_time_t */
548 : : void
549 : 90981 : pdf_time_init (pdf_time_t *time_var)
550 : : {
551 [ - + ]: 90981 : PDF_ASSERT_POINTER_RETURN (time_var);
552 : :
553 : 90981 : pdf_time_clear (time_var);
554 : : }
555 : :
556 : : /* Initializes a preallocated (heap or stack) pdf_time_t with same contents as
557 : : * another given pdf_time_t. Just a sequence of
558 : : * pdf_time_init() + pdf_time_copy() */
559 : : void
560 : 39853 : pdf_time_init_dup (pdf_time_t *time_var,
561 : : const pdf_time_t *time_var_orig)
562 : : {
563 [ - + ]: 39853 : PDF_ASSERT_POINTER_RETURN (time_var_orig);
564 [ - + ]: 39853 : PDF_ASSERT_POINTER_RETURN (time_var);
565 : :
566 : 39853 : pdf_time_copy (time_var, time_var_orig);
567 : : }
568 : :
569 : : void
570 : 112817 : pdf_time_deinit (pdf_time_t *time_var)
571 : : {
572 : : /* Currently a no-op */
573 : 112817 : }
574 : :
575 : : /* ------------------------- Managing Time Values --------------------------- */
576 : :
577 : : /* Copy the contents of a given pdf_time_t object */
578 : : void
579 : 39856 : pdf_time_copy (pdf_time_t *copy,
580 : : const pdf_time_t *orig)
581 : : {
582 [ - + ]: 39856 : PDF_ASSERT_POINTER_RETURN (orig);
583 [ - + ]: 39856 : PDF_ASSERT_POINTER_RETURN (copy);
584 : :
585 : 39856 : copy->seconds = orig->seconds;
586 : 39856 : copy->gmt_offset = orig->gmt_offset;
587 : : }
588 : :
589 : : /* Clear contents of the pdf_time_t object */
590 : : void
591 : 92666 : pdf_time_clear (pdf_time_t *time_var)
592 : : {
593 : : /* Set time as January 1st, 1970 */
594 : 92666 : time_var->seconds = 0;
595 : : /* UTC */
596 : 92666 : time_var->gmt_offset = 0;
597 : 92666 : }
598 : :
599 : : /* Set time value with a pdf_i64_t variable representing UTC Unix time */
600 : : void
601 : 33453 : pdf_time_set_utc (pdf_time_t *time_var,
602 : : pdf_i64_t utc_seconds)
603 : : {
604 [ - + ]: 33453 : PDF_ASSERT_POINTER_RETURN (time_var);
605 : :
606 : 33453 : time_var->seconds = utc_seconds;
607 : 33453 : time_var->gmt_offset = 0;
608 : : }
609 : :
610 : : /* Set time value with a pdf_i64_t variable representing Local Unix time */
611 : : void
612 : 0 : pdf_time_set_local (pdf_time_t *time_var,
613 : : pdf_i64_t local_seconds,
614 : : pdf_i32_t local_gmt_offset)
615 : : {
616 [ # # ]: 0 : PDF_ASSERT_POINTER_RETURN (time_var);
617 : :
618 : : /* pdf_time_t always stores seconds in UTC */
619 : 0 : time_var->seconds = local_seconds - local_gmt_offset;
620 : 0 : time_var->gmt_offset = local_gmt_offset;
621 : : }
622 : :
623 : : #ifdef PDF_HOST_WIN32
624 : : /* Windows-specific function to set the time with a FILETIME structure */
625 : : pdf_bool_t
626 : : pdf_time_w32_set_from_filetime (pdf_time_t *time_var,
627 : : const FILETIME *filetime,
628 : : pdf_error_t **error)
629 : : {
630 : : struct pdf_time_cal_s calendar;
631 : : SYSTEMTIME systemtime;
632 : :
633 : : /*
634 : : BOOL WINAPI
635 : : FileTimeToSystemTime(const FILETIME *lpFileTime,
636 : : LPSYSTEMTIME lpSystemTime);
637 : :
638 : : If the function succeeds, the return value is nonzero.
639 : :
640 : : typedef struct _SYSTEMTIME {
641 : : WORD wYear;
642 : : WORD wMonth; (1: january, 2: february...)
643 : : WORD wDayOfWeek; (0:sunday, 1: monday...)
644 : : WORD wDay;
645 : : WORD wHour;
646 : : WORD wMinute;
647 : : WORD wSecond;
648 : : WORD wMilliseconds;
649 : : } SYSTEMTIME;
650 : :
651 : : */
652 : :
653 : : /* Convert filetime to systemtime calendar */
654 : : if (FileTimeToSystemTime (filetime, &systemtime) == 0)
655 : : {
656 : : /* TODO: Use FormatMessage() to include a string with the exact error
657 : : * in the pdf_error_t */
658 : : pdf_set_error (error,
659 : : PDF_EDOMAIN_BASE_TIME,
660 : : PDF_ERROR,
661 : : "couldn't get system time from FILETIME: %d",
662 : : (pdf_i32_t)GetLastError ());
663 : : return PDF_FALSE;
664 : : }
665 : :
666 : : /* Convert from systemtime calendar to our pdf_time_cal_s */
667 : : calendar.year = systemtime.wYear;
668 : : calendar.month = systemtime.wMonth;
669 : : calendar.day = systemtime.wDay;
670 : : calendar.hour = systemtime.wHour;
671 : : calendar.minute = systemtime.wMinute;
672 : : calendar.second = systemtime.wSecond;
673 : : /* Round seconds if milliseconds available */
674 : : if (systemtime.wMilliseconds >= 500)
675 : : calendar.second++;
676 : :
677 : : /* Store as UTC? */
678 : : calendar.gmt_offset = 0;
679 : :
680 : : /* For us, sunday is 7 */
681 : : calendar.dow = (systemtime.wDayOfWeek == 0) ? 7 : systemtime.wDayOfWeek;
682 : :
683 : : pdf_time_set_from_cal (time_var, &calendar);
684 : :
685 : : return PDF_TRUE;
686 : : }
687 : : #endif
688 : :
689 : : /*
690 : : * Based on the work done by Perl guys in DateTime:
691 : : * http://search.cpan.org/dist/DateTime/lib/DateTime.pm#Adding_a_Duration_to_a_Datetime
692 : : *
693 : : * "DateTime.pm always adds (or subtracts) days, then months, minutes, and then
694 : : * seconds and nanoseconds. If there are any boundary overflows, these are
695 : : * normalized at each step. For the days and months (the calendar) the local
696 : : * (not UTC) values are used. For minutes and seconds, the local values are
697 : : * used. This generally just works.
698 : : *
699 : : * This means that adding one month and one day to February 28, 2003 will
700 : : * produce the date April 1, 2003, not March 29, 2003."
701 : : *
702 : : * Thanks to S.Jansen for the link!
703 : : */
704 : : static void
705 : 5792 : pdf_time_add_cal_span_with_sign (pdf_time_t *time_var,
706 : : const struct pdf_time_cal_span_s *cal_span,
707 : : pdf_bool_t negate)
708 : : {
709 : : struct pdf_time_cal_s calendar;
710 : : pdf_i32_t sign;
711 : :
712 [ + + ]: 5792 : sign = (negate ? -1 : 1);
713 : :
714 : : /* Create Calendar type from the time object */
715 : 5792 : pdf_time_get_utc_cal (time_var, &calendar);
716 : 5792 : pdf_time_calendar_add_days (&calendar, sign * cal_span->days);
717 : 5792 : pdf_time_calendar_add_months (&calendar, sign * cal_span->months);
718 : 5792 : pdf_time_calendar_add_years (&calendar, sign * cal_span->years);
719 : 5792 : pdf_time_calendar_add_hours (&calendar, sign * cal_span->hours);
720 : 5792 : pdf_time_calendar_add_minutes (&calendar, sign * cal_span->minutes);
721 : 5792 : pdf_time_calendar_add_seconds (&calendar, sign * cal_span->seconds);
722 : :
723 : : /* Check for possible underflow condition */
724 [ + + ]: 5792 : if (calendar.year < 1970)
725 : : {
726 : : /* If underflow, reset the time to Unix time origin */
727 : 240 : pdf_time_clear (time_var);
728 : 240 : return;
729 : : }
730 : :
731 : : /* Generate time from the new calendar */
732 : 5792 : pdf_time_set_from_cal (time_var, &calendar);
733 : : }
734 : :
735 : : /* Add the time span represented by cal_span to the text object. */
736 : : void
737 : 5072 : pdf_time_add_cal_span (pdf_time_t *time_var,
738 : : const struct pdf_time_cal_span_s *cal_span)
739 : : {
740 [ - + ]: 5072 : PDF_ASSERT_POINTER_RETURN (time_var);
741 [ - + ]: 5072 : PDF_ASSERT_POINTER_RETURN (cal_span);
742 : :
743 : 5072 : pdf_time_add_cal_span_with_sign (time_var,
744 : : cal_span,
745 : : PDF_FALSE);
746 : : }
747 : :
748 : : /* Substract the time span represented by cal_span from the text object */
749 : : void
750 : 720 : pdf_time_sub_cal_span (pdf_time_t *time_var,
751 : : const struct pdf_time_cal_span_s *cal_span)
752 : : {
753 [ - + ]: 720 : PDF_ASSERT_POINTER_RETURN (time_var);
754 [ - + ]: 720 : PDF_ASSERT_POINTER_RETURN (cal_span);
755 : :
756 : 720 : pdf_time_add_cal_span_with_sign (time_var,
757 : : cal_span,
758 : : PDF_TRUE);
759 : : }
760 : :
761 : : /* Add the time span contained in time_span to time. As the time span is stored
762 : : * in seconds, the adding is direct. */
763 : : void
764 : 18317 : pdf_time_add_span (pdf_time_t *time_var,
765 : : pdf_i32_t time_span)
766 : : {
767 [ - + ]: 18317 : PDF_ASSERT_POINTER_RETURN (time_var);
768 : : /*
769 : : * TODO: Why does this fail?
770 : : * PDF_ASSERT_RETURN ((PDF_U64_MAX - time_var->seconds) >= time_span);
771 : : **/
772 : :
773 : 18317 : time_var->seconds += time_span;
774 : : }
775 : :
776 : : /* Subtract the time span contained in time_span to time. As the time span is
777 : : * stored in seconds. */
778 : : void
779 : 2 : pdf_time_sub_span (pdf_time_t *time_var,
780 : : pdf_i32_t time_span)
781 : : {
782 [ - + ]: 2 : PDF_ASSERT_POINTER_RETURN (time_var);
783 [ - + ]: 2 : PDF_ASSERT_RETURN (time_var->seconds >= time_span);
784 : :
785 : 2 : time_var->seconds -= time_span;
786 : : }
787 : :
788 : : /* Fill local_cal with the local calendar time of object. */
789 : : void
790 : 17313 : pdf_time_get_local_cal (const pdf_time_t *time_var,
791 : : struct pdf_time_cal_s *local_cal)
792 : : {
793 [ - + ]: 17313 : PDF_ASSERT_POINTER_RETURN (time_var);
794 [ - + ]: 17313 : PDF_ASSERT_POINTER_RETURN (local_cal);
795 : :
796 : 17313 : pdf_time_get_cal (time_var,
797 : : PDF_TIME_CAL_LOCAL,
798 : : local_cal);
799 : : }
800 : :
801 : : /* Get the UTC calendar time of a given time variable. */
802 : : void
803 : 13872 : pdf_time_get_utc_cal (const pdf_time_t *time_var,
804 : : struct pdf_time_cal_s *utc_cal)
805 : : {
806 [ - + ]: 13872 : PDF_ASSERT_POINTER_RETURN (time_var);
807 [ - + ]: 13872 : PDF_ASSERT_POINTER_RETURN (utc_cal);
808 : :
809 : 13872 : pdf_time_get_cal (time_var,
810 : : PDF_TIME_CAL_UTC,
811 : : utc_cal);
812 : : }
813 : :
814 : : /* Set the value of a time variable to a given calendar time. */
815 : : void
816 : 53376 : pdf_time_set_from_cal (pdf_time_t *time_var,
817 : : const struct pdf_time_cal_s *cal)
818 : : {
819 : : pdf_u64_t aux;
820 : : pdf_i32_t walker;
821 : :
822 [ - + ]: 53376 : PDF_ASSERT_POINTER_RETURN (time_var);
823 [ - + ]: 53376 : PDF_ASSERT_POINTER_RETURN (cal);
824 : :
825 : : /* Wrong calendar contents are treated as programmer errors */
826 [ - + ]: 53376 : PDF_ASSERT_RETURN (cal->year >= 1970);
827 [ - + ]: 53376 : PDF_ASSERT_RETURN (cal->month >= 1);
828 [ - + ]: 53376 : PDF_ASSERT_RETURN (cal->month <= 12);
829 [ - + ]: 53376 : PDF_ASSERT_RETURN (cal->day > 0);
830 [ - + ]: 53376 : PDF_ASSERT_RETURN (cal->day <= pdf_time_get_days_in_month (cal->year, cal->month));
831 [ - + ]: 53376 : PDF_ASSERT_RETURN (cal->hour < 24);
832 [ - + ]: 53376 : PDF_ASSERT_RETURN (cal->minute < 60);
833 [ - + ]: 53376 : PDF_ASSERT_RETURN (cal->second < 60);
834 : :
835 : : /* Note: There is no possible overflow with this procedure to
836 : : * get Unix time from calendar (year is 2-bytes max) */
837 : :
838 : : /* Add days per year until the current year in the calendar */
839 : 53376 : aux = 0;
840 [ + + ]: 859365 : for (walker = 1970; walker < cal->year; walker++)
841 : : {
842 [ + + ][ + + ]: 805989 : aux += (IS_LEAP_YEAR (walker) ?
[ + - ]
843 : : PDF_DAYS_IN_LEAP_YEAR : PDF_DAYS_IN_YEAR);
844 : : }
845 : :
846 : : /* Add days per month until the current month in the calendar */
847 : 106752 : aux += pdf_time_get_days_before_month (cal->year, cal->month);
848 : :
849 : : /* Add days in current month until the current required day */
850 : 53376 : aux += (cal->day - 1);
851 : :
852 : : /* Set date as seconds in the output variable */
853 : 53376 : time_var->seconds = aux * PDF_SECS_PER_DAY;
854 : :
855 : : /* Add hours as seconds */
856 : 53376 : time_var->seconds += (cal->hour * PDF_SECS_PER_HOUR);
857 : :
858 : : /* Add minutes as seconds */
859 : 53376 : time_var->seconds += (cal->minute * PDF_SECS_PER_MIN);
860 : :
861 : : /* Finally, add seconds */
862 : 53376 : time_var->seconds += cal->second;
863 : :
864 : : /* Set specific GMT offset if any */
865 [ + + ]: 53376 : if (cal->gmt_offset != 0)
866 : : {
867 [ - + ]: 45774 : if (cal->gmt_offset > time_var->seconds)
868 : : {
869 : : /* Avoid the underflow, by just resetting seconds to zero.
870 : : * This is very unlikely to happen, so no worth having a
871 : : * pdf_error_t arg just for this. */
872 : 0 : time_var->seconds = 0;
873 : : }
874 : : else
875 : : {
876 : : /* pdf_time_t always stores seconds in UTC */
877 : 45774 : time_var->seconds -= cal->gmt_offset;
878 : : }
879 : : }
880 : :
881 : : /* Store the offset */
882 : 53376 : time_var->gmt_offset = cal->gmt_offset;
883 : : }
884 : :
885 : : /* Set the local time offset of time to the one used by the operating system. */
886 : : void
887 : 77 : pdf_time_set_local_offset (pdf_time_t *time_var)
888 : : {
889 [ - + ]: 77 : PDF_ASSERT_POINTER_RETURN (time_var);
890 : :
891 : : /* Set local GMT offset */
892 : 77 : time_var->gmt_offset = pdf_time_context_get_gmt_offset ();
893 : : }
894 : :
895 : : /* ----------------------- Getting Time Intervals --------------------------- */
896 : :
897 : : /* Get time interval as Calendar Span */
898 : : void
899 : 2160 : pdf_time_diff_cal (const pdf_time_t *time1,
900 : : const pdf_time_t *time2,
901 : : struct pdf_time_cal_span_s *cal_span)
902 : : {
903 : : struct pdf_time_cal_s calendar1;
904 : : struct pdf_time_cal_s calendar2;
905 : : struct pdf_time_cal_s *p_big;
906 : : struct pdf_time_cal_s *p_small;
907 : : pdf_i32_t aux;
908 : :
909 [ - + ]: 2160 : PDF_ASSERT_POINTER_RETURN (time1);
910 [ - + ]: 2160 : PDF_ASSERT_POINTER_RETURN (time2);
911 [ - + ]: 2160 : PDF_ASSERT_POINTER_RETURN (cal_span);
912 : :
913 : 2160 : pdf_time_get_cal (time1,
914 : : PDF_TIME_CAL_UTC,
915 : : &calendar1);
916 : 2160 : pdf_time_get_cal (time2,
917 : : PDF_TIME_CAL_UTC,
918 : : &calendar2);
919 : :
920 : : /* Check which of the dates is bigger */
921 [ - + ]: 2160 : if (pdf_time_cmp (time1, time2) > 0)
922 : : {
923 : 0 : cal_span->sign = PDF_TRUE;
924 : 0 : p_big = &calendar1;
925 : 0 : p_small = &calendar2;
926 : : }
927 : : else
928 : : {
929 : 2160 : cal_span->sign = PDF_FALSE;
930 : 2160 : p_big = &calendar2;
931 : 2160 : p_small = &calendar1;
932 : : }
933 : :
934 : : /* Get diff of years directly (always + or 0) */
935 : 2160 : cal_span->years = p_big->year - p_small->year;
936 : :
937 : : #define DIFF_AND_CORRECT(field,spanfield,spanupperfield) \
938 : : do { \
939 : : aux = p_big->field - p_small->field; \
940 : : if (aux < 0) { \
941 : : cal_span->spanupperfield--; \
942 : : cal_span->spanfield = (-1) * aux; \
943 : : } else { \
944 : : cal_span->spanfield = aux; \
945 : : } \
946 : : } while(0)
947 : :
948 : : /* Get diff of months (could be -) */
949 [ - + ]: 2160 : DIFF_AND_CORRECT (month, months, years);
950 : : /* Get diff of days (could be -) */
951 [ - + ]: 2160 : DIFF_AND_CORRECT (day, days, months);
952 : : /* Get diff of hours (could be -) */
953 [ - + ]: 2160 : DIFF_AND_CORRECT (hour, hours, days);
954 : : /* Get diff of minutes (could be -) */
955 [ - + ]: 2160 : DIFF_AND_CORRECT (minute, minutes, hours);
956 : : /* Get diff of seconds (could be -) */
957 [ - + ]: 2160 : DIFF_AND_CORRECT (second, seconds, minutes);
958 : :
959 : : #undef DIFF_AND_CORRECT
960 : : }
961 : :
962 : : /* Get time interval as Span */
963 : : pdf_i64_t
964 : 2881 : pdf_time_diff (const pdf_time_t *time1,
965 : : const pdf_time_t *time2)
966 : : {
967 [ - + ]: 2881 : PDF_ASSERT_POINTER_RETURN_VAL (time1, -1);
968 [ - + ]: 2881 : PDF_ASSERT_POINTER_RETURN_VAL (time2, -1);
969 : :
970 : 2881 : return ((pdf_i64_t)time1->seconds - (pdf_i64_t)time2->seconds);
971 : : }
972 : :
973 : : /* ---------------------------- Time comparison ----------------------------- */
974 : :
975 : : /* Compares two times. */
976 : : pdf_i8_t
977 : 39167 : pdf_time_cmp (const pdf_time_t *time1,
978 : : const pdf_time_t *time2)
979 : : {
980 [ + + ]: 39167 : if (time1->seconds > time2->seconds)
981 : 6 : return 1;
982 [ + + ]: 39161 : if (time1->seconds < time2->seconds)
983 : 2140 : return -1;
984 : 39167 : return 0;
985 : : }
986 : :
987 : : /* ---------------------- Time printing and parsing ------------------------- */
988 : :
989 : : /* Create a string representation of a given time. */
990 : : pdf_char_t *
991 : 17151 : pdf_time_to_string (const pdf_time_t *time_var,
992 : : const enum pdf_time_string_format_e time_format,
993 : : pdf_u32_t options,
994 : : pdf_error_t **error)
995 : : {
996 [ - + ]: 17151 : PDF_ASSERT_POINTER_RETURN_VAL (time_var, NULL);
997 : : PDF_ASSERT_RETURN_VAL (time_format >= PDF_TIME_STRING_FORMAT_PDF, NULL);
998 [ - + ]: 17151 : PDF_ASSERT_RETURN_VAL (time_format <= PDF_TIME_STRING_FORMAT_GENERALIZED_ASN1, NULL);
999 : :
1000 [ + + + + : 17151 : switch (time_format)
- ]
1001 : : {
1002 : : case PDF_TIME_STRING_FORMAT_PDF:
1003 : 6860 : return pdf_time_to_string_pdf (time_var,
1004 : 6860 : (options & PDF_TIME_STRING_TRAILING_APOSTROPHE),
1005 : : error);
1006 : : case PDF_TIME_STRING_FORMAT_ISO_8601:
1007 : 3431 : return pdf_time_to_string_iso8601 (time_var, error);
1008 : : case PDF_TIME_STRING_FORMAT_UTC_ASN1:
1009 : 3430 : return pdf_time_to_string_utc_asn1 (time_var, error);
1010 : : case PDF_TIME_STRING_FORMAT_GENERALIZED_ASN1:
1011 : 3430 : return pdf_time_to_string_generalized_asn1 (time_var, error);
1012 : : default:
1013 : : /* Make compiler happy */
1014 : 17151 : return NULL;
1015 : : }
1016 : : }
1017 : :
1018 : : /* Get a string containing a time specification in some format and fill a time
1019 : : * variable with the parsed values. */
1020 : : pdf_bool_t
1021 : 40076 : pdf_time_set_from_string (pdf_time_t *time_var,
1022 : : const pdf_char_t *time_str,
1023 : : const enum pdf_time_string_format_e time_format,
1024 : : pdf_u32_t options,
1025 : : pdf_error_t **error)
1026 : : {
1027 [ - + ]: 40076 : PDF_ASSERT_POINTER_RETURN_VAL (time_var, PDF_FALSE);
1028 [ - + ]: 40076 : PDF_ASSERT_POINTER_RETURN_VAL (time_str, PDF_FALSE);
1029 : : PDF_ASSERT_RETURN_VAL (time_format >= PDF_TIME_STRING_FORMAT_PDF, PDF_FALSE);
1030 [ - + ]: 40076 : PDF_ASSERT_RETURN_VAL (time_format <= PDF_TIME_STRING_FORMAT_GENERALIZED_ASN1, PDF_FALSE);
1031 : :
1032 [ + + + + : 40076 : switch (time_format)
- ]
1033 : : {
1034 : : case PDF_TIME_STRING_FORMAT_PDF:
1035 : 15718 : return pdf_time_from_string_pdf (time_var,
1036 : : time_str,
1037 : 15718 : (options & PDF_TIME_STRING_TRAILING_APOSTROPHE),
1038 : : error);
1039 : : case PDF_TIME_STRING_FORMAT_ISO_8601:
1040 : 8208 : return pdf_time_from_string_iso8601 (time_var, time_str, error);
1041 : : case PDF_TIME_STRING_FORMAT_UTC_ASN1:
1042 : 7988 : return pdf_time_from_string_utc_asn1 (time_var, time_str, error);
1043 : : case PDF_TIME_STRING_FORMAT_GENERALIZED_ASN1:
1044 : 8162 : return pdf_time_from_string_generalized_asn1 (time_var, time_str, error);
1045 : : default:
1046 : : /* Make compiler happy */
1047 : 40076 : return PDF_FALSE;
1048 : : }
1049 : : }
1050 : :
1051 : : /* ---------------------- Getting the Current Time -------------------------- */
1052 : :
1053 : : /* Set the value of object to the current local time used by the operating
1054 : : * system. */
1055 : : void
1056 : 2 : pdf_time_set_to_current_local_time (pdf_time_t *time_var)
1057 : : {
1058 : : /* time() always returns UTC */
1059 : 2 : time_var->seconds = time (NULL);
1060 : : /* Store offset in the gmt_offset */
1061 : 2 : time_var->gmt_offset = pdf_time_context_get_gmt_offset ();
1062 : 2 : }
1063 : :
1064 : : /* Set the value of object to the current UTC time used by the operating
1065 : : * system. */
1066 : : void
1067 : 7989 : pdf_time_set_to_current_utc_time (pdf_time_t *time_var)
1068 : : {
1069 : : /* time() always returns UTC */
1070 : 7989 : time_var->seconds = time (NULL);
1071 : 7989 : time_var->gmt_offset = 0;
1072 : 7989 : }
1073 : :
1074 : : /* ---------------------- Calendar Spans Management ------------------------- */
1075 : :
1076 : : static pdf_i32_t
1077 : 2880 : pdf_time_span_from_cal_span (const struct pdf_time_cal_span_s *cal_span,
1078 : : const pdf_time_t *base_time)
1079 : : {
1080 : : pdf_i64_t span;
1081 : : pdf_time_t new_time;
1082 : :
1083 : : /* Duplicate base object and add calendar span */
1084 : 2880 : pdf_time_init_dup (&new_time, base_time);
1085 : 2880 : pdf_time_add_cal_span (&new_time, cal_span);
1086 : :
1087 : : /* Get the difference in seconds */
1088 : 2880 : span = pdf_time_diff (&new_time, base_time);
1089 : :
1090 : 2880 : pdf_time_deinit (&new_time);
1091 : :
1092 : 2880 : return span;
1093 : : }
1094 : :
1095 : : static void
1096 : 1440 : pdf_time_span_to_cal_span (pdf_i32_t span,
1097 : : const pdf_time_t *base_time,
1098 : : struct pdf_time_cal_span_s *cal_span)
1099 : : {
1100 : : pdf_time_t new_time;
1101 : :
1102 : : /* Duplicate base object and add calendar span,
1103 : : * and get both initial and new times as calendars
1104 : : */
1105 : 1440 : pdf_time_init_dup (&new_time, base_time);
1106 : 1440 : pdf_time_add_span (&new_time, span);
1107 : :
1108 : : /* Now, directly get calendar diff */
1109 : 1440 : pdf_time_diff_cal (base_time, &new_time, cal_span);
1110 : :
1111 : 1440 : pdf_time_deinit (&new_time);
1112 : 1440 : }
1113 : :
1114 : : /* Add two calendar spans. Since the calendar spans are relative (some years
1115 : : * has more days than another) the calendar spans are first resolved from a
1116 : : * base time to get the number of seconds, and then that number is stored in
1117 : : * the resulting calendar span */
1118 : : void
1119 : 720 : pdf_time_add_cal_span_with_base (const struct pdf_time_cal_span_s *span1,
1120 : : const struct pdf_time_cal_span_s *span2,
1121 : : const pdf_time_t *base_time,
1122 : : struct pdf_time_cal_span_s *result)
1123 : : {
1124 : : pdf_i32_t span_time;
1125 : :
1126 [ - + ]: 720 : PDF_ASSERT_POINTER_RETURN (span1);
1127 [ - + ]: 720 : PDF_ASSERT_POINTER_RETURN (span2);
1128 [ - + ]: 720 : PDF_ASSERT_POINTER_RETURN (base_time);
1129 [ - + ]: 720 : PDF_ASSERT_POINTER_RETURN (result);
1130 : :
1131 : 720 : span_time = pdf_time_span_from_cal_span (span1, base_time);
1132 : 720 : span_time += pdf_time_span_from_cal_span (span2, base_time);
1133 : :
1134 : : /* Get calendar span from the new result */
1135 : 720 : pdf_time_span_to_cal_span (span_time, base_time, result);
1136 : : }
1137 : :
1138 : : /* Compare two calendar spans previously resolved with a given base time. */
1139 : : pdf_i8_t
1140 : 14 : pdf_time_cal_span_cmp (const struct pdf_time_cal_span_s *span1,
1141 : : const struct pdf_time_cal_span_s *span2,
1142 : : const pdf_time_t *base_time)
1143 : : {
1144 : : /* Probably the best way to do it is convert the cal spans into pdf_time_t
1145 : : * and then compare the pdf_time_t objects */
1146 : : pdf_time_t time1;
1147 : : pdf_time_t time2;
1148 : : pdf_i8_t cmp_ret;
1149 : :
1150 [ - + ]: 14 : PDF_ASSERT_POINTER_RETURN_VAL (span1, -1);
1151 [ - + ]: 14 : PDF_ASSERT_POINTER_RETURN_VAL (span2, -1);
1152 [ - + ]: 14 : PDF_ASSERT_POINTER_RETURN_VAL (base_time, -1);
1153 : :
1154 : 14 : pdf_time_init_dup (&time1, base_time);
1155 : 14 : pdf_time_init_dup (&time2, base_time);
1156 : :
1157 : 14 : pdf_time_add_cal_span (&time1, span1);
1158 : 14 : pdf_time_add_cal_span (&time2, span2);
1159 : :
1160 : 14 : cmp_ret = pdf_time_cmp (&time1, &time2);
1161 : :
1162 : 14 : pdf_time_deinit (&time1);
1163 : 14 : pdf_time_deinit (&time2);
1164 : :
1165 : 14 : return cmp_ret;
1166 : : }
1167 : :
1168 : : /* Compute the difference between two calendar spans relative to a given base
1169 : : * time and store it in a given calendar span. */
1170 : : void
1171 : 720 : pdf_time_cal_span_diff (const struct pdf_time_cal_span_s *span1,
1172 : : const struct pdf_time_cal_span_s *span2,
1173 : : const pdf_time_t *base_time,
1174 : : struct pdf_time_cal_span_s *result)
1175 : : {
1176 : : pdf_i32_t span_time;
1177 : :
1178 : 720 : span_time = pdf_time_span_from_cal_span (span1, base_time);
1179 : 720 : span_time -= pdf_time_span_from_cal_span (span2, base_time);
1180 : :
1181 : : /* Get calendar span from the new result */
1182 : 720 : pdf_time_span_to_cal_span (span_time, base_time, result);
1183 : 720 : }
1184 : :
1185 : : /* End of pdf-time.c */
|