pacemaker  2.0.1-9e909a5bdd
Scalable High-Availability cluster resource manager
iso8601.c
Go to the documentation of this file.
1 /*
2  * Copyright 2005-2018 Andrew Beekhof <andrew@beekhof.net>
3  *
4  * This source code is licensed under the GNU Lesser General Public License
5  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
6  */
7 
8 /*
9  * Primary reference:
10  * http://en.wikipedia.org/wiki/ISO_8601 (as at 2005-08-01)
11  *
12  * Secondary references:
13  * http://hydracen.com/dx/iso8601.htm
14  * http://www.personal.ecu.edu/mccartyr/ISOwdALG.txt
15  * http://www.personal.ecu.edu/mccartyr/isowdcal.html
16  * http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
17  *
18  */
19 
20 #include <crm_internal.h>
21 #include <crm/crm.h>
22 #include <time.h>
23 #include <ctype.h>
24 #include <crm/common/iso8601.h>
26 
27 /*
28  * Andrew's code was originally written for OSes whose "struct tm" contains:
29  * long tm_gmtoff; :: Seconds east of UTC
30  * const char *tm_zone; :: Timezone abbreviation
31  * Some OSes lack these, instead having:
32  * time_t (or long) timezone;
33  :: "difference between UTC and local standard time"
34  * char *tzname[2] = { "...", "..." };
35  * I (David Lee) confess to not understanding the details. So my attempted
36  * generalisations for where their use is necessary may be flawed.
37  *
38  * 1. Does "difference between ..." subtract the same or opposite way?
39  * 2. Should it use "altzone" instead of "timezone"?
40  * 3. Should it use tzname[0] or tzname[1]? Interaction with timezone/altzone?
41  */
42 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
43 # define GMTOFF(tm) ((tm)->tm_gmtoff)
44 #else
45 /* Note: extern variable; macro argument not actually used. */
46 # define GMTOFF(tm) (-timezone+daylight)
47 #endif
48 
49 struct crm_time_s {
50  int years;
51  int months; /* Only for durations */
52  int days;
53  int seconds;
54  int offset; /* Seconds */
55  bool duration;
56 };
57 
58 char *crm_time_as_string(crm_time_t * date_time, int flags);
59 crm_time_t *parse_date(const char *date_str);
60 
61 gboolean check_for_ordinal(const char *str);
62 
63 static crm_time_t *
64 crm_get_utc_time(crm_time_t * dt)
65 {
66  crm_time_t *utc = calloc(1, sizeof(crm_time_t));
67 
68  utc->years = dt->years;
69  utc->days = dt->days;
70  utc->seconds = dt->seconds;
71  utc->offset = 0;
72 
73  if (dt->offset) {
74  crm_time_add_seconds(utc, -dt->offset);
75  } else {
76  /* Durations (which are the only things that can include months, never have a timezone */
77  utc->months = dt->months;
78  }
79 
80  crm_time_log(LOG_TRACE, "utc-source", dt,
82  crm_time_log(LOG_TRACE, "utc-target", utc,
84  return utc;
85 }
86 
87 crm_time_t *
88 crm_time_new(const char *date_time)
89 {
90  time_t tm_now;
91  crm_time_t *dt = NULL;
92 
93  tzset();
94  if (date_time == NULL) {
95  tm_now = time(NULL);
96  dt = calloc(1, sizeof(crm_time_t));
97  crm_time_set_timet(dt, &tm_now);
98  } else {
99  dt = parse_date(date_time);
100  }
101  return dt;
102 }
103 
104 void
106 {
107  if (dt == NULL) {
108  return;
109  }
110  free(dt);
111 }
112 
113 static int
114 year_days(int year)
115 {
116  int d = 365;
117 
118  if (crm_time_leapyear(year)) {
119  d++;
120  }
121  return d;
122 }
123 
124 /* http://www.personal.ecu.edu/mccartyr/ISOwdALG.txt
125  *
126  * 5. Find the Jan1Weekday for Y (Monday=1, Sunday=7)
127  * YY = (Y-1) % 100
128  * C = (Y-1) - YY
129  * G = YY + YY/4
130  * Jan1Weekday = 1 + (((((C / 100) % 4) x 5) + G) % 7)
131  */
132 int
134 {
135  int YY = (year - 1) % 100;
136  int C = (year - 1) - YY;
137  int G = YY + YY / 4;
138  int jan1 = 1 + (((((C / 100) % 4) * 5) + G) % 7);
139 
140  crm_trace("YY=%d, C=%d, G=%d", YY, C, G);
141  crm_trace("January 1 %.4d: %d", year, jan1);
142  return jan1;
143 }
144 
145 int
147 {
148  int weeks = 52;
149  int jan1 = crm_time_january1_weekday(year);
150 
151  /* if jan1 == thursday */
152  if (jan1 == 4) {
153  weeks++;
154  } else {
155  jan1 = crm_time_january1_weekday(year + 1);
156  /* if dec31 == thursday aka. jan1 of next year is a friday */
157  if (jan1 == 5) {
158  weeks++;
159  }
160 
161  }
162  return weeks;
163 }
164 
165 int month_days[14] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 29 };
166 
167 int
168 crm_time_days_in_month(int month, int year)
169 {
170  if (month == 2 && crm_time_leapyear(year)) {
171  month = 13;
172  }
173  return month_days[month];
174 }
175 
176 bool
178 {
179  gboolean is_leap = FALSE;
180 
181  if (year % 4 == 0) {
182  is_leap = TRUE;
183  }
184  if (year % 100 == 0 && year % 400 != 0) {
185  is_leap = FALSE;
186  }
187  return is_leap;
188 }
189 
190 static uint32_t
191 get_ordinal_days(uint32_t y, uint32_t m, uint32_t d)
192 {
193  int lpc;
194 
195  for (lpc = 1; lpc < m; lpc++) {
196  d += crm_time_days_in_month(lpc, y);
197  }
198  return d;
199 }
200 
201 void
202 crm_time_log_alias(int log_level, const char *file, const char *function, int line,
203  const char *prefix, crm_time_t * date_time, int flags)
204 {
205  char *date_s = crm_time_as_string(date_time, flags);
206 
207  if (log_level < LOG_CRIT) {
208  printf("%s%s%s\n",
209  prefix ? prefix : "", prefix ? ": " : "", date_s ? date_s : "__invalid_date__");
210  } else {
211  do_crm_log_alias(log_level, file, function, line, "%s%s%s",
212  prefix ? prefix : "", prefix ? ": " : "",
213  date_s ? date_s : "__invalid_date__");
214  }
215  free(date_s);
216 }
217 
218 static int
219 crm_time_get_sec(int sec, uint * h, uint * m, uint * s)
220 {
221  uint hours, minutes, seconds;
222 
223  if (sec < 0) {
224  seconds = 0 - sec;
225  } else {
226  seconds = sec;
227  }
228 
229  hours = seconds / (60 * 60);
230  seconds -= 60 * 60 * hours;
231 
232  minutes = seconds / (60);
233  seconds -= 60 * minutes;
234 
235  crm_trace("%d == %.2d:%.2d:%.2d", sec, hours, minutes, seconds);
236 
237  *h = hours;
238  *m = minutes;
239  *s = seconds;
240 
241  return TRUE;
242 }
243 
244 int
245 crm_time_get_timeofday(crm_time_t * dt, uint * h, uint * m, uint * s)
246 {
247  return crm_time_get_sec(dt->seconds, h, m, s);
248 }
249 
250 int
251 crm_time_get_timezone(crm_time_t * dt, uint * h, uint * m)
252 {
253  uint s;
254 
255  return crm_time_get_sec(dt->seconds, h, m, &s);
256 }
257 
258 long long
260 {
261  int lpc;
262  crm_time_t *utc = NULL;
263  long long in_seconds = 0;
264 
265  utc = crm_get_utc_time(dt);
266 
267  for (lpc = 1; lpc < utc->years; lpc++) {
268  int dmax = year_days(lpc);
269 
270  in_seconds += 60 * 60 * 24 * dmax;
271  }
272 
273  /* utc->months is an offset that can only be set for a duration
274  * By definiton, the value is variable depending on the date to
275  * which it is applied
276  *
277  * Force 30-day months so that something vaguely sane happens
278  * for anyone that tries to use a month in this way
279  */
280  if (utc->months > 0) {
281  in_seconds += 60 * 60 * 24 * 30 * utc->months;
282  }
283 
284  if (utc->days > 0) {
285  in_seconds += 60 * 60 * 24 * (utc->days - 1);
286  }
287  in_seconds += utc->seconds;
288 
289  crm_time_free(utc);
290  return in_seconds;
291 }
292 
293 #define EPOCH_SECONDS 62135596800ULL /* Calculated using crm_time_get_seconds() */
294 long long
296 {
297  return crm_time_get_seconds(dt) - EPOCH_SECONDS;
298 }
299 
300 int
301 crm_time_get_gregorian(crm_time_t * dt, uint * y, uint * m, uint * d)
302 {
303  int months = 0;
304  int days = dt->days;
305 
306  if(dt->years != 0) {
307  for (months = 1; months <= 12 && days > 0; months++) {
308  int mdays = crm_time_days_in_month(months, dt->years);
309 
310  if (mdays >= days) {
311  break;
312  } else {
313  days -= mdays;
314  }
315  }
316 
317  } else if (dt->months) {
318  /* This is a duration including months, don't convert the days field */
319  months = dt->months;
320 
321  } else {
322  /* This is a duration not including months, still don't convert the days field */
323  }
324 
325  *y = dt->years;
326  *m = months;
327  *d = days;
328  crm_trace("%.4d-%.3d -> %.4d-%.2d-%.2d", dt->years, dt->days, dt->years, months, days);
329  return TRUE;
330 }
331 
332 int
333 crm_time_get_ordinal(crm_time_t * dt, uint * y, uint * d)
334 {
335  *y = dt->years;
336  *d = dt->days;
337  return TRUE;
338 }
339 
340 int
341 crm_time_get_isoweek(crm_time_t * dt, uint * y, uint * w, uint * d)
342 {
343  /*
344  * Monday 29 December 2008 is written "2009-W01-1"
345  * Sunday 3 January 2010 is written "2009-W53-7"
346  */
347  int year_num = 0;
348  int jan1 = crm_time_january1_weekday(dt->years);
349  int h = -1;
350 
351  CRM_CHECK(dt->days > 0, return FALSE);
352 
353 /* 6. Find the Weekday for Y M D */
354  h = dt->days + jan1 - 1;
355  *d = 1 + ((h - 1) % 7);
356 
357 /* 7. Find if Y M D falls in YearNumber Y-1, WeekNumber 52 or 53 */
358  if (dt->days <= (8 - jan1) && jan1 > 4) {
359  crm_trace("year--, jan1=%d", jan1);
360  year_num = dt->years - 1;
361  *w = crm_time_weeks_in_year(year_num);
362 
363  } else {
364  year_num = dt->years;
365  }
366 
367 /* 8. Find if Y M D falls in YearNumber Y+1, WeekNumber 1 */
368  if (year_num == dt->years) {
369  int dmax = year_days(year_num);
370  int correction = 4 - *d;
371 
372  if ((dmax - dt->days) < correction) {
373  crm_trace("year++, jan1=%d, i=%d vs. %d", jan1, dmax - dt->days, correction);
374  year_num = dt->years + 1;
375  *w = 1;
376  }
377  }
378 
379 /* 9. Find if Y M D falls in YearNumber Y, WeekNumber 1 through 53 */
380  if (year_num == dt->years) {
381  int j = dt->days + (7 - *d) + (jan1 - 1);
382 
383  *w = j / 7;
384  if (jan1 > 4) {
385  *w -= 1;
386  }
387  }
388 
389  *y = year_num;
390  crm_trace("Converted %.4d-%.3d to %.4d-W%.2d-%d", dt->years, dt->days, *y, *w, *d);
391  return TRUE;
392 }
393 
394 #define DATE_MAX 128
395 
396 char *
398 {
399  char *date_s = NULL;
400  char *time_s = NULL;
401  char *offset_s = NULL;
402  char *result_s = NULL;
403  crm_time_t *dt = NULL;
404  crm_time_t *utc = NULL;
405 
406  if (date_time == NULL) {
407  return strdup("");
408 
409  } else if (date_time->offset && (flags & crm_time_log_with_timezone) == 0) {
410  crm_trace("UTC conversion");
411  utc = crm_get_utc_time(date_time);
412  dt = utc;
413  } else {
414  dt = date_time;
415  }
416 
417  CRM_CHECK(dt != NULL, return NULL);
419  uint h = 0, m = 0, s = 0;
420  int offset = 0;
421 
422  date_s = calloc(1, DATE_MAX);
423  crm_time_get_sec(dt->seconds, &h, &m, &s);
424 
425  if (date_s == NULL) {
426  goto done;
427  }
428 
429  if(dt->years) {
430  offset += snprintf(date_s+offset, DATE_MAX - offset, "%4d year%s ", dt->years, dt->years>1?"s":"");
431  }
432  if(dt->months) {
433  offset += snprintf(date_s+offset, DATE_MAX - offset, "%2d month%s ", dt->months, dt->months>1?"s":"");
434  }
435  if(dt->days) {
436  offset += snprintf(date_s+offset, DATE_MAX - offset, "%2d day%s ", dt->days, dt->days>1?"s":"");
437  }
438  if(dt->seconds) {
439  offset += snprintf(date_s+offset, DATE_MAX - offset, "%d seconds ( ", dt->seconds);
440  if(h) {
441  offset += snprintf(date_s+offset, DATE_MAX - offset, "%u hour%s ", h, h>1?"s":"");
442  }
443  if(m) {
444  offset += snprintf(date_s+offset, DATE_MAX - offset, "%u minute%s ", m, m>1?"s":"");
445  }
446  if(s) {
447  offset += snprintf(date_s+offset, DATE_MAX - offset, "%u second%s ", s, s>1?"s":"");
448  }
449  offset += snprintf(date_s+offset, DATE_MAX - offset, ")");
450  }
451  goto done;
452  }
453 
454  if (flags & crm_time_log_date) {
455  date_s = calloc(1, 34);
456  if (date_s == NULL) {
457  goto done;
458 
459  } else if (flags & crm_time_seconds) {
460  long long s = crm_time_get_seconds(date_time);
461 
462  snprintf(date_s, 32, "%lld", s);
463  goto done;
464 
465  } else if (flags & crm_time_epoch) {
466  long long s = crm_time_get_seconds_since_epoch(date_time);
467 
468  snprintf(date_s, 32, "%lld", s);
469  goto done;
470 
471  } else if (flags & crm_time_weeks) {
472  /* YYYY-Www-D */
473  uint y, w, d;
474 
475  if (crm_time_get_isoweek(dt, &y, &w, &d)) {
476  snprintf(date_s, 34, "%u-W%.2u-%u", y, w, d);
477  }
478 
479  } else if (flags & crm_time_ordinal) {
480  /* YYYY-DDD */
481  uint y, d;
482 
483  if (crm_time_get_ordinal(dt, &y, &d)) {
484  snprintf(date_s, 22, "%u-%.3u", y, d);
485  }
486 
487  } else {
488  /* YYYY-MM-DD */
489  uint y, m, d;
490 
491  if (crm_time_get_gregorian(dt, &y, &m, &d)) {
492  snprintf(date_s, 33, "%.4u-%.2u-%.2u", y, m, d);
493  }
494  }
495  }
496 
498  uint h, m, s;
499 
500  time_s = calloc(1, 33);
501  if (time_s == NULL) {
502  goto cleanup;
503  }
504 
505  if (crm_time_get_timeofday(dt, &h, &m, &s)) {
506  snprintf(time_s, 33, "%.2u:%.2u:%.2u", h, m, s);
507  }
508 
509  if (dt->offset != 0) {
510  crm_time_get_sec(dt->offset, &h, &m, &s);
511  }
512 
513  offset_s = calloc(1, 31);
514  if ((flags & crm_time_log_with_timezone) == 0 || dt->offset == 0) {
515  crm_trace("flags %6x %6x", flags, crm_time_log_with_timezone);
516  snprintf(offset_s, 31, "Z");
517 
518  } else {
519  snprintf(offset_s, 24, " %c%.2u:%.2u", dt->offset < 0 ? '-' : '+', h, m);
520  }
521  }
522 
523  done:
524  result_s = calloc(1, 100);
525 
526  snprintf(result_s, 100, "%s%s%s%s",
527  date_s ? date_s : "", (date_s != NULL && time_s != NULL) ? " " : "",
528  time_s ? time_s : "", offset_s ? offset_s : "");
529 
530  cleanup:
531  free(date_s);
532  free(time_s);
533  free(offset_s);
534  crm_time_free(utc);
535 
536  return result_s;
537 }
538 
539 static int
540 crm_time_parse_sec(const char *time_str)
541 {
542  int rc;
543  uint hour = 0;
544  uint minute = 0;
545  uint second = 0;
546 
547  rc = sscanf(time_str, "%d:%d:%d", &hour, &minute, &second);
548  if (rc == 1) {
549  rc = sscanf(time_str, "%2d%2d%2d", &hour, &minute, &second);
550  }
551 
552  if (rc > 0 && rc < 4) {
553  crm_trace("Got valid time: %.2d:%.2d:%.2d", hour, minute, second);
554  if (hour >= 24) {
555  crm_err("Invalid hour: %d", hour);
556  } else if (minute >= 60) {
557  crm_err("Invalid minute: %d", minute);
558  } else if (second >= 60) {
559  crm_err("Invalid second: %d", second);
560  } else {
561  second += (minute * 60);
562  second += (hour * 60 * 60);
563  }
564  } else {
565  crm_err("Bad time: %s (%d)", time_str, rc);
566  }
567  return second;
568 }
569 
570 static int
571 crm_time_parse_offset(const char *offset_str)
572 {
573  int offset = 0;
574 
575  tzset();
576  if (offset_str == NULL) {
577 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
578  time_t now = time(NULL);
579  struct tm *now_tm = localtime(&now);
580 #endif
581  int h_offset = GMTOFF(now_tm) / (3600);
582  int m_offset = (GMTOFF(now_tm) - (3600 * h_offset)) / (60);
583 
584  if (h_offset < 0 && m_offset < 0) {
585  m_offset = 0 - m_offset;
586  }
587  offset += (60 * 60 * h_offset);
588  offset += (60 * m_offset);
589 
590  } else if (offset_str[0] == 'Z') {
591 
592  } else if (offset_str[0] == '+' || offset_str[0] == '-' || isdigit((int)offset_str[0])) {
593  gboolean negate = FALSE;
594 
595  if (offset_str[0] == '-') {
596  negate = TRUE;
597  offset_str++;
598  }
599  offset = crm_time_parse_sec(offset_str);
600  if (negate) {
601  offset = 0 - offset;
602  }
603  }
604  return offset;
605 }
606 
607 static crm_time_t *
608 crm_time_parse(const char *time_str, crm_time_t * a_time)
609 {
610  uint h, m, s;
611  char *offset_s = NULL;
612  crm_time_t *dt = a_time;
613 
614  tzset();
615  if (a_time == NULL) {
616  dt = calloc(1, sizeof(crm_time_t));
617  }
618 
619  if (time_str) {
620  dt->seconds = crm_time_parse_sec(time_str);
621 
622  offset_s = strstr(time_str, "Z");
623  if (offset_s == NULL) {
624  offset_s = strstr(time_str, " ");
625  }
626  }
627 
628  if (offset_s) {
629  while (isspace(offset_s[0])) {
630  offset_s++;
631  }
632  }
633  dt->offset = crm_time_parse_offset(offset_s);
634  crm_time_get_sec(dt->offset, &h, &m, &s);
635  crm_trace("Got tz: %c%2.d:%.2d", dt->offset < 0 ? '-' : '+', h, m);
636  return dt;
637 }
638 
639 crm_time_t *
640 parse_date(const char *date_str)
641 {
642  char *time_s;
643  crm_time_t *dt = NULL;
644 
645  int year = 0;
646  int month = 0;
647  int week = 0;
648  int day = 0;
649  int rc = 0;
650 
651  CRM_CHECK(date_str != NULL, return NULL);
652  CRM_CHECK(strlen(date_str) > 0, return NULL);
653 
654  if (date_str[0] == 'T' || date_str[2] == ':') {
655  /* Just a time supplied - Infer current date */
656  dt = crm_time_new(NULL);
657  dt = crm_time_parse(date_str, dt);
658  goto done;
659 
660  } else {
661  dt = calloc(1, sizeof(crm_time_t));
662  }
663 
664  if (safe_str_eq("epoch", date_str)) {
665  dt->days = 1;
666  dt->years = 1970;
668  return dt;
669  }
670 
671  /* YYYY-MM-DD */
672  rc = sscanf(date_str, "%d-%d-%d", &year, &month, &day);
673  if (rc == 1) {
674  /* YYYYMMDD */
675  rc = sscanf(date_str, "%4d%2d%2d", &year, &month, &day);
676  }
677  if (rc == 3) {
678  if (month > 12) {
679  crm_err("Invalid month: %d", month);
680  } else if (day > 31) {
681  crm_err("Invalid day: %d", day);
682  } else {
683  dt->years = year;
684  dt->days = get_ordinal_days(year, month, day);
685  crm_trace("Got gergorian date: %.4d-%.3d", year, dt->days);
686  }
687  goto done;
688  }
689 
690  /* YYYY-DDD */
691  rc = sscanf(date_str, "%d-%d", &year, &day);
692  if (rc == 2) {
693  crm_trace("Got ordinal date");
694  if (day > year_days(year)) {
695  crm_err("Invalid day: %d (max=%d)", day, year_days(year));
696  } else {
697  dt->days = day;
698  dt->years = year;
699  }
700  goto done;
701  }
702 
703  /* YYYY-Www-D */
704  rc = sscanf(date_str, "%d-W%d-%d", &year, &week, &day);
705  if (rc == 3) {
706  crm_trace("Got week date");
707  if (week > crm_time_weeks_in_year(year)) {
708  crm_err("Invalid week: %d (max=%d)", week, crm_time_weeks_in_year(year));
709  } else if (day < 1 || day > 7) {
710  crm_err("Invalid day: %d", day);
711  } else {
712  /*
713  * http://en.wikipedia.org/wiki/ISO_week_date
714  *
715  * Monday 29 December 2008 is written "2009-W01-1"
716  * Sunday 3 January 2010 is written "2009-W53-7"
717  *
718  * Saturday 27 September 2008 is written "2008-W37-6"
719  *
720  * http://en.wikipedia.org/wiki/ISO_week_date
721  * If 1 January is on a Monday, Tuesday, Wednesday or Thursday, it is in week 01.
722  * If 1 January is on a Friday, Saturday or Sunday, it is in week 52 or 53 of the previous year.
723  */
724  int jan1 = crm_time_january1_weekday(year);
725 
726  crm_trace("Jan 1 = %d", jan1);
727 
728  dt->years = year;
729  crm_time_add_days(dt, (week - 1) * 7);
730 
731  if (jan1 <= 4) {
732  crm_time_add_days(dt, 1 - jan1);
733  } else {
734  crm_time_add_days(dt, 8 - jan1);
735  }
736 
737  crm_time_add_days(dt, day);
738  }
739  goto done;
740  }
741 
742  crm_err("Couldn't parse %s", date_str);
743  done:
744 
745  time_s = strstr(date_str, " ");
746  if (time_s == NULL) {
747  time_s = strstr(date_str, "T");
748  }
749 
750  if (dt && time_s) {
751  time_s++;
752  crm_time_parse(time_s, dt);
753  }
754 
756 
757  CRM_CHECK(crm_time_check(dt), return NULL);
758 
759  return dt;
760 }
761 
762 static int
763 parse_int(const char *str, int field_width, int uppper_bound, int *result)
764 {
765  int lpc = 0;
766  int offset = 0;
767  int intermediate = 0;
768  gboolean fraction = FALSE;
769  gboolean negate = FALSE;
770 
771  CRM_CHECK(str != NULL, return FALSE);
772  CRM_CHECK(result != NULL, return FALSE);
773 
774  *result = 0;
775 
776  if (*str == '\0') {
777  return FALSE;
778  }
779 
780  if (str[offset] == 'T') {
781  offset++;
782  }
783 
784  if (str[offset] == '.' || str[offset] == ',') {
785  fraction = TRUE;
786  field_width = -1;
787  offset++;
788  } else if (str[offset] == '-') {
789  negate = TRUE;
790  offset++;
791  } else if (str[offset] == '+' || str[offset] == ':') {
792  offset++;
793  }
794 
795  for (; (fraction || lpc < field_width) && isdigit((int)str[offset]); lpc++) {
796  if (fraction) {
797  intermediate = (str[offset] - '0') / (10 ^ lpc);
798  } else {
799  *result *= 10;
800  intermediate = str[offset] - '0';
801  }
802  *result += intermediate;
803  offset++;
804  }
805  if (fraction) {
806  *result = (int)(*result * uppper_bound);
807 
808  } else if (uppper_bound > 0 && *result > uppper_bound) {
809  *result = uppper_bound;
810  }
811  if (negate) {
812  *result = 0 - *result;
813  }
814  if (lpc > 0) {
815  crm_trace("Found int: %d. Stopped at str[%d]='%c'", *result, lpc, str[lpc]);
816  return offset;
817  }
818  return 0;
819 }
820 
821 crm_time_t *
822 crm_time_parse_duration(const char *period_s)
823 {
824  gboolean is_time = FALSE;
825  crm_time_t *diff = NULL;
826 
827  CRM_CHECK(period_s != NULL, goto bail);
828  CRM_CHECK(strlen(period_s) > 0, goto bail);
829  CRM_CHECK(period_s[0] == 'P', goto bail);
830  period_s++;
831 
832  diff = calloc(1, sizeof(crm_time_t));
833 
834  while (isspace((int)period_s[0]) == FALSE) {
835  int an_int = 0, rc;
836  char ch = 0;
837 
838  if (period_s[0] == 'T') {
839  is_time = TRUE;
840  period_s++;
841  }
842 
843  rc = parse_int(period_s, 10, 0, &an_int);
844  if (rc == 0) {
845  break;
846  }
847  period_s += rc;
848 
849  ch = period_s[0];
850  period_s++;
851 
852  crm_trace("Testing %c=%d, rc=%d", ch, an_int, rc);
853 
854  switch (ch) {
855  case 0:
856  return diff;
857  break;
858  case 'Y':
859  diff->years = an_int;
860  break;
861  case 'M':
862  if (is_time) {
863  /* Minutes */
864  diff->seconds += an_int * 60;
865  } else {
866  diff->months = an_int;
867  }
868  break;
869  case 'W':
870  diff->days += an_int * 7;
871  break;
872  case 'D':
873  diff->days += an_int;
874  break;
875  case 'H':
876  diff->seconds += an_int * 60 * 60;
877  break;
878  case 'S':
879  diff->seconds += an_int;
880  break;
881  default:
882  goto bail;
883  break;
884  }
885  }
886  return diff;
887 
888  bail:
889  free(diff);
890  return NULL;
891 }
892 
894 crm_time_parse_period(const char *period_str)
895 {
896  gboolean invalid = FALSE;
897  const char *original = period_str;
898  crm_time_period_t *period = NULL;
899 
900  CRM_CHECK(period_str != NULL, return NULL);
901  CRM_CHECK(strlen(period_str) > 0, return NULL);
902 
903  tzset();
904  period = calloc(1, sizeof(crm_time_period_t));
905 
906  if (period_str[0] == 'P') {
907  period->diff = crm_time_parse_duration(period_str);
908  } else {
909  period->start = parse_date(period_str);
910  }
911 
912  period_str = strstr(original, "/");
913  if (period_str) {
914  CRM_CHECK(period_str[0] == '/', invalid = TRUE;
915  goto bail);
916  period_str++;
917 
918  if (period_str[0] == 'P') {
919  period->diff = crm_time_parse_duration(period_str);
920  } else {
921  period->end = parse_date(period_str);
922  }
923 
924  } else if (period->diff != NULL) {
925  /* just aduration starting from now */
926  period->start = crm_time_new(NULL);
927 
928  } else {
929  invalid = TRUE;
930  CRM_CHECK(period_str != NULL, goto bail);
931  }
932 
933  /* sanity checks */
934  if (period->start == NULL && period->end == NULL) {
935  crm_err("Invalid time period: %s", original);
936  invalid = TRUE;
937 
938  } else if (period->start == NULL && period->diff == NULL) {
939  crm_err("Invalid time period: %s", original);
940  invalid = TRUE;
941 
942  } else if (period->end == NULL && period->diff == NULL) {
943  crm_err("Invalid time period: %s", original);
944  invalid = TRUE;
945  }
946 
947  bail:
948  if (invalid) {
949  free(period->start);
950  free(period->end);
951  free(period->diff);
952  free(period);
953  return NULL;
954  }
955  if (period->end == NULL && period->diff == NULL) {
956  }
957 
958  if (period->start == NULL) {
959  period->start = crm_time_subtract(period->end, period->diff);
960 
961  } else if (period->end == NULL) {
962  period->end = crm_time_add(period->start, period->diff);
963  }
964 
965  crm_time_check(period->start);
966  crm_time_check(period->end);
967 
968  return period;
969 }
970 
971 void
972 crm_time_set(crm_time_t * target, crm_time_t * source)
973 {
974  crm_trace("target=%p, source=%p", target, source);
975 
976  CRM_CHECK(target != NULL && source != NULL, return);
977 
978  target->years = source->years;
979  target->days = source->days;
980  target->months = source->months; /* Only for durations */
981  target->seconds = source->seconds;
982  target->offset = source->offset;
983 
984  crm_time_log(LOG_TRACE, "source", source,
986  crm_time_log(LOG_TRACE, "target", target,
988 }
989 
990 static void
991 ha_set_tm_time(crm_time_t * target, struct tm *source)
992 {
993  int h_offset = 0;
994  int m_offset = 0;
995 
996  /* Ensure target is fully initialized */
997  target->years = 0;
998  target->months = 0;
999  target->days = 0;
1000  target->seconds = 0;
1001  target->offset = 0;
1002  target->duration = FALSE;
1003 
1004  if (source->tm_year > 0) {
1005  /* years since 1900 */
1006  target->years = 1900 + source->tm_year;
1007  }
1008 
1009  if (source->tm_yday >= 0) {
1010  /* days since January 1 [0-365] */
1011  target->days = 1 + source->tm_yday;
1012  }
1013 
1014  if (source->tm_hour >= 0) {
1015  target->seconds += 60 * 60 * source->tm_hour;
1016  }
1017  if (source->tm_min >= 0) {
1018  target->seconds += 60 * source->tm_min;
1019  }
1020  if (source->tm_sec >= 0) {
1021  target->seconds += source->tm_sec;
1022  }
1023 
1024  /* tm_gmtoff == offset from UTC in seconds */
1025  h_offset = GMTOFF(source) / (3600);
1026  m_offset = (GMTOFF(source) - (3600 * h_offset)) / (60);
1027  crm_trace("Offset (s): %ld, offset (hh:mm): %.2d:%.2d", GMTOFF(source), h_offset, m_offset);
1028 
1029  target->offset += 60 * 60 * h_offset;
1030  target->offset += 60 * m_offset;
1031 }
1032 
1033 void
1034 crm_time_set_timet(crm_time_t * target, time_t * source)
1035 {
1036  ha_set_tm_time(target, localtime(source));
1037 }
1038 
1039 crm_time_t *
1041 {
1042  crm_time_t *utc = NULL;
1043  crm_time_t *answer = NULL;
1044 
1045  CRM_CHECK(dt != NULL && value != NULL, return NULL);
1046 
1047  answer = calloc(1, sizeof(crm_time_t));
1048  crm_time_set(answer, dt);
1049 
1050  utc = crm_get_utc_time(value);
1051 
1052  answer->years += utc->years;
1053  crm_time_add_months(answer, utc->months);
1054  crm_time_add_days(answer, utc->days);
1055  crm_time_add_seconds(answer, utc->seconds);
1056 
1057  crm_time_free(utc);
1058  return answer;
1059 }
1060 
1061 crm_time_t *
1063 {
1064  crm_time_t *utc = NULL;
1065  crm_time_t *answer = NULL;
1066 
1067  CRM_CHECK(dt != NULL && value != NULL, return NULL);
1068 
1069  utc = crm_get_utc_time(value);
1070  answer = crm_get_utc_time(dt);
1071  answer->duration = TRUE;
1072 
1073  answer->years -= utc->years;
1074  if(utc->months != 0) {
1075  crm_time_add_months(answer, -utc->months);
1076  }
1077  crm_time_add_days(answer, -utc->days);
1078  crm_time_add_seconds(answer, -utc->seconds);
1079 
1080  crm_time_free(utc);
1081  return answer;
1082 }
1083 
1084 crm_time_t *
1086 {
1087  crm_time_t *utc = NULL;
1088  crm_time_t *answer = NULL;
1089 
1090  CRM_CHECK(dt != NULL && value != NULL, return NULL);
1091 
1092  answer = calloc(1, sizeof(crm_time_t));
1093  crm_time_set(answer, dt);
1094  utc = crm_get_utc_time(value);
1095 
1096  answer->years -= utc->years;
1097  if(utc->months != 0) {
1098  crm_time_add_months(answer, -utc->months);
1099  }
1100  crm_time_add_days(answer, -utc->days);
1101  crm_time_add_seconds(answer, -utc->seconds);
1102 
1103  return answer;
1104 }
1105 
1106 bool
1108 {
1109  int ydays = 0;
1110 
1111  CRM_CHECK(dt != NULL, return FALSE);
1112 
1113  ydays = year_days(dt->years);
1114  crm_trace("max ydays: %d", ydays);
1115 
1116  CRM_CHECK(dt->days > 0, return FALSE);
1117  CRM_CHECK(dt->days <= ydays, return FALSE);
1118 
1119  CRM_CHECK(dt->seconds >= 0, return FALSE);
1120  CRM_CHECK(dt->seconds < 24 * 60 * 60, return FALSE);
1121 
1122  return TRUE;
1123 }
1124 
1125 #define do_cmp_field(l, r, field) \
1126  if(rc == 0) { \
1127  if(l->field > r->field) { \
1128  crm_trace("%s: %d > %d", \
1129  #field, l->field, r->field); \
1130  rc = 1; \
1131  } else if(l->field < r->field) { \
1132  crm_trace("%s: %d < %d", \
1133  #field, l->field, r->field); \
1134  rc = -1; \
1135  } \
1136  }
1137 
1138 int
1140 {
1141  int rc = 0;
1142  crm_time_t *t1 = NULL;
1143  crm_time_t *t2 = NULL;
1144 
1145  if (a == NULL && b == NULL) {
1146  return 0;
1147  } else if (a == NULL) {
1148  return -1;
1149  } else if (b == NULL) {
1150  return 1;
1151  }
1152 
1153  t1 = crm_get_utc_time(a);
1154  t2 = crm_get_utc_time(b);
1155 
1156  do_cmp_field(t1, t2, years);
1157  do_cmp_field(t1, t2, days);
1158  do_cmp_field(t1, t2, seconds);
1159 
1160  crm_time_free(t1);
1161  crm_time_free(t2);
1162  return rc;
1163 }
1164 
1165 void
1166 crm_time_add_seconds(crm_time_t * a_time, int extra)
1167 {
1168  int days = 0;
1169  int seconds = 24 * 60 * 60;
1170 
1171  crm_trace("Adding %d seconds to %d (max=%d)", extra, a_time->seconds, seconds);
1172 
1173  a_time->seconds += extra;
1174  while (a_time->seconds >= seconds) {
1175  a_time->seconds -= seconds;
1176  days++;
1177  }
1178 
1179  while (a_time->seconds < 0) {
1180  a_time->seconds += seconds;
1181  days--;
1182  }
1183  crm_time_add_days(a_time, days);
1184 }
1185 
1186 void
1187 crm_time_add_days(crm_time_t * a_time, int extra)
1188 {
1189  int lower_bound = 1;
1190  int ydays = crm_time_leapyear(a_time->years) ? 366 : 365;
1191 
1192  crm_trace("Adding %d days to %.4d-%.3d", extra, a_time->years, a_time->days);
1193 
1194  a_time->days += extra;
1195  while (a_time->days > ydays) {
1196  a_time->years++;
1197  a_time->days -= ydays;
1198  ydays = crm_time_leapyear(a_time->years) ? 366 : 365;
1199  }
1200 
1201  if(a_time->duration) {
1202  lower_bound = 0;
1203  }
1204 
1205  while (a_time->days < lower_bound) {
1206  a_time->years--;
1207  a_time->days += crm_time_leapyear(a_time->years) ? 366 : 365;
1208  }
1209 }
1210 
1211 void
1212 crm_time_add_months(crm_time_t * a_time, int extra)
1213 {
1214  int lpc;
1215  uint32_t y, m, d, dmax;
1216 
1217  crm_time_get_gregorian(a_time, &y, &m, &d);
1218  crm_trace("Adding %d months to %.4d-%.2d-%.2d", extra, y, m, d);
1219 
1220  if (extra > 0) {
1221  for (lpc = extra; lpc > 0; lpc--) {
1222  m++;
1223  if (m == 13) {
1224  m = 1;
1225  y++;
1226  }
1227  }
1228  } else {
1229  for (lpc = -extra; lpc > 0; lpc--) {
1230  m--;
1231  if (m == 0) {
1232  m = 12;
1233  y--;
1234  }
1235  }
1236  }
1237 
1238  dmax = crm_time_days_in_month(m, y);
1239  if (dmax < d) {
1240  /* Preserve day-of-month unless the month doesn't have enough days */
1241  d = dmax;
1242  }
1243 
1244  crm_trace("Calculated %.4d-%.2d-%.2d", y, m, d);
1245 
1246  a_time->years = y;
1247  a_time->days = get_ordinal_days(y, m, d);
1248 
1249  crm_time_get_gregorian(a_time, &y, &m, &d);
1250  crm_trace("Got %.4d-%.2d-%.2d", y, m, d);
1251 }
1252 
1253 void
1254 crm_time_add_minutes(crm_time_t * a_time, int extra)
1255 {
1256  crm_time_add_seconds(a_time, extra * 60);
1257 }
1258 
1259 void
1260 crm_time_add_hours(crm_time_t * a_time, int extra)
1261 {
1262  crm_time_add_seconds(a_time, extra * 60 * 60);
1263 }
1264 
1265 void
1266 crm_time_add_weeks(crm_time_t * a_time, int extra)
1267 {
1268  crm_time_add_days(a_time, extra * 7);
1269 }
1270 
1271 void
1272 crm_time_add_years(crm_time_t * a_time, int extra)
1273 {
1274  a_time->years += extra;
1275 }
1276 
1277 static void
1278 ha_get_tm_time( struct tm *target, crm_time_t *source)
1279 {
1280  *target = (struct tm) {
1281  .tm_year = source->years - 1900,
1282  .tm_mday = source->days,
1283  .tm_sec = source->seconds % 60,
1284  .tm_min = ( source->seconds / 60 ) % 60,
1285  .tm_hour = source->seconds / 60 / 60,
1286  .tm_isdst = -1, /* don't adjust */
1287 
1288 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
1289  .tm_gmtoff = source->offset
1290 #endif
1291  };
1292  mktime(target);
1293 }
1294 
1295 crm_time_hr_t *
1297 {
1298  crm_time_hr_t *hr_dt = NULL;
1299 
1300  if (dt) {
1301  hr_dt = target?target:calloc(1, sizeof(crm_time_hr_t));
1302  if (hr_dt) {
1303  *hr_dt = (crm_time_hr_t) {
1304  .years = dt->years,
1305  .months = dt->months,
1306  .days = dt->days,
1307  .seconds = dt->seconds,
1308  .offset = dt->offset,
1309  .duration = dt->duration
1310  };
1311  }
1312  }
1313 
1314  return hr_dt;
1315 }
1316 
1317 void
1319 {
1320  CRM_ASSERT((hr_dt) && (target));
1321  *target = (crm_time_t) {
1322  .years = hr_dt->years,
1323  .months = hr_dt->months,
1324  .days = hr_dt->days,
1325  .seconds = hr_dt->seconds,
1326  .offset = hr_dt->offset,
1327  .duration = hr_dt->duration
1328  };
1329 }
1330 
1331 crm_time_hr_t *
1332 crm_time_timeval_hr_convert(crm_time_hr_t *target, struct timeval *tv)
1333 {
1334  crm_time_t dt;
1335  crm_time_hr_t *ret;
1336 
1337  crm_time_set_timet(&dt, &tv->tv_sec);
1338  ret = crm_time_hr_convert(target, &dt);
1339  if (ret) {
1340  ret->useconds = tv->tv_usec;
1341  }
1342  return ret;
1343 }
1344 
1345 crm_time_hr_t *
1346 crm_time_hr_new(const char *date_time)
1347 {
1348  crm_time_hr_t *hr_dt = NULL;
1349  struct timeval tv_now;
1350 
1351  if (!date_time) {
1352  if (gettimeofday(&tv_now, NULL) == 0) {
1353  hr_dt = crm_time_timeval_hr_convert(NULL, &tv_now);
1354  }
1355  } else {
1356  crm_time_t *dt;
1357 
1358  dt = parse_date(date_time);
1359  hr_dt = crm_time_hr_convert(NULL, dt);
1360  crm_time_free(dt);
1361  }
1362  return hr_dt;
1363 }
1364 
1365 void
1367 {
1368  free(hr_dt);
1369 }
1370 
1371 char *
1372 crm_time_format_hr(const char *format, crm_time_hr_t * hr_dt)
1373 {
1374  const char *mark_s;
1375  int max = 128, scanned_pos = 0, printed_pos = 0, fmt_pos = 0,
1376  date_len = 0, nano_digits = 0;
1377  char nano_s[10], date_s[max+1], nanofmt_s[5] = "%", *tmp_fmt_s;
1378  struct tm tm;
1379  crm_time_t dt;
1380 
1381  if (!format) {
1382  return NULL;
1383  }
1384  crm_time_set_hr_dt(&dt, hr_dt);
1385  ha_get_tm_time(&tm, &dt);
1386  sprintf(nano_s, "%06d000", hr_dt->useconds);
1387 
1388  while ((format[scanned_pos]) != '\0') {
1389  mark_s = strchr(&format[scanned_pos], '%');
1390  if (mark_s) {
1391  int fmt_len = 1;
1392 
1393  fmt_pos = mark_s - format;
1394  while ((format[fmt_pos+fmt_len] != '\0') &&
1395  (format[fmt_pos+fmt_len] >= '0') &&
1396  (format[fmt_pos+fmt_len] <= '9')) {
1397  fmt_len++;
1398  }
1399  scanned_pos = fmt_pos + fmt_len + 1;
1400  if (format[fmt_pos+fmt_len] == 'N') {
1401  nano_digits = atoi(&format[fmt_pos+1]);
1402  nano_digits = (nano_digits > 6)?6:nano_digits;
1403  nano_digits = (nano_digits < 0)?0:nano_digits;
1404  sprintf(&nanofmt_s[1], ".%ds", nano_digits);
1405  } else {
1406  if (format[scanned_pos] != '\0') {
1407  continue;
1408  }
1409  fmt_pos = scanned_pos; /* print till end */
1410  }
1411  } else {
1412  scanned_pos = strlen(format);
1413  fmt_pos = scanned_pos; /* print till end */
1414  }
1415  tmp_fmt_s = strndup(&format[printed_pos], fmt_pos - printed_pos);
1416 #ifdef GCC_FORMAT_NONLITERAL_CHECKING_ENABLED
1417 #pragma GCC diagnostic push
1418 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1419 #endif
1420  date_len += strftime(&date_s[date_len], max-date_len, tmp_fmt_s, &tm);
1421 #ifdef GCC_FORMAT_NONLITERAL_CHECKING_ENABLED
1422 #pragma GCC diagnostic pop
1423 #endif
1424  printed_pos = scanned_pos;
1425  free(tmp_fmt_s);
1426  if (nano_digits) {
1427 #ifdef GCC_FORMAT_NONLITERAL_CHECKING_ENABLED
1428 #pragma GCC diagnostic push
1429 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1430 #endif
1431  date_len += snprintf(&date_s[date_len], max-date_len,
1432  nanofmt_s, nano_s);
1433 #ifdef GCC_FORMAT_NONLITERAL_CHECKING_ENABLED
1434 #pragma GCC diagnostic pop
1435 #endif
1436  nano_digits = 0;
1437  }
1438  }
1439 
1440  return (date_len == 0)?NULL:strdup(date_s);
1441 }
crm_time_hr_convert
crm_time_hr_t * crm_time_hr_convert(crm_time_hr_t *target, crm_time_t *dt)
Definition: iso8601.c:1296
crm_time_get_ordinal
int crm_time_get_ordinal(crm_time_t *dt, uint *y, uint *d)
Definition: iso8601.c:333
crm_time_us::years
int years
Definition: iso8601_internal.h:39
crm_time_set_timet
void crm_time_set_timet(crm_time_t *target, time_t *source)
Definition: iso8601.c:1034
crm_time_set_hr_dt
void crm_time_set_hr_dt(crm_time_t *target, crm_time_hr_t *hr_dt)
Definition: iso8601.c:1318
crm_time_period_s::diff
crm_time_t * diff
Definition: iso8601.h:46
do_cmp_field
#define do_cmp_field(l, r, field)
Definition: iso8601.c:1125
DATE_MAX
#define DATE_MAX
Definition: iso8601.c:394
crm_time_free
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:105
crm_time_us::seconds
int seconds
Definition: iso8601_internal.h:42
crm_time_timeval_hr_convert
crm_time_hr_t * crm_time_timeval_hr_convert(crm_time_hr_t *target, struct timeval *tv)
Definition: iso8601.c:1332
flags
uint64_t flags
Definition: remote.c:148
crm_time_add_minutes
void crm_time_add_minutes(crm_time_t *a_time, int extra)
Definition: iso8601.c:1254
crm_time_subtract
crm_time_t * crm_time_subtract(crm_time_t *dt, crm_time_t *value)
Definition: iso8601.c:1085
crm_time_get_timeofday
int crm_time_get_timeofday(crm_time_t *dt, uint *h, uint *m, uint *s)
Definition: iso8601.c:245
LOG_TRACE
#define LOG_TRACE
Definition: logging.h:35
crm_time_set
void crm_time_set(crm_time_t *target, crm_time_t *source)
Definition: iso8601.c:972
crm_time_compare
int crm_time_compare(crm_time_t *a, crm_time_t *b)
Definition: iso8601.c:1139
parse_date
crm_time_t * parse_date(const char *date_str)
Definition: iso8601.c:640
crm_time_log_timeofday
#define crm_time_log_timeofday
Definition: iso8601.h:75
crm_time_us::offset
int offset
Definition: iso8601_internal.h:43
crm_time_us
Definition: iso8601_internal.h:38
CRM_CHECK
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:165
crm_time_add_weeks
void crm_time_add_weeks(crm_time_t *a_time, int extra)
Definition: iso8601.c:1266
crm_time_epoch
#define crm_time_epoch
Definition: iso8601.h:82
crm_time_hr_t
struct crm_time_us crm_time_hr_t
Definition: iso8601_internal.h:26
crm_err
#define crm_err(fmt, args...)
Definition: logging.h:249
crm_time_get_gregorian
int crm_time_get_gregorian(crm_time_t *dt, uint *y, uint *m, uint *d)
Definition: iso8601.c:301
crm_trace
#define crm_trace(fmt, args...)
Definition: logging.h:255
safe_str_eq
#define safe_str_eq(a, b)
Definition: util.h:54
check_for_ordinal
gboolean check_for_ordinal(const char *str)
do_crm_log_alias
#define do_crm_log_alias(level, file, function, line, fmt, args...)
Log a message as if it came from a different code location.
Definition: logging.h:197
crm_time_log_alias
void crm_time_log_alias(int log_level, const char *file, const char *function, int line, const char *prefix, crm_time_t *date_time, int flags)
Definition: iso8601.c:202
crm_time_add_seconds
void crm_time_add_seconds(crm_time_t *a_time, int extra)
Definition: iso8601.c:1166
crm_time_parse_duration
crm_time_t * crm_time_parse_duration(const char *period_s)
Definition: iso8601.c:822
crm_time_get_isoweek
int crm_time_get_isoweek(crm_time_t *dt, uint *y, uint *w, uint *d)
Definition: iso8601.c:341
crm_time_log_duration
#define crm_time_log_duration
Definition: iso8601.h:77
crm_time_period_s
Definition: iso8601.h:43
crm_time_period_s::start
crm_time_t * start
Definition: iso8601.h:44
crm_time_add_days
void crm_time_add_days(crm_time_t *a_time, int extra)
Definition: iso8601.c:1187
crm_time_log_with_timezone
#define crm_time_log_with_timezone
Definition: iso8601.h:76
uint32_t
#define uint32_t
Definition: stdint.in.h:158
crm_time_period_s::end
crm_time_t * end
Definition: iso8601.h:45
GMTOFF
#define GMTOFF(tm)
Definition: iso8601.c:46
crm_time_get_timezone
int crm_time_get_timezone(crm_time_t *dt, uint *h, uint *m)
Definition: iso8601.c:251
crm_time_get_seconds
long long crm_time_get_seconds(crm_time_t *dt)
Definition: iso8601.c:259
crm_time_add_hours
void crm_time_add_hours(crm_time_t *a_time, int extra)
Definition: iso8601.c:1260
crm_time_days_in_month
int crm_time_days_in_month(int month, int year)
Definition: iso8601.c:168
crm_time_us::useconds
int useconds
Definition: iso8601_internal.h:45
crm_time_parse_period
crm_time_period_t * crm_time_parse_period(const char *period_str)
Definition: iso8601.c:894
crm_time_hr_free
void crm_time_hr_free(crm_time_hr_t *hr_dt)
Definition: iso8601.c:1366
iso8601.h
ISO_8601 Date handling.
crm_time_check
bool crm_time_check(crm_time_t *dt)
Definition: iso8601.c:1107
crm_time_seconds
#define crm_time_seconds
Definition: iso8601.h:81
crm_time_format_hr
char * crm_time_format_hr(const char *format, crm_time_hr_t *hr_dt)
Definition: iso8601.c:1372
crm_time_hr_new
crm_time_hr_t * crm_time_hr_new(const char *date_time)
Definition: iso8601.c:1346
crm_time_log
#define crm_time_log(level, prefix, dt, flags)
Definition: iso8601.h:70
crm_time_weeks_in_year
int crm_time_weeks_in_year(int year)
Definition: iso8601.c:146
crm_time_add_years
void crm_time_add_years(crm_time_t *a_time, int extra)
Definition: iso8601.c:1272
crm_time_january1_weekday
int crm_time_january1_weekday(int year)
Definition: iso8601.c:133
crm_time_us::months
int months
Definition: iso8601_internal.h:40
EPOCH_SECONDS
#define EPOCH_SECONDS
Definition: iso8601.c:293
CRM_ASSERT
#define CRM_ASSERT(expr)
Definition: results.h:20
month_days
int month_days[14]
Definition: iso8601.c:165
crm_time_us::duration
bool duration
Definition: iso8601_internal.h:44
crm_time_as_string
char * crm_time_as_string(crm_time_t *date_time, int flags)
Definition: iso8601.c:397
iso8601_internal.h
crm_time_weeks
#define crm_time_weeks
Definition: iso8601.h:80
crm_time_get_seconds_since_epoch
long long crm_time_get_seconds_since_epoch(crm_time_t *dt)
Definition: iso8601.c:295
crm_time_leapyear
bool crm_time_leapyear(int year)
Definition: iso8601.c:177
crm_time_log_date
#define crm_time_log_date
Definition: iso8601.h:74
crm_time_calculate_duration
crm_time_t * crm_time_calculate_duration(crm_time_t *dt, crm_time_t *value)
Definition: iso8601.c:1062
strndup
char * strndup(const char *str, size_t len)
crm_time_add_months
void crm_time_add_months(crm_time_t *a_time, int extra)
Definition: iso8601.c:1212
crm_internal.h
crm_time_add
crm_time_t * crm_time_add(crm_time_t *dt, crm_time_t *value)
Definition: iso8601.c:1040
HAVE_STRUCT_TM_TM_GMTOFF
#define HAVE_STRUCT_TM_TM_GMTOFF
Definition: config.h:401
crm.h
A dumping ground.
crm_time_new
crm_time_t * crm_time_new(const char *date_time)
Definition: iso8601.c:88
crm_time_ordinal
#define crm_time_ordinal
Definition: iso8601.h:79
crm_time_t
struct crm_time_s crm_time_t
Definition: iso8601.h:41
crm_time_us::days
int days
Definition: iso8601_internal.h:41