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