pacemaker  1.1.17-b36b869ca8
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 char *
407 {
408  char *date_s = NULL;
409  char *time_s = NULL;
410  char *offset_s = NULL;
411  char *result_s = NULL;
412  crm_time_t *dt = NULL;
413  crm_time_t *utc = NULL;
414 
415  if (date_time == NULL) {
416  return strdup("");
417 
418  } else if (date_time->offset && (flags & crm_time_log_with_timezone) == 0) {
419  crm_trace("UTC conversion");
420  utc = crm_get_utc_time(date_time);
421  dt = utc;
422  } else {
423  dt = date_time;
424  }
425 
426  CRM_CHECK(dt != NULL, return NULL);
427  if (flags & crm_time_log_duration) {
428  uint h = 0, m = 0, s = 0;
429  int offset = 0, max = 128;
430 
431  date_s = calloc(1, max+1);
432  crm_time_get_sec(dt->seconds, &h, &m, &s);
433 
434  if (date_s == NULL) {
435  goto done;
436  }
437 
438  if(dt->years) {
439  offset += snprintf(date_s+offset, max-offset, "%4d year%s ", dt->years, dt->years>1?"s":"");
440  }
441  if(dt->months) {
442  offset += snprintf(date_s+offset, max-offset, "%2d month%s ", dt->months, dt->months>1?"s":"");
443  }
444  if(dt->days) {
445  offset += snprintf(date_s+offset, max-offset, "%2d day%s ", dt->days, dt->days>1?"s":"");
446  }
447  if(dt->seconds) {
448  offset += snprintf(date_s+offset, max-offset, "%d seconds ( ", dt->seconds);
449  if(h) {
450  offset += snprintf(date_s+offset, max-offset, "%d hour%s ", h, h>1?"s":"");
451  }
452  if(m) {
453  offset += snprintf(date_s+offset, max-offset, "%d minute%s ", m, m>1?"s":"");
454  }
455  if(s) {
456  offset += snprintf(date_s+offset, max-offset, "%d second%s ", s, s>1?"s":"");
457  }
458  offset += snprintf(date_s+offset, max-offset, ")");
459  }
460  goto done;
461  }
462 
463  if (flags & crm_time_log_date) {
464  date_s = calloc(1, 32);
465  if (date_s == NULL) {
466  goto done;
467 
468  } else if (flags & crm_time_seconds) {
469  unsigned long long s = crm_time_get_seconds(date_time);
470 
471  snprintf(date_s, 31, "%lld", s); /* Durations may not be +ve */
472  goto done;
473 
474  } else if (flags & crm_time_epoch) {
475  unsigned long long s = crm_time_get_seconds_since_epoch(date_time);
476 
477  snprintf(date_s, 31, "%lld", s); /* Durations may not be +ve */
478  goto done;
479 
480  } else if (flags & crm_time_weeks) {
481  /* YYYY-Www-D */
482  uint y, w, d;
483 
484  if (crm_time_get_isoweek(dt, &y, &w, &d)) {
485  snprintf(date_s, 31, "%d-W%.2d-%d", y, w, d);
486  }
487 
488  } else if (flags & crm_time_ordinal) {
489  /* YYYY-DDD */
490  uint y, d;
491 
492  if (crm_time_get_ordinal(dt, &y, &d)) {
493  snprintf(date_s, 31, "%d-%.3d", y, d);
494  }
495 
496  } else {
497  /* YYYY-MM-DD */
498  uint y, m, d;
499 
500  if (crm_time_get_gregorian(dt, &y, &m, &d)) {
501  snprintf(date_s, 31, "%.4d-%.2d-%.2d", y, m, d);
502  }
503  }
504  }
505 
506  if (flags & crm_time_log_timeofday) {
507  uint h, m, s;
508 
509  time_s = calloc(1, 32);
510  if (time_s == NULL) {
511  goto cleanup;
512  }
513 
514  if (crm_time_get_timeofday(dt, &h, &m, &s)) {
515  snprintf(time_s, 31, "%.2d:%.2d:%.2d", h, m, s);
516  }
517 
518  if (dt->offset != 0) {
519  crm_time_get_sec(dt->offset, &h, &m, &s);
520  }
521 
522  offset_s = calloc(1, 32);
523  if ((flags & crm_time_log_with_timezone) == 0 || dt->offset == 0) {
524  crm_trace("flags %6x %6x", flags, crm_time_log_with_timezone);
525  snprintf(offset_s, 31, "Z");
526 
527  } else {
528  snprintf(offset_s, 31, " %c%.2d:%.2d", dt->offset < 0 ? '-' : '+', h, m);
529  }
530  }
531 
532  done:
533  result_s = calloc(1, 100);
534 
535  snprintf(result_s, 100, "%s%s%s%s",
536  date_s ? date_s : "", (date_s != NULL && time_s != NULL) ? " " : "",
537  time_s ? time_s : "", offset_s ? offset_s : "");
538 
539  cleanup:
540  free(date_s);
541  free(time_s);
542  free(offset_s);
543  crm_time_free(utc);
544 
545  return result_s;
546 }
547 
548 static int
549 crm_time_parse_sec(const char *time_str)
550 {
551  int rc;
552  uint hour = 0;
553  uint minute = 0;
554  uint second = 0;
555 
556  rc = sscanf(time_str, "%d:%d:%d", &hour, &minute, &second);
557  if (rc == 1) {
558  rc = sscanf(time_str, "%2d%2d%2d", &hour, &minute, &second);
559  }
560 
561  if (rc > 0 && rc < 4) {
562  crm_trace("Got valid time: %.2d:%.2d:%.2d", hour, minute, second);
563  if (hour >= 24) {
564  crm_err("Invalid hour: %d", hour);
565  } else if (minute >= 60) {
566  crm_err("Invalid minute: %d", minute);
567  } else if (second >= 60) {
568  crm_err("Invalid second: %d", second);
569  } else {
570  second += (minute * 60);
571  second += (hour * 60 * 60);
572  }
573  } else {
574  crm_err("Bad time: %s (%d)", time_str, rc);
575  }
576  return second;
577 }
578 
579 static int
580 crm_time_parse_offset(const char *offset_str)
581 {
582  int offset = 0;
583 
584  tzset();
585  if (offset_str == NULL) {
586 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
587  time_t now = time(NULL);
588  struct tm *now_tm = localtime(&now);
589 #endif
590  int h_offset = GMTOFF(now_tm) / (3600);
591  int m_offset = (GMTOFF(now_tm) - (3600 * h_offset)) / (60);
592 
593  if (h_offset < 0 && m_offset < 0) {
594  m_offset = 0 - m_offset;
595  }
596  offset += (60 * 60 * h_offset);
597  offset += (60 * m_offset);
598 
599  } else if (offset_str[0] == 'Z') {
600 
601  } else if (offset_str[0] == '+' || offset_str[0] == '-' || isdigit((int)offset_str[0])) {
602  gboolean negate = FALSE;
603 
604  if (offset_str[0] == '-') {
605  negate = TRUE;
606  offset_str++;
607  }
608  offset = crm_time_parse_sec(offset_str);
609  if (negate) {
610  offset = 0 - offset;
611  }
612  }
613  return offset;
614 }
615 
616 static crm_time_t *
617 crm_time_parse(const char *time_str, crm_time_t * a_time)
618 {
619  uint h, m, s;
620  char *offset_s = NULL;
621  crm_time_t *dt = a_time;
622 
623  tzset();
624  if (a_time == NULL) {
625  dt = calloc(1, sizeof(crm_time_t));
626  }
627 
628  if (time_str) {
629  dt->seconds = crm_time_parse_sec(time_str);
630 
631  offset_s = strstr(time_str, "Z");
632  if (offset_s == NULL) {
633  offset_s = strstr(time_str, " ");
634  }
635  }
636 
637  if (offset_s) {
638  while (isspace(offset_s[0])) {
639  offset_s++;
640  }
641  }
642  dt->offset = crm_time_parse_offset(offset_s);
643  crm_time_get_sec(dt->offset, &h, &m, &s);
644  crm_trace("Got tz: %c%2.d:%.2d", dt->offset < 0 ? '-' : '+', h, m);
645  return dt;
646 }
647 
648 crm_time_t *
649 parse_date(const char *date_str)
650 {
651  char *time_s;
652  crm_time_t *dt = NULL;
653 
654  int year = 0;
655  int month = 0;
656  int week = 0;
657  int day = 0;
658  int rc = 0;
659 
660  CRM_CHECK(date_str != NULL, return NULL);
661  CRM_CHECK(strlen(date_str) > 0, return NULL);
662 
663  if (date_str[0] == 'T' || date_str[2] == ':') {
664  /* Just a time supplied - Infer current date */
665  dt = crm_time_new(NULL);
666  dt = crm_time_parse(date_str, dt);
667  goto done;
668 
669  } else {
670  dt = calloc(1, sizeof(crm_time_t));
671  }
672 
673  if (safe_str_eq("epoch", date_str)) {
674  dt->days = 1;
675  dt->years = 1970;
677  return dt;
678  }
679 
680  /* YYYY-MM-DD */
681  rc = sscanf(date_str, "%d-%d-%d", &year, &month, &day);
682  if (rc == 1) {
683  /* YYYYMMDD */
684  rc = sscanf(date_str, "%4d%2d%2d", &year, &month, &day);
685  }
686  if (rc == 3) {
687  if (month > 12) {
688  crm_err("Invalid month: %d", month);
689  } else if (day > 31) {
690  crm_err("Invalid day: %d", day);
691  } else {
692  dt->years = year;
693  dt->days = get_ordinal_days(year, month, day);
694  crm_trace("Got gergorian date: %.4d-%.3d", year, dt->days);
695  }
696  goto done;
697  }
698 
699  /* YYYY-DDD */
700  rc = sscanf(date_str, "%d-%d", &year, &day);
701  if (rc == 2) {
702  crm_trace("Got ordinal date");
703  if (day > year_days(year)) {
704  crm_err("Invalid day: %d (max=%d)", day, year_days(year));
705  } else {
706  dt->days = day;
707  dt->years = year;
708  }
709  goto done;
710  }
711 
712  /* YYYY-Www-D */
713  rc = sscanf(date_str, "%d-W%d-%d", &year, &week, &day);
714  if (rc == 3) {
715  crm_trace("Got week date");
716  if (week > crm_time_weeks_in_year(year)) {
717  crm_err("Invalid week: %d (max=%d)", week, crm_time_weeks_in_year(year));
718  } else if (day < 1 || day > 7) {
719  crm_err("Invalid day: %d", day);
720  } else {
721  /*
722  * http://en.wikipedia.org/wiki/ISO_week_date
723  *
724  * Monday 29 December 2008 is written "2009-W01-1"
725  * Sunday 3 January 2010 is written "2009-W53-7"
726  *
727  * Saturday 27 September 2008 is written "2008-W37-6"
728  *
729  * http://en.wikipedia.org/wiki/ISO_week_date
730  * If 1 January is on a Monday, Tuesday, Wednesday or Thursday, it is in week 01.
731  * If 1 January is on a Friday, Saturday or Sunday, it is in week 52 or 53 of the previous year.
732  */
733  int jan1 = crm_time_january1_weekday(year);
734 
735  crm_trace("Jan 1 = %d", jan1);
736 
737  dt->years = year;
738  crm_time_add_days(dt, (week - 1) * 7);
739 
740  if (jan1 <= 4) {
741  crm_time_add_days(dt, 1 - jan1);
742  } else {
743  crm_time_add_days(dt, 8 - jan1);
744  }
745 
746  crm_time_add_days(dt, day);
747  }
748  goto done;
749  }
750 
751  crm_err("Couldn't parse %s", date_str);
752  done:
753 
754  time_s = strstr(date_str, " ");
755  if (time_s == NULL) {
756  time_s = strstr(date_str, "T");
757  }
758 
759  if (dt && time_s) {
760  time_s++;
761  crm_time_parse(time_s, dt);
762  }
763 
765 
766  CRM_CHECK(crm_time_check(dt), return NULL);
767 
768  return dt;
769 }
770 
771 static int
772 parse_int(const char *str, int field_width, int uppper_bound, int *result)
773 {
774  int lpc = 0;
775  int offset = 0;
776  int intermediate = 0;
777  gboolean fraction = FALSE;
778  gboolean negate = FALSE;
779 
780  CRM_CHECK(str != NULL, return FALSE);
781  CRM_CHECK(result != NULL, return FALSE);
782 
783  *result = 0;
784 
785  if (strlen(str) <= 0) {
786  return FALSE;
787  }
788 
789  if (str[offset] == 'T') {
790  offset++;
791  }
792 
793  if (str[offset] == '.' || str[offset] == ',') {
794  fraction = TRUE;
795  field_width = -1;
796  offset++;
797  } else if (str[offset] == '-') {
798  negate = TRUE;
799  offset++;
800  } else if (str[offset] == '+' || str[offset] == ':') {
801  offset++;
802  }
803 
804  for (; (fraction || lpc < field_width) && isdigit((int)str[offset]); lpc++) {
805  if (fraction) {
806  intermediate = (str[offset] - '0') / (10 ^ lpc);
807  } else {
808  *result *= 10;
809  intermediate = str[offset] - '0';
810  }
811  *result += intermediate;
812  offset++;
813  }
814  if (fraction) {
815  *result = (int)(*result * uppper_bound);
816 
817  } else if (uppper_bound > 0 && *result > uppper_bound) {
818  *result = uppper_bound;
819  }
820  if (negate) {
821  *result = 0 - *result;
822  }
823  if (lpc > 0) {
824  crm_trace("Found int: %d. Stopped at str[%d]='%c'", *result, lpc, str[lpc]);
825  return offset;
826  }
827  return 0;
828 }
829 
830 crm_time_t *
831 crm_time_parse_duration(const char *interval_str)
832 {
833  gboolean is_time = FALSE;
834  crm_time_t *diff = NULL;
835 
836  CRM_CHECK(interval_str != NULL, goto bail);
837  CRM_CHECK(strlen(interval_str) > 0, goto bail);
838  CRM_CHECK(interval_str[0] == 'P', goto bail);
839  interval_str++;
840 
841  diff = calloc(1, sizeof(crm_time_t));
842 
843  while (isspace((int)interval_str[0]) == FALSE) {
844  int an_int = 0, rc;
845  char ch = 0;
846 
847  if (interval_str[0] == 'T') {
848  is_time = TRUE;
849  interval_str++;
850  }
851 
852  rc = parse_int(interval_str, 10, 0, &an_int);
853  if (rc == 0) {
854  break;
855  }
856  interval_str += rc;
857 
858  ch = interval_str[0];
859  interval_str++;
860 
861  crm_trace("Testing %c=%d, rc=%d", ch, an_int, rc);
862 
863  switch (ch) {
864  case 0:
865  return diff;
866  break;
867  case 'Y':
868  diff->years = an_int;
869  break;
870  case 'M':
871  if (is_time) {
872  /* Minutes */
873  diff->seconds += an_int * 60;
874  } else {
875  diff->months = an_int;
876  }
877  break;
878  case 'W':
879  diff->days += an_int * 7;
880  break;
881  case 'D':
882  diff->days += an_int;
883  break;
884  case 'H':
885  diff->seconds += an_int * 60 * 60;
886  break;
887  case 'S':
888  diff->seconds += an_int;
889  break;
890  default:
891  goto bail;
892  break;
893  }
894  }
895  return diff;
896 
897  bail:
898  free(diff);
899  return NULL;
900 }
901 
903 crm_time_parse_period(const char *period_str)
904 {
905  gboolean invalid = FALSE;
906  const char *original = period_str;
907  crm_time_period_t *period = NULL;
908 
909  CRM_CHECK(period_str != NULL, return NULL);
910  CRM_CHECK(strlen(period_str) > 0, return NULL);
911 
912  tzset();
913  period = calloc(1, sizeof(crm_time_period_t));
914 
915  if (period_str[0] == 'P') {
916  period->diff = crm_time_parse_duration(period_str);
917  } else {
918  period->start = parse_date(period_str);
919  }
920 
921  period_str = strstr(original, "/");
922  if (period_str) {
923  CRM_CHECK(period_str[0] == '/', invalid = TRUE;
924  goto bail);
925  period_str++;
926 
927  if (period_str[0] == 'P') {
928  period->diff = crm_time_parse_duration(period_str);
929  } else {
930  period->end = parse_date(period_str);
931  }
932 
933  } else if (period->diff != NULL) {
934  /* just aduration starting from now */
935  period->start = crm_time_new(NULL);
936 
937  } else {
938  invalid = TRUE;
939  CRM_CHECK(period_str != NULL, goto bail);
940  }
941 
942  /* sanity checks */
943  if (period->start == NULL && period->end == NULL) {
944  crm_err("Invalid time period: %s", original);
945  invalid = TRUE;
946 
947  } else if (period->start == NULL && period->diff == NULL) {
948  crm_err("Invalid time period: %s", original);
949  invalid = TRUE;
950 
951  } else if (period->end == NULL && period->diff == NULL) {
952  crm_err("Invalid time period: %s", original);
953  invalid = TRUE;
954  }
955 
956  bail:
957  if (invalid) {
958  free(period->start);
959  free(period->end);
960  free(period->diff);
961  free(period);
962  return NULL;
963  }
964  if (period->end == NULL && period->diff == NULL) {
965  }
966 
967  if (period->start == NULL) {
968  period->start = crm_time_subtract(period->end, period->diff);
969 
970  } else if (period->end == NULL) {
971  period->end = crm_time_add(period->start, period->diff);
972  }
973 
974  crm_time_check(period->start);
975  crm_time_check(period->end);
976 
977  return period;
978 }
979 
980 void
981 crm_time_set(crm_time_t * target, crm_time_t * source)
982 {
983  crm_trace("target=%p, source=%p", target, source);
984 
985  CRM_CHECK(target != NULL && source != NULL, return);
986 
987  target->years = source->years;
988  target->days = source->days;
989  target->months = source->months; /* Only for durations */
990  target->seconds = source->seconds;
991  target->offset = source->offset;
992 
993  crm_time_log(LOG_TRACE, "source", source,
995  crm_time_log(LOG_TRACE, "target", target,
997 }
998 
999 static void
1000 ha_set_tm_time(crm_time_t * target, struct tm *source)
1001 {
1002  int h_offset = 0;
1003  int m_offset = 0;
1004 
1005  /* Ensure target is fully initialized */
1006  target->years = 0;
1007  target->months = 0;
1008  target->days = 0;
1009  target->seconds = 0;
1010  target->offset = 0;
1011  target->duration = FALSE;
1012 
1013  if (source->tm_year > 0) {
1014  /* years since 1900 */
1015  target->years = 1900 + source->tm_year;
1016  }
1017 
1018  if (source->tm_yday >= 0) {
1019  /* days since January 1 [0-365] */
1020  target->days = 1 + source->tm_yday;
1021  }
1022 
1023  if (source->tm_hour >= 0) {
1024  target->seconds += 60 * 60 * source->tm_hour;
1025  }
1026  if (source->tm_min >= 0) {
1027  target->seconds += 60 * source->tm_min;
1028  }
1029  if (source->tm_sec >= 0) {
1030  target->seconds += source->tm_sec;
1031  }
1032 
1033  /* tm_gmtoff == offset from UTC in seconds */
1034  h_offset = GMTOFF(source) / (3600);
1035  m_offset = (GMTOFF(source) - (3600 * h_offset)) / (60);
1036  crm_trace("Offset (s): %ld, offset (hh:mm): %.2d:%.2d", GMTOFF(source), h_offset, m_offset);
1037 
1038  target->offset += 60 * 60 * h_offset;
1039  target->offset += 60 * m_offset;
1040 }
1041 
1042 void
1043 crm_time_set_timet(crm_time_t * target, time_t * source)
1044 {
1045  ha_set_tm_time(target, localtime(source));
1046 }
1047 
1048 crm_time_t *
1050 {
1051  crm_time_t *utc = NULL;
1052  crm_time_t *answer = NULL;
1053 
1054  CRM_CHECK(dt != NULL && value != NULL, return NULL);
1055 
1056  answer = calloc(1, sizeof(crm_time_t));
1057  crm_time_set(answer, dt);
1058 
1059  utc = crm_get_utc_time(value);
1060 
1061  answer->years += utc->years;
1062  crm_time_add_months(answer, utc->months);
1063  crm_time_add_days(answer, utc->days);
1064  crm_time_add_seconds(answer, utc->seconds);
1065 
1066  crm_time_free(utc);
1067  return answer;
1068 }
1069 
1070 crm_time_t *
1072 {
1073  crm_time_t *utc = NULL;
1074  crm_time_t *answer = NULL;
1075 
1076  CRM_CHECK(dt != NULL && value != NULL, return NULL);
1077 
1078  utc = crm_get_utc_time(value);
1079  answer = crm_get_utc_time(dt);
1080  answer->duration = TRUE;
1081 
1082  answer->years -= utc->years;
1083  if(utc->months != 0) {
1084  crm_time_add_months(answer, -utc->months);
1085  }
1086  crm_time_add_days(answer, -utc->days);
1087  crm_time_add_seconds(answer, -utc->seconds);
1088 
1089  crm_time_free(utc);
1090  return answer;
1091 }
1092 
1093 crm_time_t *
1095 {
1096  crm_time_t *utc = NULL;
1097  crm_time_t *answer = NULL;
1098 
1099  CRM_CHECK(dt != NULL && value != NULL, return NULL);
1100 
1101  answer = calloc(1, sizeof(crm_time_t));
1102  crm_time_set(answer, dt);
1103  utc = crm_get_utc_time(value);
1104 
1105  answer->years -= utc->years;
1106  if(utc->months != 0) {
1107  crm_time_add_months(answer, -utc->months);
1108  }
1109  crm_time_add_days(answer, -utc->days);
1110  crm_time_add_seconds(answer, -utc->seconds);
1111 
1112  return answer;
1113 }
1114 
1115 bool
1117 {
1118  int ydays = 0;
1119 
1120  CRM_CHECK(dt != NULL, return FALSE);
1121 
1122  ydays = year_days(dt->years);
1123  crm_trace("max ydays: %d", ydays);
1124 
1125  CRM_CHECK(dt->days > 0, return FALSE);
1126  CRM_CHECK(dt->days <= ydays, return FALSE);
1127 
1128  CRM_CHECK(dt->seconds >= 0, return FALSE);
1129  CRM_CHECK(dt->seconds < 24 * 60 * 60, return FALSE);
1130 
1131  return TRUE;
1132 }
1133 
1134 #define do_cmp_field(l, r, field) \
1135  if(rc == 0) { \
1136  if(l->field > r->field) { \
1137  crm_trace("%s: %d > %d", \
1138  #field, l->field, r->field); \
1139  rc = 1; \
1140  } else if(l->field < r->field) { \
1141  crm_trace("%s: %d < %d", \
1142  #field, l->field, r->field); \
1143  rc = -1; \
1144  } \
1145  }
1146 
1147 int
1149 {
1150  int rc = 0;
1151  crm_time_t *t1 = NULL;
1152  crm_time_t *t2 = NULL;
1153 
1154  if (a == NULL && b == NULL) {
1155  return 0;
1156  } else if (a == NULL) {
1157  return -1;
1158  } else if (b == NULL) {
1159  return 1;
1160  }
1161 
1162  t1 = crm_get_utc_time(a);
1163  t2 = crm_get_utc_time(b);
1164 
1165  do_cmp_field(t1, t2, years);
1166  do_cmp_field(t1, t2, days);
1167  do_cmp_field(t1, t2, seconds);
1168 
1169  crm_time_free(t1);
1170  crm_time_free(t2);
1171  return rc;
1172 }
1173 
1174 void
1175 crm_time_add_seconds(crm_time_t * a_time, int extra)
1176 {
1177  int days = 0;
1178  int seconds = 24 * 60 * 60;
1179 
1180  crm_trace("Adding %d seconds to %d (max=%d)", extra, a_time->seconds, seconds);
1181 
1182  a_time->seconds += extra;
1183  while (a_time->seconds >= seconds) {
1184  a_time->seconds -= seconds;
1185  days++;
1186  }
1187 
1188  while (a_time->seconds < 0) {
1189  a_time->seconds += seconds;
1190  days--;
1191  }
1192  crm_time_add_days(a_time, days);
1193 }
1194 
1195 void
1196 crm_time_add_days(crm_time_t * a_time, int extra)
1197 {
1198  int lower_bound = 1;
1199  int ydays = crm_time_leapyear(a_time->years) ? 366 : 365;
1200 
1201  crm_trace("Adding %d days to %.4d-%.3d", extra, a_time->years, a_time->days);
1202 
1203  a_time->days += extra;
1204  while (a_time->days > ydays) {
1205  a_time->years++;
1206  a_time->days -= ydays;
1207  ydays = crm_time_leapyear(a_time->years) ? 366 : 365;
1208  }
1209 
1210  if(a_time->duration) {
1211  lower_bound = 0;
1212  }
1213 
1214  while (a_time->days < lower_bound) {
1215  a_time->years--;
1216  a_time->days += crm_time_leapyear(a_time->years) ? 366 : 365;
1217  }
1218 }
1219 
1220 void
1221 crm_time_add_months(crm_time_t * a_time, int extra)
1222 {
1223  int lpc;
1224  uint32_t y, m, d, dmax;
1225 
1226  crm_time_get_gregorian(a_time, &y, &m, &d);
1227  crm_trace("Adding %d months to %.4d-%.2d-%.2d", extra, y, m, d);
1228 
1229  if (extra > 0) {
1230  for (lpc = extra; lpc > 0; lpc--) {
1231  m++;
1232  if (m == 13) {
1233  m = 1;
1234  y++;
1235  }
1236  }
1237  } else {
1238  for (lpc = -extra; lpc > 0; lpc--) {
1239  m--;
1240  if (m == 0) {
1241  m = 12;
1242  y--;
1243  }
1244  }
1245  }
1246 
1247  dmax = crm_time_days_in_month(m, y);
1248  if (dmax < d) {
1249  /* Preserve day-of-month unless the month doesn't have enough days */
1250  d = dmax;
1251  }
1252 
1253  crm_trace("Calculated %.4d-%.2d-%.2d", y, m, d);
1254 
1255  a_time->years = y;
1256  a_time->days = get_ordinal_days(y, m, d);
1257 
1258  crm_time_get_gregorian(a_time, &y, &m, &d);
1259  crm_trace("Got %.4d-%.2d-%.2d", y, m, d);
1260 }
1261 
1262 void
1263 crm_time_add_minutes(crm_time_t * a_time, int extra)
1264 {
1265  crm_time_add_seconds(a_time, extra * 60);
1266 }
1267 
1268 void
1269 crm_time_add_hours(crm_time_t * a_time, int extra)
1270 {
1271  crm_time_add_seconds(a_time, extra * 60 * 60);
1272 }
1273 
1274 void
1275 crm_time_add_weeks(crm_time_t * a_time, int extra)
1276 {
1277  crm_time_add_days(a_time, extra * 7);
1278 }
1279 
1280 void
1281 crm_time_add_years(crm_time_t * a_time, int extra)
1282 {
1283  a_time->years += extra;
1284 }
1285 
1286 static void
1287 ha_get_tm_time( struct tm *target, crm_time_t *source)
1288 {
1289  *target = (struct tm) {
1290  .tm_year = source->years - 1900,
1291  .tm_mday = source->days,
1292  .tm_sec = source->seconds % 60,
1293  .tm_min = ( source->seconds / 60 ) % 60,
1294  .tm_hour = source->seconds / 60 / 60,
1295  .tm_isdst = -1, /* don't adjust */
1296 
1297 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
1298  .tm_gmtoff = source->offset
1299 #endif
1300  };
1301  mktime(target);
1302 }
1303 
1304 crm_time_hr_t *
1306 {
1307  crm_time_hr_t *hr_dt = NULL;
1308 
1309  if (dt) {
1310  hr_dt = target?target:calloc(1, sizeof(crm_time_hr_t));
1311  if (hr_dt) {
1312  *hr_dt = (crm_time_hr_t) {
1313  .years = dt->years,
1314  .months = dt->months,
1315  .days = dt->days,
1316  .seconds = dt->seconds,
1317  .offset = dt->offset,
1318  .duration = dt->duration
1319  };
1320  }
1321  }
1322 
1323  return hr_dt;
1324 }
1325 
1326 void
1328 {
1329  CRM_ASSERT((hr_dt) && (target));
1330  *target = (crm_time_t) {
1331  .years = hr_dt->years,
1332  .months = hr_dt->months,
1333  .days = hr_dt->days,
1334  .seconds = hr_dt->seconds,
1335  .offset = hr_dt->offset,
1336  .duration = hr_dt->duration
1337  };
1338 }
1339 
1340 crm_time_hr_t *
1341 crm_time_timeval_hr_convert(crm_time_hr_t *target, struct timeval *tv)
1342 {
1343  crm_time_t dt;
1344  crm_time_hr_t *ret;
1345 
1346  crm_time_set_timet(&dt, &tv->tv_sec);
1347  ret = crm_time_hr_convert(target, &dt);
1348  if (ret) {
1349  ret->useconds = tv->tv_usec;
1350  }
1351  return ret;
1352 }
1353 
1354 crm_time_hr_t *
1355 crm_time_hr_new(const char *date_time)
1356 {
1357  crm_time_hr_t *hr_dt = NULL;
1358  struct timeval tv_now;
1359 
1360  if (!date_time) {
1361  if (gettimeofday(&tv_now, NULL) == 0) {
1362  hr_dt = crm_time_timeval_hr_convert(NULL, &tv_now);
1363  }
1364  } else {
1365  crm_time_t *dt;
1366 
1367  dt = parse_date(date_time);
1368  hr_dt = crm_time_hr_convert(NULL, dt);
1369  crm_time_free(dt);
1370  }
1371  return hr_dt;
1372 }
1373 
1374 void
1376 {
1377  free(hr_dt);
1378 }
1379 
1380 char *
1381 crm_time_format_hr(const char *format, crm_time_hr_t * hr_dt)
1382 {
1383  const char *mark_s;
1384  int max = 128, scanned_pos = 0, printed_pos = 0, fmt_pos = 0,
1385  date_len = 0, nano_digits = 0, fmt_len;
1386  char nano_s[10], date_s[max+1], nanofmt_s[5] = "%", *tmp_fmt_s;
1387  struct tm tm;
1388  crm_time_t dt;
1389 
1390  if (!format) {
1391  return NULL;
1392  }
1393  crm_time_set_hr_dt(&dt, hr_dt);
1394  ha_get_tm_time(&tm, &dt);
1395  sprintf(nano_s, "%06d000", hr_dt->useconds);
1396 
1397  while ((format[scanned_pos]) != '\0') {
1398  fmt_len = 0;
1399  mark_s = strchr(&format[scanned_pos], '%');
1400  if (mark_s) {
1401  fmt_pos = mark_s - format;
1402  fmt_len = 1;
1403  while ((format[fmt_pos+fmt_len] != '\0') &&
1404  (format[fmt_pos+fmt_len] >= '0') &&
1405  (format[fmt_pos+fmt_len] <= '9')) {
1406  fmt_len++;
1407  }
1408  scanned_pos = fmt_pos + fmt_len + 1;
1409  if (format[fmt_pos+fmt_len] == 'N') {
1410  nano_digits = atoi(&format[fmt_pos+1]);
1411  nano_digits = (nano_digits > 6)?6:nano_digits;
1412  nano_digits = (nano_digits < 0)?0:nano_digits;
1413  sprintf(&nanofmt_s[1], ".%ds", nano_digits);
1414  } else {
1415  if (format[scanned_pos] != '\0') {
1416  continue;
1417  }
1418  fmt_pos = scanned_pos; /* print till end */
1419  }
1420  } else {
1421  scanned_pos = strlen(format);
1422  fmt_pos = scanned_pos; /* print till end */
1423  }
1424  tmp_fmt_s = strndup(&format[printed_pos], fmt_pos - printed_pos);
1425 #ifdef GCC_FORMAT_NONLITERAL_CHECKING_ENABLED
1426 #pragma GCC diagnostic push
1427 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1428 #endif
1429  date_len += strftime(&date_s[date_len], max-date_len, tmp_fmt_s, &tm);
1430 #ifdef GCC_FORMAT_NONLITERAL_CHECKING_ENABLED
1431 #pragma GCC diagnostic pop
1432 #endif
1433  printed_pos = scanned_pos;
1434  free(tmp_fmt_s);
1435  if (nano_digits) {
1436 #ifdef GCC_FORMAT_NONLITERAL_CHECKING_ENABLED
1437 #pragma GCC diagnostic push
1438 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1439 #endif
1440  date_len += snprintf(&date_s[date_len], max-date_len,
1441  nanofmt_s, nano_s);
1442 #ifdef GCC_FORMAT_NONLITERAL_CHECKING_ENABLED
1443 #pragma GCC diagnostic pop
1444 #endif
1445  nano_digits = 0;
1446  }
1447  }
1448 
1449  return (date_len == 0)?NULL:strdup(date_s);
1450 }
#define LOG_TRACE
Definition: logging.h:29
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:164
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:831
#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:1094
void crm_time_set_timet(crm_time_t *target, time_t *source)
Definition: iso8601.c:1043
crm_time_t * crm_time_add(crm_time_t *dt, crm_time_t *value)
Definition: iso8601.c:1049
#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:649
int crm_time_compare(crm_time_t *a, crm_time_t *b)
Definition: iso8601.c:1148
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:1263
void crm_time_add_weeks(crm_time_t *a_time, int extra)
Definition: iso8601.c:1275
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:116
#define do_cmp_field(l, r, field)
Definition: iso8601.c:1134
crm_time_hr_t * crm_time_timeval_hr_convert(crm_time_hr_t *target, struct timeval *tv)
Definition: iso8601.c:1341
#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:196
#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:903
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:1175
bool crm_time_check(crm_time_t *dt)
Definition: iso8601.c:1116
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:1196
#define crm_trace(fmt, args...)
Definition: logging.h:254
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:1269
#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:1281
char * crm_time_format_hr(const char *format, crm_time_hr_t *hr_dt)
Definition: iso8601.c:1381
crm_time_hr_t * crm_time_hr_new(const char *date_time)
Definition: iso8601.c:1355
#define HAVE_STRUCT_TM_TM_GMTOFF
Definition: config.h:465
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:1375
#define crm_err(fmt, args...)
Definition: logging.h:248
void crm_time_add_months(crm_time_t *a_time, int extra)
Definition: iso8601.c:1221
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:35
crm_time_t * crm_time_calculate_duration(crm_time_t *dt, crm_time_t *value)
Definition: iso8601.c:1071
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:1305
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:406
void crm_time_set_hr_dt(crm_time_t *target, crm_time_hr_t *hr_dt)
Definition: iso8601.c:1327
#define safe_str_eq(a, b)
Definition: util.h:64
#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:981
struct crm_time_us crm_time_hr_t