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, 2009, 2010 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-types.h>
32 : #include <pdf-time-context.h>
33 : #include <pdf-time-string.h>
34 : #include <pdf-time.h>
35 :
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 : #define PDF_MINIMUM_YEAR 1970
46 :
47 : enum pdf_time_cal_type_e {
48 : PDF_TIME_CAL_LOCAL,
49 : PDF_TIME_CAL_UTC
50 : };
51 :
52 : enum pdf_time_month_e {
53 : PDF_TIME_JANUARY = 1,
54 : PDF_TIME_FEBRUARY = 2,
55 : PDF_TIME_MARCH = 3,
56 : PDF_TIME_APRIL = 4,
57 : PDF_TIME_MAY = 5,
58 : PDF_TIME_JUNE = 6,
59 : PDF_TIME_JULY = 7,
60 : PDF_TIME_AUGUST = 8,
61 : PDF_TIME_SEPTEMBER = 9,
62 : PDF_TIME_OCTOBER = 10,
63 : PDF_TIME_NOVEMBER = 11,
64 : PDF_TIME_DECEMBER = 12,
65 : PDF_TIME_NMONTHS
66 : };
67 :
68 : /* Returns PDF_TRUE if the Olimpic Games [were/will be] celebrated in the given
69 : * year */
70 : static pdf_bool_t
71 : pdf_time_is_leap_year_p(pdf_u32_t year)
72 778510 : {
73 : /* A leap year is divisable by 4, but not by 100, except if divisable by
74 : * 400 */
75 778510 : return (((year % 4 == 0) && \
76 : ((year % 100 != 0) || \
77 : (year % 400 == 0))) ? \
78 : PDF_TRUE : PDF_FALSE);
79 : }
80 :
81 :
82 : /* Returns number of days in the given month */
83 : static pdf_u32_t
84 : pdf_time_get_days_in_month(const pdf_u32_t year,
85 : const enum pdf_time_month_e month)
86 1516080 : {
87 1516080 : switch(month)
88 : {
89 : case PDF_TIME_JANUARY:
90 : case PDF_TIME_MARCH:
91 : case PDF_TIME_MAY:
92 : case PDF_TIME_JULY:
93 : case PDF_TIME_AUGUST:
94 : case PDF_TIME_OCTOBER:
95 : case PDF_TIME_DECEMBER:
96 890967 : return 31;
97 : case PDF_TIME_APRIL:
98 : case PDF_TIME_JUNE:
99 : case PDF_TIME_SEPTEMBER:
100 : case PDF_TIME_NOVEMBER:
101 396848 : return 30;
102 : case PDF_TIME_FEBRUARY:
103 228265 : return (pdf_time_is_leap_year_p(year) ? 29 : 28);
104 : default:
105 0 : return 0;
106 : }
107 : }
108 :
109 :
110 : /* Returns number of days before the given month */
111 : static pdf_u32_t
112 : pdf_time_get_days_before_month(const pdf_u32_t year,
113 : const enum pdf_time_month_e month)
114 : {
115 274747 : enum pdf_time_month_e walk = PDF_TIME_JANUARY;
116 274747 : pdf_u32_t sum = 0;
117 1689784 : while(walk != month) {
118 1415037 : sum += pdf_time_get_days_in_month(year, walk++);
119 : }
120 274747 : return sum;
121 : }
122 :
123 : static pdf_bool_t
124 : pdf_time_is_valid_cal_p(const struct pdf_time_cal_s *p_cal_time)
125 62611 : {
126 : /*
127 : PDF_DEBUG_BASE("Calendar: %d/%d/%d %d:%d:%d off:%d",
128 : p_cal_time->year,
129 : p_cal_time->month,
130 : p_cal_time->day,
131 : p_cal_time->hour,
132 : p_cal_time->minute,
133 : p_cal_time->second,
134 : p_cal_time->gmt_offset);
135 : */
136 62611 : return ( ( (p_cal_time == NULL) || \
137 : (p_cal_time->year < PDF_MINIMUM_YEAR) || \
138 : (p_cal_time->month < PDF_TIME_JANUARY) || \
139 : (p_cal_time->month > PDF_TIME_DECEMBER) || \
140 : (p_cal_time->day == 0) || \
141 : (p_cal_time->day > pdf_time_get_days_in_month(p_cal_time->year,
142 : p_cal_time->month)) || \
143 : (p_cal_time->hour >= PDF_HOURS_PER_DAY) || \
144 : (p_cal_time->minute >= PDF_MINS_PER_HOUR) || \
145 : (p_cal_time->second >= PDF_SECS_PER_MIN) ) ? PDF_FALSE : PDF_TRUE);
146 :
147 : }
148 :
149 :
150 : /* Get Break-Down calendar from pdf_time_t */
151 : static pdf_status_t
152 : pdf_time_get_cal (const pdf_time_t time_var,
153 : const enum pdf_time_cal_type_e cal_type,
154 : struct pdf_time_cal_s *p_cal_time)
155 26774 : {
156 : /* Based on glibc's __offtime function */
157 :
158 : pdf_i32_t days;
159 : pdf_i64_t aux64;
160 : pdf_i32_t remaining;
161 : pdf_i32_t years;
162 : pdf_i32_t months;
163 : pdf_time_t new_time_var;
164 26774 : pdf_status_t p_status = PDF_OK;
165 :
166 : /* Duplicate time var */
167 26774 : new_time_var = pdf_time_dup(time_var);
168 :
169 : /* pdf_time_t always stores the date & time in UTC timescale, so we only need
170 : * to modify the time_var IF gmt_offset is not zero, in order to move the
171 : * date & time from UTC to local time specified by the offset */
172 26774 : if( (cal_type == PDF_TIME_CAL_LOCAL) && \
173 : (time_var->gmt_offset != 0) )
174 : {
175 : pdf_time_span_t delta;
176 : /* Modify time in the time object */
177 12543 : delta = pdf_time_span_new();
178 12543 : pdf_time_span_set_from_i32(&delta, time_var->gmt_offset);
179 12543 : pdf_time_add_span(new_time_var, delta);
180 12543 : pdf_time_span_destroy(&delta);
181 : }
182 :
183 26774 : aux64 = pdf_i64_new(0,0);
184 :
185 :
186 : /* Get date as days */
187 26774 : pdf_i64_div_i32_divisor(&aux64, new_time_var->seconds, PDF_SECS_PER_DAY, &p_status);
188 26774 : days = pdf_i64_to_i32(aux64);
189 : /* Get time in seconds */
190 26774 : pdf_i64_mod_i32_divisor(&aux64, new_time_var->seconds, PDF_SECS_PER_DAY, &p_status);
191 26774 : remaining = pdf_i64_to_i32(aux64);
192 : /* Get hours */
193 26774 : p_cal_time->hour = remaining / PDF_SECS_PER_HOUR;
194 : /* Get remaining */
195 26774 : remaining = remaining % PDF_SECS_PER_HOUR;
196 : /* Get minutes */
197 26774 : p_cal_time->minute = remaining / PDF_MINS_PER_HOUR;
198 : /* Get seconds */
199 26774 : p_cal_time->second = remaining % PDF_MINS_PER_HOUR;
200 :
201 : /* Seems that Unix origin time was thursday */
202 26774 : p_cal_time->dow = ((days+4)%7);
203 :
204 26774 : years = 1970;
205 :
206 :
207 68913 : while((days < 0) || \
208 : (days >= (pdf_time_is_leap_year_p(years) ? \
209 : (PDF_DAYS_IN_YEAR+1) : \
210 : (PDF_DAYS_IN_YEAR))))
211 : {
212 : pdf_i32_t yg;
213 15365 : yg = years;
214 :
215 : /* Compute number of years (assuming all years of 365 days) between the
216 : * origin and our date */
217 15365 : yg += (days / PDF_DAYS_IN_YEAR);
218 : /* Get number of remaining days after having added the fixed-size years
219 : If the number of remaining days is less than zero, go down 1 year */
220 15365 : yg -= ((days % PDF_DAYS_IN_YEAR) < 0);
221 :
222 :
223 : #define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
224 : /* Remove number of days due to the leap years */
225 15365 : days -= (((yg - years)*PDF_DAYS_IN_YEAR) + \
226 : (LEAPS_THRU_END_OF (yg - 1)) - \
227 : (LEAPS_THRU_END_OF (years - 1)));
228 15365 : years = yg;
229 : }
230 :
231 : /* Set year */
232 26774 : p_cal_time->year = years;// - 1900;
233 :
234 212136 : for (months = 11; \
235 451046 : days < pdf_time_get_days_before_month(p_cal_time->year,months); \
236 : --months)
237 : continue;
238 :
239 53548 : days -= pdf_time_get_days_before_month(p_cal_time->year,months);
240 :
241 : /* Set month and day of month */
242 26774 : p_cal_time->month = months;
243 26774 : if (pdf_time_get_days_in_month(p_cal_time->year, p_cal_time->month) < days + 1){
244 4711 : p_cal_time->day = days + 1 - pdf_time_get_days_in_month(p_cal_time->year, p_cal_time->month);
245 4711 : p_cal_time->month+=1;
246 4711 : if (p_cal_time->month == 13) {
247 0 : p_cal_time->month = 1;
248 0 : p_cal_time->year+=1;
249 : }
250 : }
251 : else
252 22063 : p_cal_time->day = days + 1;
253 :
254 : /* Finally, set gmt offset */
255 26774 : p_cal_time->gmt_offset = new_time_var->gmt_offset;
256 :
257 26774 : pdf_time_destroy(new_time_var);
258 :
259 26774 : return (pdf_time_is_valid_cal_p(p_cal_time) ? PDF_OK : PDF_ERROR);
260 : }
261 :
262 :
263 :
264 : /* Function to normalize a given date after having added YEARS */
265 : static void
266 : pdf_time_calendar_add_years(struct pdf_time_cal_s *p_calendar,
267 : const pdf_i32_t delta_years)
268 : {
269 : /* ADD years */
270 5102 : p_calendar->year += delta_years;
271 :
272 : /* The only thing to normalize is in case we reach Feb.29 in a non-leap
273 : * year */
274 5102 : if( (!pdf_time_is_leap_year_p(p_calendar->year)) && \
275 : (p_calendar->month == PDF_TIME_FEBRUARY) && \
276 : (p_calendar->day == 29) )
277 : {
278 0 : p_calendar->day = 28;
279 : }
280 : }
281 :
282 : /* Function to normalize a given date after having added MONTHS */
283 : static void
284 : pdf_time_calendar_add_months(struct pdf_time_cal_s *p_calendar,
285 : const pdf_i32_t delta_months)
286 5102 : {
287 5102 : if(delta_months > 0)
288 : {
289 3440 : p_calendar->month += delta_months;
290 6880 : while(p_calendar->month > 12)
291 : {
292 0 : p_calendar->month -= 12;
293 0 : p_calendar->year++;
294 : }
295 : }
296 1662 : else if(delta_months < 0)
297 : {
298 24 : p_calendar->month += delta_months;
299 48 : while(p_calendar->month < 1)
300 : {
301 0 : p_calendar->month += 12;
302 0 : p_calendar->year--;
303 : }
304 : }
305 :
306 : /* After having added months, we could need to normalize the days */
307 5102 : if(pdf_time_get_days_in_month(p_calendar->year,
308 : p_calendar->month) < p_calendar->day)
309 : {
310 25 : p_calendar->day = pdf_time_get_days_in_month(p_calendar->year,
311 : p_calendar->month);
312 : }
313 5102 : }
314 :
315 : /* Function to normalize a given date after having added DAYS */
316 : static void
317 : pdf_time_calendar_add_days(struct pdf_time_cal_s *p_calendar,
318 : const pdf_i32_t delta_days)
319 20408 : {
320 20408 : pdf_i32_t delta = delta_days;
321 :
322 : /* ADD days */
323 20408 : if(delta_days > 0)
324 : {
325 : pdf_i32_t days_in_month;
326 :
327 : /* Initialize days in month */
328 1820 : days_in_month = pdf_time_get_days_in_month(p_calendar->year, \
329 : (enum pdf_time_month_e)p_calendar->month);
330 3640 : while(delta > (days_in_month - p_calendar->day))
331 : {
332 : /* Go to start of next month */
333 0 : p_calendar->day = 1;
334 0 : pdf_time_calendar_add_months(p_calendar, 1);
335 :
336 : /* Update remaining delta and new days_in_month */
337 0 : delta -= (days_in_month - p_calendar->day +1);
338 0 : days_in_month = pdf_time_get_days_in_month(p_calendar->year, \
339 : (enum pdf_time_month_e)p_calendar->month);
340 : }
341 : /* Add final delta, which doesn't require month change */
342 1820 : p_calendar->day += delta;
343 : }
344 :
345 : /* SUBSTRACT days */
346 18588 : else if(delta_days < 0)
347 : {
348 : pdf_i32_t days_in_month;
349 :
350 : /* Initialize days in month */
351 0 : days_in_month = p_calendar->day - 1;
352 :
353 0 : while(days_in_month <= (-delta))
354 : {
355 : /* Go to the begin of previous month */
356 0 : p_calendar->day = 1;
357 0 : pdf_time_calendar_add_months(p_calendar, -1);
358 :
359 : /* Update remaining delta and new days_in_month */
360 0 : delta += days_in_month;
361 0 : days_in_month = pdf_time_get_days_in_month(p_calendar->year, \
362 : (enum pdf_time_month_e)p_calendar->month);
363 : }
364 : /* Add final delta, which doesn't require month change */
365 0 : delta += days_in_month;
366 0 : p_calendar->day += delta;
367 : }
368 20408 : }
369 :
370 : /* Function to normalize a given date after having added HOURS */
371 : static void
372 : pdf_time_calendar_add_hours(struct pdf_time_cal_s *p_calendar,
373 : const pdf_i32_t delta_hours)
374 15306 : {
375 : pdf_i32_t days;
376 : pdf_i32_t remaining_hours;
377 :
378 : /* No real problem with hours, as 1 day is always 24h */
379 15306 : days = delta_hours / PDF_HOURS_PER_DAY;
380 15306 : remaining_hours = delta_hours % PDF_HOURS_PER_DAY;
381 :
382 : /* Add remaining hours */
383 15306 : p_calendar->hour += remaining_hours;
384 : /* If we went back to the previous day, correct time and add 1 day more
385 : * to remove */
386 : if(p_calendar->hour < 0)
387 : {
388 : p_calendar->hour += PDF_HOURS_PER_DAY;
389 : days--;
390 : }
391 : /* If we went forward to the next day, correct time and add 1 day more
392 : * to add */
393 15306 : else if(p_calendar->hour >= PDF_HOURS_PER_DAY)
394 : {
395 0 : p_calendar->hour -= PDF_HOURS_PER_DAY;
396 0 : days++;
397 : }
398 :
399 : /* Add/Remove days... */
400 15306 : pdf_time_calendar_add_days(p_calendar, days);
401 15306 : }
402 :
403 : /* Function to normalize a given date after having added MINUTES */
404 : static void
405 : pdf_time_calendar_add_minutes(struct pdf_time_cal_s *p_calendar,
406 : const pdf_i32_t delta_minutes)
407 10204 : {
408 : pdf_i32_t hours;
409 : pdf_i32_t remaining_minutes;
410 :
411 : /* No real problem with minutes, as 1 hour is always 60minutes */
412 10204 : hours = delta_minutes / PDF_MINS_PER_HOUR;
413 10204 : remaining_minutes = delta_minutes % PDF_MINS_PER_HOUR;
414 :
415 : /* Add remaining minutes */
416 10204 : p_calendar->minute += remaining_minutes;
417 :
418 : /* If we went back to the previous hour, correct time and add 1 hour more
419 : * to remove */
420 : if(p_calendar->minute < 0)
421 : {
422 : p_calendar->minute += PDF_MINS_PER_HOUR;
423 : hours--;
424 : }
425 : /* If we went forward to the next day, correct time and add 1 hour more
426 : * to add */
427 10204 : else if(p_calendar->minute >= PDF_MINS_PER_HOUR)
428 : {
429 0 : p_calendar->minute -= PDF_MINS_PER_HOUR;
430 0 : hours++;
431 : }
432 :
433 : /* Add/Remove hours... */
434 10204 : pdf_time_calendar_add_hours(p_calendar, hours);
435 10204 : }
436 :
437 :
438 : /* Function to normalize a given date after having added SECONDS */
439 : static void
440 : pdf_time_calendar_add_seconds(struct pdf_time_cal_s *p_calendar,
441 : const pdf_i32_t delta_seconds)
442 : {
443 : pdf_i32_t minutes;
444 : pdf_i32_t remaining_seconds;
445 :
446 : /* No real problem with minutes, as 1 hour is always 60minutes */
447 5102 : minutes = delta_seconds / PDF_SECS_PER_MIN;
448 5102 : remaining_seconds = delta_seconds % PDF_SECS_PER_MIN;
449 :
450 : /* Add remaining seconds */
451 5102 : p_calendar->second += remaining_seconds;
452 :
453 : /* If we went back to the previous minute, correct time and add 1 minute more
454 : * to remove */
455 : if(p_calendar->second < 0)
456 : {
457 : p_calendar->second += PDF_SECS_PER_MIN;
458 : minutes--;
459 : }
460 : /* If we went forward to the next minute, correct time and add 1 minute more
461 : * to add */
462 5102 : else if(p_calendar->second >= PDF_SECS_PER_MIN)
463 : {
464 0 : p_calendar->second -= PDF_SECS_PER_MIN;
465 0 : minutes++;
466 : }
467 :
468 : /* Add/Remove minutes... */
469 5102 : pdf_time_calendar_add_minutes(p_calendar, minutes);
470 : }
471 :
472 :
473 :
474 :
475 :
476 :
477 : /* --------------------- Time Module Initialization ------------------------- */
478 :
479 : /* Initialize Time module. Warning! Not thread-safe, must be used only once when
480 : * the program starts. It will be in charge of detecting currently configured
481 : * time zone (GMT offset) and so on. */
482 : pdf_status_t
483 : pdf_time_init(void)
484 618 : {
485 : /* Start Time context */
486 618 : return pdf_time_context_init();
487 : }
488 :
489 :
490 : /* --------------------- Time Creation and Destruction ---------------------- */
491 :
492 : /* Create new pdf_time_t object */
493 : pdf_status_t
494 : pdf_time_new (pdf_time_t *element)
495 35833 : {
496 : /* Allocate object & Initialize all contents */
497 35833 : *element = (pdf_time_t) pdf_alloc (sizeof(struct pdf_time_s));
498 35833 : if (*element == NULL)
499 : {
500 : /* Not enough memory condition */
501 0 : return PDF_ENOMEM;
502 : }
503 :
504 : /* Create pdf_i64_t */
505 35833 : (*element)->seconds = pdf_i64_new(0,0);
506 35833 : pdf_time_clear(*element);
507 :
508 : /* Success */
509 35833 : return PDF_OK;
510 : }
511 :
512 : /* Duplicate pdf_time_t object */
513 : pdf_time_t
514 : pdf_time_dup (const pdf_time_t orig)
515 31123 : {
516 : pdf_time_t element;
517 :
518 31123 : if((pdf_time_new (&element) == PDF_OK) &&
519 : (pdf_time_copy(orig, element) != PDF_OK))
520 : {
521 0 : pdf_time_destroy(element);
522 0 : element = NULL;
523 : }
524 :
525 31123 : return element;
526 : }
527 :
528 :
529 : /* Destroy pdf_time_t object */
530 : pdf_status_t
531 : pdf_time_destroy (pdf_time_t time_var)
532 35801 : {
533 35801 : pdf_time_clear(time_var); /* Just in case additional contents are stored */
534 35801 : pdf_dealloc(time_var);
535 35801 : return PDF_OK;
536 : }
537 :
538 :
539 : /* Set time value with a 32-bit unsigned integer */
540 : pdf_status_t
541 : pdf_time_set_from_u32 (pdf_time_t time_var,
542 : pdf_u32_t seconds)
543 21604 : {
544 : pdf_status_t ret_code;
545 21604 : pdf_i64_assign(&(time_var->seconds), 0, seconds, &ret_code);
546 21604 : return ret_code;
547 : }
548 :
549 :
550 : /* Set time value with a pdf_i64_t variable */
551 : pdf_status_t
552 : pdf_time_set_from_i64 (pdf_time_t time_var,
553 : pdf_i64_t seconds)
554 8 : {
555 : pdf_status_t ret_code;
556 8 : pdf_i64_copy(seconds, &(time_var->seconds), &ret_code);
557 8 : return ret_code;
558 : }
559 :
560 : #ifdef PDF_HOST_WIN32
561 : /* Windows-specific function to set the time with a FILETIME structure */
562 : pdf_status_t
563 : pdf_time_w32_set_from_filetime (pdf_time_t time_var,
564 : const FILETIME *p_filetime)
565 : {
566 : SYSTEMTIME systemtime;
567 :
568 :
569 : /*
570 : BOOL WINAPI
571 : FileTimeToSystemTime(const FILETIME *lpFileTime,
572 : LPSYSTEMTIME lpSystemTime);
573 :
574 : If the function succeeds, the return value is nonzero.
575 :
576 : typedef struct _SYSTEMTIME {
577 : WORD wYear;
578 : WORD wMonth; (1: january, 2: february...)
579 : WORD wDayOfWeek; (0:sunday, 1: monday...)
580 : WORD wDay;
581 : WORD wHour;
582 : WORD wMinute;
583 : WORD wSecond;
584 : WORD wMilliseconds;
585 : } SYSTEMTIME;
586 :
587 : */
588 :
589 : /* Convert filetime to systemtime calendar */
590 : if(FileTimeToSystemTime(p_filetime,&systemtime)==0)
591 : {
592 : PDF_DEBUG_BASE("FileTimeToSystemTime failed...");
593 : return PDF_ERROR;
594 : }
595 : else
596 : {
597 : /* Convert from systemtime calendar to our pdf_time_cal_s */
598 : struct pdf_time_cal_s calendar;
599 :
600 : calendar.year = systemtime.wYear;
601 : calendar.month = systemtime.wMonth;
602 : calendar.day = systemtime.wDay;
603 : calendar.hour = systemtime.wHour;
604 : calendar.minute = systemtime.wMinute;
605 : calendar.second = systemtime.wSecond;
606 : /* Round seconds if milliseconds available */
607 : if(systemtime.wMilliseconds >= 500)
608 : {
609 : calendar.second++;
610 : }
611 : calendar.gmt_offset = 0;
612 : /* For us, sunday is 7 */
613 : calendar.dow = (systemtime.wDayOfWeek == 0) ? 7: systemtime.wDayOfWeek;
614 :
615 : return pdf_time_from_cal(time_var,&calendar);
616 : }
617 : }
618 : #endif
619 :
620 :
621 :
622 :
623 :
624 : /* ------------------------- Managing Time Values --------------------------- */
625 :
626 : /* Copy the contents of a given pdf_time_t object */
627 : pdf_status_t
628 : pdf_time_copy (const pdf_time_t orig,
629 : pdf_time_t copy)
630 31124 : {
631 31124 : pdf_status_t p_status = PDF_OK;
632 31124 : pdf_i64_copy (orig->seconds, &(copy->seconds), &p_status);
633 31124 : copy->gmt_offset = orig->gmt_offset;
634 31124 : return p_status;
635 : }
636 :
637 : /* Clear contents of the pdf_time_t object */
638 : pdf_status_t
639 : pdf_time_clear (pdf_time_t time_var)
640 75986 : {
641 75986 : pdf_status_t p_status = PDF_OK;
642 : /* Set time as January 1st, 1970 */
643 75986 : pdf_i64_assign_quick(&time_var->seconds, 0, &p_status);
644 : /* UTC */
645 75986 : time_var->gmt_offset = 0;
646 75986 : return p_status;
647 : }
648 :
649 :
650 :
651 : /*
652 : * Based on the work done by Perl guys in DateTime:
653 : * http://search.cpan.org/dist/DateTime/lib/DateTime.pm#Adding_a_Duration_to_a_Datetime
654 : *
655 : * "DateTime.pm always adds (or subtracts) days, then months, minutes, and then
656 : * seconds and nanoseconds. If there are any boundary overflows, these are
657 : * normalized at each step. For the days and months (the calendar) the local
658 : * (not UTC) values are used. For minutes and seconds, the local values are
659 : * used. This generally just works.
660 : *
661 : * This means that adding one month and one day to February 28, 2003 will
662 : * produce the date April 1, 2003, not March 29, 2003."
663 : *
664 : * Thanks to S.Jansen for the link!
665 : */
666 : static pdf_status_t
667 : pdf_time_add_cal_span_with_sign (pdf_time_t time_var,
668 : const struct pdf_time_cal_span_s *p_cal_span,
669 : int sign)
670 5102 : {
671 5102 : pdf_status_t status = PDF_ERROR;
672 :
673 : /* Check allowed sign values */
674 5102 : if( (sign == -1) || \
675 : (sign == 1) )
676 : {
677 : struct pdf_time_cal_s calendar;
678 :
679 : /* Create Calendar type from the time object */
680 5102 : if(pdf_time_get_utc_cal (time_var, &calendar) == PDF_OK)
681 : {
682 5102 : pdf_time_calendar_add_days(&calendar, sign * p_cal_span->days);
683 5102 : pdf_time_calendar_add_months(&calendar, sign * p_cal_span->months);
684 5102 : pdf_time_calendar_add_years(&calendar, sign * p_cal_span->years);
685 5102 : pdf_time_calendar_add_hours(&calendar, sign * p_cal_span->hours);
686 5102 : pdf_time_calendar_add_minutes(&calendar, sign * p_cal_span->minutes);
687 5102 : pdf_time_calendar_add_seconds(&calendar, sign * p_cal_span->seconds);
688 :
689 5102 : status = pdf_time_from_cal(time_var, &calendar);
690 : }
691 : }
692 :
693 5102 : return status;
694 : }
695 :
696 : /* Add the time span represented by cal_span to the text object. */
697 : pdf_status_t
698 : pdf_time_add_cal_span (pdf_time_t time_var,
699 : const struct pdf_time_cal_span_s *p_cal_span)
700 5072 : {
701 5072 : return pdf_time_add_cal_span_with_sign(time_var, p_cal_span, 1);
702 : }
703 :
704 : /* Substract the time span represented by cal_span from the text object */
705 : pdf_status_t
706 : pdf_time_sub_cal_span (pdf_time_t time_var,
707 : const struct pdf_time_cal_span_s *p_cal_span)
708 30 : {
709 30 : return pdf_time_add_cal_span_with_sign(time_var, p_cal_span, -1);
710 : }
711 :
712 : /* Add the time span contained in time_span to time. As the time span is stored
713 : * in seconds, the adding is direct. */
714 : pdf_status_t
715 : pdf_time_add_span (pdf_time_t time_var,
716 : const pdf_time_span_t time_span)
717 13984 : {
718 13984 : pdf_status_t p_status = PDF_OK;
719 13984 : pdf_i64_add ((&time_var->seconds),
720 : time_var->seconds,
721 : time_span, &p_status);
722 13984 : return p_status;
723 : }
724 :
725 : /* Subtract the time span contained in time_span to time. As the time span is
726 : * stored in seconds. */
727 : pdf_status_t
728 : pdf_time_sub_span (pdf_time_t time_var,
729 : const pdf_time_span_t time_span)
730 30258 : {
731 30258 : pdf_status_t p_status = PDF_OK;
732 30258 : pdf_i64_subtraction ((&time_var->seconds),
733 : time_var->seconds,
734 : time_span, &p_status);
735 30258 : return p_status;
736 : }
737 :
738 :
739 : /* Fill local_cal with the local calendar time of object. */
740 : pdf_status_t
741 : pdf_time_get_local_cal (const pdf_time_t time_var,
742 : struct pdf_time_cal_s *p_local_cal)
743 12630 : {
744 12630 : return pdf_time_get_cal(time_var, PDF_TIME_CAL_LOCAL,
745 : p_local_cal);
746 : }
747 :
748 : /* Get the UTC calendar time of a given time variable. */
749 : pdf_status_t
750 : pdf_time_get_utc_cal (const pdf_time_t time_var,
751 : struct pdf_time_cal_s *p_utc_cal)
752 9824 : {
753 9824 : return pdf_time_get_cal(time_var, PDF_TIME_CAL_UTC,
754 : p_utc_cal);
755 : }
756 :
757 :
758 : /* Set the value of a time variable to a given calendar time. */
759 : pdf_status_t
760 : pdf_time_from_cal (pdf_time_t time_var,
761 : const struct pdf_time_cal_s *p_cal_time)
762 35837 : {
763 : pdf_i64_t aux;
764 : pdf_i32_t walker;
765 35837 : pdf_status_t p_status = PDF_OK;
766 :
767 35837 : if( (time_var == NULL) || \
768 : (! pdf_time_is_valid_cal_p(p_cal_time)) )
769 : {
770 : PDF_DEBUG_BASE("Invalid arguments received");
771 0 : return PDF_EBADDATA;
772 : }
773 :
774 : /* Initialize days to 0 */
775 35837 : aux = pdf_i64_new(0,0);
776 :
777 : /* Add days per year until the current year in the calendar */
778 35837 : walker = 1970;
779 575868 : while(walker < p_cal_time->year)
780 : {
781 504194 : pdf_i64_add_i32(&aux, aux, \
782 : (pdf_time_is_leap_year_p(walker) ? \
783 : PDF_DAYS_IN_LEAP_YEAR : PDF_DAYS_IN_YEAR), &p_status);
784 504194 : walker++;
785 : }
786 :
787 : /* Add days per month until the current month in the calendar */
788 71674 : pdf_i64_add_i32(&aux, aux, pdf_time_get_days_before_month(p_cal_time->year,
789 : p_cal_time->month), &p_status);
790 :
791 : /* Add days in current month until the current required day */
792 35837 : pdf_i64_add_i32(&aux, aux, p_cal_time->day -1, &p_status);
793 :
794 : /* Set date as seconds in the output variable */
795 35837 : pdf_i64_mult_i32(&(time_var->seconds), aux, PDF_SECS_PER_DAY, &p_status);
796 :
797 : /* Add hours as seconds */
798 35837 : pdf_i64_add_i32(&(time_var->seconds), \
799 : (time_var->seconds), \
800 : p_cal_time->hour * PDF_SECS_PER_HOUR, &p_status);
801 : /* Add minutes as seconds */
802 35837 : pdf_i64_add_i32(&(time_var->seconds), \
803 : (time_var->seconds), \
804 : p_cal_time->minute * PDF_SECS_PER_MIN, &p_status);
805 : /* Finally, add seconds */
806 35837 : pdf_i64_add_i32(&(time_var->seconds), \
807 : (time_var->seconds), \
808 : p_cal_time->second, &p_status);
809 :
810 : /* Set specific GMT offset if any */
811 35837 : if(p_cal_time->gmt_offset != 0)
812 : {
813 : /* Remove it from the time value (calendar comes in local time, so
814 : * we must remove the offset to get the pdf_time_t->seconds in UTC. */
815 30255 : pdf_time_span_t delta = pdf_time_span_new();
816 30255 : pdf_time_span_set_from_i32(&delta, p_cal_time->gmt_offset);
817 30255 : pdf_time_sub_span(time_var, delta);
818 30255 : pdf_time_span_destroy(&delta);
819 : }
820 :
821 : /* Store the offset */
822 35837 : time_var->gmt_offset = p_cal_time->gmt_offset;
823 :
824 35837 : return PDF_OK;
825 : }
826 :
827 : /* Set the local time offset of time to the one used by the operating system. */
828 : pdf_status_t
829 : pdf_time_set_local_offset (pdf_time_t time_var)
830 74 : {
831 : /* Set local GMT offset */
832 74 : time_var->gmt_offset = pdf_time_context_get_gmt_offset();
833 74 : return PDF_OK;
834 : }
835 :
836 :
837 : /* ----------------------- Getting Time Intervals --------------------------- */
838 :
839 : /* Get time interval as Calendar Span */
840 : pdf_status_t
841 : pdf_time_diff_cal (const pdf_time_t time1,
842 : const pdf_time_t time2,
843 : struct pdf_time_cal_span_s *p_cal_span)
844 2160 : {
845 2160 : pdf_status_t ret_code = PDF_ERROR;
846 : struct pdf_time_cal_s calendar1;
847 : struct pdf_time_cal_s calendar2;
848 :
849 2160 : if( (p_cal_span != NULL) && \
850 : (pdf_time_get_cal(time1,
851 : PDF_TIME_CAL_UTC,
852 : &calendar1) == PDF_OK) && \
853 : (pdf_time_get_cal(time2,
854 : PDF_TIME_CAL_UTC,
855 : &calendar2) == PDF_OK) )
856 : {
857 : struct pdf_time_cal_s *p_big;
858 : struct pdf_time_cal_s *p_small;
859 : pdf_i32_t aux;
860 :
861 : /* Check which of the dates is bigger */
862 2160 : if(pdf_time_cmp(time1, time2) > 0)
863 : {
864 0 : p_cal_span->sign = PDF_TRUE;
865 0 : p_big = &calendar1;
866 0 : p_small = &calendar2;
867 : }
868 : else
869 : {
870 2160 : p_cal_span->sign = PDF_FALSE;
871 2160 : p_big = &calendar2;
872 2160 : p_small = &calendar1;
873 : }
874 :
875 : /* Get diff of years directly (always + or 0) */
876 2160 : p_cal_span->years = p_big->year - p_small->year;
877 :
878 : #define DIFF_AND_CORRECT(field,spanfield,spanupperfield) \
879 : do { \
880 : aux = p_big->field - p_small->field; \
881 : if(aux < 0) { \
882 : p_cal_span->spanupperfield--; \
883 : p_cal_span->spanfield = (-1)*aux; \
884 : } else { \
885 : p_cal_span->spanfield = aux; \
886 : } \
887 : } while(0)
888 :
889 : /* Get diff of months (could be -) */
890 2160 : DIFF_AND_CORRECT(month, months, years);
891 : /* Get diff of days (could be -) */
892 2160 : DIFF_AND_CORRECT(day, days, months);
893 : /* Get diff of hours (could be -) */
894 2160 : DIFF_AND_CORRECT(hour, hours, days);
895 : /* Get diff of minutes (could be -) */
896 2160 : DIFF_AND_CORRECT(minute, minutes, hours);
897 : /* Get diff of seconds (could be -) */
898 2160 : DIFF_AND_CORRECT(second, seconds, minutes);
899 :
900 : #undef DIFF_AND_CORRECT
901 :
902 2160 : ret_code = PDF_OK;
903 : }
904 :
905 2160 : return ret_code;
906 : }
907 :
908 : /* Get time interval as Span */
909 : pdf_status_t
910 : pdf_time_diff (const pdf_time_t time1,
911 : const pdf_time_t time2,
912 : pdf_time_span_t *p_time_span)
913 2881 : {
914 2881 : pdf_status_t p_status = PDF_OK;
915 2881 : pdf_i64_subtraction(p_time_span, time1->seconds, time2->seconds, &p_status);
916 2881 : return p_status;
917 : }
918 :
919 :
920 : /* ---------------------------- Time comparison ----------------------------- */
921 :
922 : /* Compares two times. */
923 : pdf_i32_t
924 : pdf_time_cmp (const pdf_time_t time1,
925 : const pdf_time_t time2)
926 25134 : {
927 25134 : return (pdf_i32_t)pdf_i64_cmp(time1->seconds, time2->seconds);
928 : }
929 :
930 :
931 : /* ---------------------- Time printing and parsing ------------------------- */
932 :
933 : /* Create a string representation of a given time. */
934 : pdf_char_t *
935 : pdf_time_to_string (const pdf_time_t time_var,
936 : const enum pdf_time_format_e time_format,
937 : pdf_bool_t include_trailing_apostrophe)
938 12471 : {
939 12471 : switch(time_format)
940 : {
941 : case PDF_TIME_FORMAT_PDF:
942 4988 : return pdf_time_to_string_pdf (time_var,
943 : include_trailing_apostrophe);
944 : case PDF_TIME_FORMAT_ISO_8601:
945 2495 : return pdf_time_to_string_iso8601(time_var);
946 : case PDF_TIME_FORMAT_UTC_ASN1:
947 2494 : return pdf_time_to_string_utc_asn1(time_var);
948 : case PDF_TIME_FORMAT_GENERALIZED_ASN1:
949 2494 : return pdf_time_to_string_generalized_asn1(time_var);
950 : default:
951 0 : return NULL;
952 : }
953 : }
954 :
955 :
956 :
957 : /* Get a string containing a time specification in some format and fill a time
958 : * variable with the parsed values. */
959 : pdf_status_t
960 : pdf_time_from_string (pdf_time_t time_var,
961 : const pdf_char_t *time_str,
962 : const enum pdf_time_format_e time_format,
963 : pdf_bool_t require_trailing_apostrophe)
964 23544 : {
965 23544 : switch(time_format)
966 : {
967 : case PDF_TIME_FORMAT_PDF:
968 9260 : return pdf_time_from_string_pdf(time_var, time_str, require_trailing_apostrophe);
969 : case PDF_TIME_FORMAT_ISO_8601:
970 4850 : return pdf_time_from_string_iso8601(time_var, time_str);
971 : case PDF_TIME_FORMAT_UTC_ASN1:
972 4630 : return pdf_time_from_string_utc_asn1(time_var, time_str);
973 : case PDF_TIME_FORMAT_GENERALIZED_ASN1:
974 4804 : return pdf_time_from_string_generalized_asn1(time_var, time_str);
975 : default:
976 0 : return PDF_ERROR;
977 : }
978 : }
979 :
980 :
981 : /* ---------------------- Getting the Current Time -------------------------- */
982 :
983 : /* Set the value of object to the current local time used by the operating
984 : * system. */
985 : pdf_status_t
986 : pdf_time_set_to_current_local_time (pdf_time_t time_var)
987 2 : {
988 2 : if(pdf_time_set_to_current_utc_time(time_var) == PDF_OK)
989 : {
990 : /* And store offset in the gmt_offset */
991 2 : time_var->gmt_offset = pdf_time_context_get_gmt_offset();
992 2 : return PDF_OK;
993 : }
994 : else
995 : {
996 0 : return PDF_ERROR;
997 : }
998 : }
999 :
1000 :
1001 : /* Set the value of object to the current UTC time used by the operating
1002 : * system. */
1003 : pdf_status_t
1004 : pdf_time_set_to_current_utc_time (pdf_time_t time_var)
1005 4633 : {
1006 4633 : pdf_status_t p_status = PDF_OK;
1007 4633 : time_t time_now = time(NULL);
1008 4633 : if(time_now != -1)
1009 : {
1010 : /* At least until 2038 this call will work correctly, even in systems with
1011 : * a 32bit time_t */
1012 4633 : pdf_i64_assign_quick(&(time_var->seconds), (pdf_i32_t)time_now, &p_status);
1013 4633 : time_var->gmt_offset = 0;
1014 : }
1015 4633 : return p_status;
1016 : }
1017 :
1018 :
1019 : /* ----------------- Time Span Creation and Destruction --------------------- */
1020 : /* Note: It seems quite weird to manage the time span as any other pdf_X object,
1021 : * taking into account that it's just a typedef of pdf_i64_t, BUT, keeping the
1022 : * common interface would allow easy updates in the future if needed */
1023 :
1024 : /* Create new time span object */
1025 : pdf_time_span_t
1026 : pdf_time_span_new (void)
1027 45711 : {
1028 45711 : return pdf_i64_new(0,0);
1029 : }
1030 :
1031 :
1032 : /* Duplicate time span object */
1033 : pdf_time_span_t
1034 : pdf_time_span_dup (const pdf_time_span_t span)
1035 1 : {
1036 : pdf_time_span_t new_span;
1037 1 : new_span = pdf_time_span_new();
1038 1 : pdf_time_span_copy(span, &new_span);
1039 1 : return new_span;
1040 : }
1041 :
1042 :
1043 : /* Destroy time span object */
1044 : pdf_status_t
1045 : pdf_time_span_destroy (pdf_time_span_t *p_span)
1046 45705 : {
1047 45705 : return PDF_OK;
1048 : }
1049 :
1050 :
1051 : /* --------------------- Managing Time Span Values -------------------------- */
1052 :
1053 : /* Set the value of a time span from a 64 bits signed number */
1054 : pdf_status_t
1055 : pdf_time_span_set (pdf_time_span_t *p_span,
1056 : const pdf_i32_t high_value,
1057 : const pdf_u32_t low_value)
1058 15 : {
1059 15 : pdf_status_t p_status = PDF_OK;
1060 15 : pdf_i64_assign(p_span, high_value, low_value, &p_status);
1061 15 : return p_status;
1062 : }
1063 :
1064 :
1065 : /* Set the value of a time span from a 32 bits signed number. */
1066 : pdf_status_t
1067 : pdf_time_span_set_from_i32 (pdf_time_span_t *p_span,
1068 : const pdf_i32_t seconds)
1069 42810 : {
1070 42810 : pdf_status_t p_status = PDF_OK;
1071 42810 : pdf_i64_assign_quick(p_span, seconds, &p_status);
1072 42810 : return p_status;
1073 : }
1074 :
1075 :
1076 : /* Change sign of time span */
1077 : pdf_status_t
1078 : pdf_time_span_negate (pdf_time_span_t *p_span)
1079 3 : {
1080 3 : pdf_status_t p_status = PDF_OK;
1081 3 : if (p_span == NULL)
1082 1 : return PDF_ERROR;
1083 2 : pdf_i64_neg(p_span, *p_span, &p_status);
1084 2 : return p_status;
1085 : }
1086 :
1087 :
1088 : /* Add two time spans and store the result in another time span. */
1089 : pdf_status_t
1090 : pdf_time_span_add (const pdf_time_span_t span1,
1091 : const pdf_time_span_t span2,
1092 : pdf_time_span_t *p_result)
1093 722 : {
1094 722 : pdf_status_t p_status = PDF_OK;
1095 722 : pdf_i64_add((pdf_i64_t *)p_result, span1, span2, &p_status);
1096 722 : return p_status;
1097 : }
1098 :
1099 : /* Copy the value of a time span into another time span. */
1100 : pdf_status_t
1101 : pdf_time_span_copy (const pdf_time_span_t orig,
1102 : pdf_time_span_t *p_dest)
1103 3 : {
1104 3 : pdf_status_t p_status = PDF_OK;
1105 3 : pdf_i64_copy(orig, (pdf_i64_t *)p_dest, &p_status);
1106 3 : return p_status;
1107 : }
1108 :
1109 : /* Difference two time spans and store the result (maybe negative) into another
1110 : * time span. */
1111 : pdf_status_t
1112 : pdf_time_span_diff (const pdf_time_span_t span1,
1113 : const pdf_time_span_t span2,
1114 : pdf_time_span_t *p_result)
1115 722 : {
1116 722 : pdf_status_t p_status= PDF_OK;
1117 722 : pdf_i64_subtraction(p_result, span1, span2, &p_status);
1118 722 : return p_status;
1119 : }
1120 :
1121 : /* Get the value of a time span in seconds. */
1122 : pdf_i64_t
1123 : pdf_time_span_to_secs (const pdf_time_span_t span)
1124 12 : {
1125 12 : return span;
1126 : }
1127 :
1128 :
1129 : /* ------------------------- Time Span Comparison --------------------------- */
1130 :
1131 : /* Compare two time spans */
1132 : pdf_i32_t
1133 : pdf_time_span_cmp (const pdf_time_span_t span1,
1134 : const pdf_time_span_t span2)
1135 4 : {
1136 4 : return (pdf_i64_cmp(span1, span2));
1137 : }
1138 :
1139 :
1140 : /* ---------------------- Calendar Spans Management ------------------------- */
1141 :
1142 :
1143 :
1144 : static pdf_status_t
1145 : pdf_time_span_from_cal_span(pdf_time_span_t *p_span,
1146 : const struct pdf_time_cal_span_s *p_cal_span,
1147 : const pdf_time_t base_time)
1148 2880 : {
1149 2880 : pdf_status_t ret_code = PDF_ERROR;
1150 2880 : pdf_time_t new_time = NULL;
1151 :
1152 : /* Duplicate base object and add calendar span */
1153 2880 : new_time = pdf_time_dup(base_time);
1154 2880 : if( (new_time != NULL) &&
1155 : (pdf_time_add_cal_span(new_time,p_cal_span) == PDF_OK) )
1156 : {
1157 : /* Get the difference in seconds */
1158 2880 : ret_code = pdf_time_diff(new_time, base_time, p_span);
1159 2880 : pdf_time_destroy(new_time);
1160 2880 : new_time = NULL;
1161 : }
1162 :
1163 : /* Destroy allocated object, if any */
1164 2880 : if(new_time != NULL)
1165 : {
1166 0 : pdf_time_destroy(new_time);
1167 : }
1168 2880 : return ret_code;
1169 : }
1170 :
1171 :
1172 : static pdf_status_t
1173 : pdf_time_span_to_cal_span(struct pdf_time_cal_span_s *p_cal_span,
1174 : const pdf_time_span_t span,
1175 : const pdf_time_t base_time)
1176 1440 : {
1177 1440 : pdf_status_t ret_code = PDF_ERROR;
1178 1440 : pdf_time_t new_time = NULL;
1179 :
1180 : /* Duplicate base object and add calendar span,
1181 : * and get both initial and new times as calendars
1182 : */
1183 1440 : new_time = pdf_time_dup(base_time);
1184 1440 : if((new_time != NULL) && \
1185 : (pdf_time_add_span(new_time,span) == PDF_OK))
1186 : {
1187 : /* Now, directly get calendar diff */
1188 1440 : ret_code = pdf_time_diff_cal(base_time, new_time, p_cal_span);
1189 : }
1190 :
1191 : /* Destroy allocated object, if any */
1192 1440 : if(new_time != NULL)
1193 : {
1194 1440 : pdf_time_destroy(new_time);
1195 : }
1196 1440 : return ret_code;
1197 : }
1198 :
1199 : /* Add two calendar spans. Since the calendar spans are relative (some years
1200 : * has more days than another) the calendar spans are first resolved from a
1201 : * base time to get the number of seconds, and then that number is stored in
1202 : * the resulting calendar span */
1203 : pdf_status_t
1204 : pdf_time_add_cal_span_with_base (const struct pdf_time_cal_span_s *p_span1,
1205 : const struct pdf_time_cal_span_s *p_span2,
1206 : const pdf_time_t base_time,
1207 : struct pdf_time_cal_span_s *p_result)
1208 720 : {
1209 720 : pdf_status_t ret_code = PDF_ERROR;
1210 : pdf_time_span_t span_time_1;
1211 : pdf_time_span_t span_time_2;
1212 :
1213 720 : span_time_1 = pdf_time_span_new();
1214 720 : span_time_2 = pdf_time_span_new();
1215 :
1216 720 : if( (p_span1 != NULL) && \
1217 : (p_span2 != NULL) && \
1218 : (pdf_time_span_from_cal_span(&span_time_1,
1219 : p_span1,
1220 : base_time) == PDF_OK) && \
1221 : (pdf_time_span_from_cal_span(&span_time_2,
1222 : p_span2,
1223 : base_time) == PDF_OK) )
1224 : {
1225 : /* Now add two time spans */
1226 720 : pdf_time_span_add(span_time_1, span_time_2, &span_time_1);
1227 :
1228 : /* Get calendar span from the new result */
1229 720 : ret_code = pdf_time_span_to_cal_span(p_result,
1230 : span_time_1,
1231 : base_time);
1232 : }
1233 :
1234 720 : pdf_time_span_destroy(&span_time_1);
1235 720 : pdf_time_span_destroy(&span_time_2);
1236 720 : return ret_code;
1237 : }
1238 :
1239 : /* Compare two calendar spans previously resolved with a given base time. */
1240 : pdf_i32_t
1241 : pdf_time_cal_span_cmp (const struct pdf_time_cal_span_s *p_span1,
1242 : const struct pdf_time_cal_span_s *p_span2,
1243 : const pdf_time_t base_time,
1244 : pdf_status_t *p_ret_code)
1245 14 : {
1246 : /* Probably the best way to do it is convert the cal spans into pdf_time_t
1247 : * and then compare the pdf_time_ts */
1248 : pdf_time_t time1;
1249 : pdf_time_t time2;
1250 14 : pdf_i32_t cmp_ret = 0;
1251 14 : pdf_status_t ret_code = PDF_ERROR;
1252 :
1253 14 : time1 = pdf_time_dup(base_time);
1254 14 : time2 = pdf_time_dup(base_time);
1255 :
1256 14 : if( (time1 != NULL) && \
1257 : (time2 != NULL) && \
1258 : (p_span1 != NULL) && \
1259 : (p_span2 != NULL) && \
1260 : (pdf_time_add_cal_span(time1, p_span1) == PDF_OK) && \
1261 : (pdf_time_add_cal_span(time2, p_span2) == PDF_OK) )
1262 : {
1263 14 : cmp_ret = pdf_time_cmp(time1, time2);
1264 14 : ret_code = PDF_OK;
1265 : }
1266 :
1267 14 : if(p_ret_code != NULL)
1268 : {
1269 14 : *p_ret_code = ret_code;
1270 : }
1271 :
1272 14 : pdf_time_destroy(time1);
1273 14 : pdf_time_destroy(time2);
1274 14 : return cmp_ret;
1275 : }
1276 :
1277 : /* Compute the difference between two calendar spans relative to a given base
1278 : * time and store it in a given calendar span. */
1279 : pdf_status_t
1280 : pdf_time_cal_span_diff (const struct pdf_time_cal_span_s *p_span1,
1281 : const struct pdf_time_cal_span_s *p_span2,
1282 : const pdf_time_t base_time,
1283 : struct pdf_time_cal_span_s *p_result)
1284 720 : {
1285 720 : pdf_status_t ret_code = PDF_ERROR;
1286 : pdf_time_span_t span_time_1;
1287 : pdf_time_span_t span_time_2;
1288 :
1289 720 : span_time_1 = pdf_time_span_new();
1290 720 : span_time_2 = pdf_time_span_new();
1291 :
1292 720 : if((p_span1 != NULL) && \
1293 : (p_span2 != NULL) && \
1294 : (pdf_time_span_from_cal_span(&span_time_1,
1295 : p_span1,
1296 : base_time) == PDF_OK) && \
1297 : (pdf_time_span_from_cal_span(&span_time_2,
1298 : p_span2,
1299 : base_time) == PDF_OK) )
1300 : {
1301 : /* Now substract the two time spans */
1302 720 : pdf_time_span_diff(span_time_1, span_time_2, &span_time_1);
1303 :
1304 : /* Get calendar span from the new result */
1305 720 : ret_code = pdf_time_span_to_cal_span(p_result,
1306 : span_time_1,
1307 : base_time);
1308 : }
1309 :
1310 720 : pdf_time_span_destroy(&span_time_1);
1311 720 : pdf_time_span_destroy(&span_time_2);
1312 720 : return ret_code;
1313 : }
1314 :
1315 :
1316 : /* End of pdf-time.c */
|