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