53 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
54 # define GMTOFF(tm) ((tm)->tm_gmtoff)
57 # define GMTOFF(tm) (-timezone+daylight)
79 utc->years = dt->years;
81 utc->seconds = dt->seconds;
88 utc->months = dt->months;
105 if (date_time == NULL) {
146 int YY = (year - 1) % 100;
147 int C = (year - 1) - YY;
149 int jan1 = 1 + (((((C / 100) % 4) * 5) + G) % 7);
151 crm_trace(
"YY=%d, C=%d, G=%d", YY, C, G);
152 crm_trace(
"January 1 %.4d: %d", year, jan1);
176 int month_days[14] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 29 };
184 return month_days[month];
190 gboolean is_leap = FALSE;
195 if (year % 100 == 0 && year % 400 != 0) {
206 for (lpc = 1; lpc < m; lpc++) {
218 if (log_level < LOG_CRIT) {
220 prefix ? prefix :
"", prefix ?
": " :
"", date_s ? date_s :
"__invalid_date__");
223 prefix ? prefix :
"", prefix ?
": " :
"",
224 date_s ? date_s :
"__invalid_date__");
230 crm_time_get_sec(
int sec, uint * h, uint * m, uint * s)
232 uint hours, minutes, seconds;
240 hours = seconds / (60 * 60);
241 seconds -= 60 * 60 * hours;
243 minutes = seconds / (60);
244 seconds -= 60 * minutes;
246 crm_trace(
"%d == %.2d:%.2d:%.2d", sec, hours, minutes, seconds);
258 return crm_time_get_sec(dt->seconds, h, m, s);
266 return crm_time_get_sec(dt->seconds, h, m, &s);
274 long long in_seconds = 0;
276 utc = crm_get_utc_time(dt);
278 for (lpc = 1; lpc < utc->years; lpc++) {
279 int dmax = year_days(lpc);
281 in_seconds += 60 * 60 * 24 * dmax;
291 if (utc->months > 0) {
292 in_seconds += 60 * 60 * 24 * 30 * utc->months;
296 in_seconds += 60 * 60 * 24 * (utc->days - 1);
298 in_seconds += utc->seconds;
304 #define EPOCH_SECONDS 62135596800ULL
318 for (months = 1; months <= 12 && days > 0; months++) {
328 }
else if (dt->months) {
339 crm_trace(
"%.4d-%.3d -> %.4d-%.2d-%.2d", dt->years, dt->days, dt->years, months, days);
365 h = dt->days + jan1 - 1;
366 *d = 1 + ((h - 1) % 7);
369 if (dt->days <= (8 - jan1) && jan1 > 4) {
371 year_num = dt->years - 1;
375 year_num = dt->years;
379 if (year_num == dt->years) {
380 int dmax = year_days(year_num);
381 int correction = 4 - *d;
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;
391 if (year_num == dt->years) {
392 int j = dt->days + (7 - *d) + (jan1 - 1);
401 crm_trace(
"Converted %.4d-%.3d to %.4d-W%.2d-%d", dt->years, dt->days, *y, *w, *d);
412 char *offset_s = NULL;
413 char *result_s = NULL;
417 if (date_time == NULL) {
422 utc = crm_get_utc_time(date_time);
430 uint h = 0, m = 0, s = 0;
434 crm_time_get_sec(dt->seconds, &h, &m, &s);
436 if (date_s == NULL) {
441 offset += snprintf(date_s+offset,
DATE_MAX - offset,
"%4d year%s ", dt->years, dt->years>1?
"s":
"");
444 offset += snprintf(date_s+offset,
DATE_MAX - offset,
"%2d month%s ", dt->months, dt->months>1?
"s":
"");
447 offset += snprintf(date_s+offset,
DATE_MAX - offset,
"%2d day%s ", dt->days, dt->days>1?
"s":
"");
450 offset += snprintf(date_s+offset,
DATE_MAX - offset,
"%d seconds ( ", dt->seconds);
452 offset += snprintf(date_s+offset,
DATE_MAX - offset,
"%u hour%s ", h, h>1?
"s":
"");
455 offset += snprintf(date_s+offset,
DATE_MAX - offset,
"%u minute%s ", m, m>1?
"s":
"");
458 offset += snprintf(date_s+offset,
DATE_MAX - offset,
"%u second%s ", s, s>1?
"s":
"");
460 offset += snprintf(date_s+offset,
DATE_MAX - offset,
")");
466 date_s = calloc(1, 34);
467 if (date_s == NULL) {
473 snprintf(date_s, 32,
"%lld", s);
479 snprintf(date_s, 32,
"%lld", s);
487 snprintf(date_s, 34,
"%u-W%.2u-%u", y, w, d);
495 snprintf(date_s, 22,
"%u-%.3u", y, d);
503 snprintf(date_s, 33,
"%.4u-%.2u-%.2u", y, m, d);
511 time_s = calloc(1, 33);
512 if (time_s == NULL) {
517 snprintf(time_s, 33,
"%.2u:%.2u:%.2u", h, m, s);
520 if (dt->offset != 0) {
521 crm_time_get_sec(dt->offset, &h, &m, &s);
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");
530 snprintf(offset_s, 24,
" %c%.2u:%.2u", dt->offset < 0 ?
'-' :
'+', h, m);
535 result_s = calloc(1, 100);
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 :
"");
551 crm_time_parse_sec(
const char *time_str)
558 rc = sscanf(time_str,
"%d:%d:%d", &hour, &minute, &second);
560 rc = sscanf(time_str,
"%2d%2d%2d", &hour, &minute, &second);
563 if (rc > 0 && rc < 4) {
564 crm_trace(
"Got valid time: %.2d:%.2d:%.2d", hour, minute, second);
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);
572 second += (minute * 60);
573 second += (hour * 60 * 60);
576 crm_err(
"Bad time: %s (%d)", time_str, rc);
582 crm_time_parse_offset(
const char *offset_str)
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);
592 int h_offset =
GMTOFF(now_tm) / (3600);
593 int m_offset = (
GMTOFF(now_tm) - (3600 * h_offset)) / (60);
595 if (h_offset < 0 && m_offset < 0) {
596 m_offset = 0 - m_offset;
598 offset += (60 * 60 * h_offset);
599 offset += (60 * m_offset);
601 }
else if (offset_str[0] ==
'Z') {
603 }
else if (offset_str[0] ==
'+' || offset_str[0] ==
'-' || isdigit((
int)offset_str[0])) {
604 gboolean negate = FALSE;
606 if (offset_str[0] ==
'-') {
610 offset = crm_time_parse_sec(offset_str);
619 crm_time_parse(
const char *time_str,
crm_time_t * a_time)
622 char *offset_s = NULL;
626 if (a_time == NULL) {
631 dt->seconds = crm_time_parse_sec(time_str);
633 offset_s = strstr(time_str,
"Z");
634 if (offset_s == NULL) {
635 offset_s = strstr(time_str,
" ");
640 while (isspace(offset_s[0])) {
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);
662 CRM_CHECK(date_str != NULL,
return NULL);
663 CRM_CHECK(strlen(date_str) > 0,
return NULL);
665 if (date_str[0] ==
'T' || date_str[2] ==
':') {
668 dt = crm_time_parse(date_str, dt);
683 rc = sscanf(date_str,
"%d-%d-%d", &year, &month, &day);
686 rc = sscanf(date_str,
"%4d%2d%2d", &year, &month, &day);
690 crm_err(
"Invalid month: %d", month);
691 }
else if (day > 31) {
692 crm_err(
"Invalid day: %d", day);
695 dt->days = get_ordinal_days(year, month, day);
696 crm_trace(
"Got gergorian date: %.4d-%.3d", year, dt->days);
702 rc = sscanf(date_str,
"%d-%d", &year, &day);
705 if (day > year_days(year)) {
706 crm_err(
"Invalid day: %d (max=%d)", day, year_days(year));
715 rc = sscanf(date_str,
"%d-W%d-%d", &year, &week, &day);
720 }
else if (day < 1 || day > 7) {
721 crm_err(
"Invalid day: %d", day);
753 crm_err(
"Couldn't parse %s", date_str);
756 time_s = strstr(date_str,
" ");
757 if (time_s == NULL) {
758 time_s = strstr(date_str,
"T");
763 crm_time_parse(time_s, dt);
774 parse_int(
const char *str,
int field_width,
int uppper_bound,
int *result)
778 int intermediate = 0;
779 gboolean fraction = FALSE;
780 gboolean negate = FALSE;
787 if (strlen(str) <= 0) {
791 if (str[offset] ==
'T') {
795 if (str[offset] ==
'.' || str[offset] ==
',') {
799 }
else if (str[offset] ==
'-') {
802 }
else if (str[offset] ==
'+' || str[offset] ==
':') {
806 for (; (fraction || lpc < field_width) && isdigit((
int)str[offset]); lpc++) {
808 intermediate = (str[offset] -
'0') / (10 ^ lpc);
811 intermediate = str[offset] -
'0';
813 *result += intermediate;
817 *result = (int)(*result * uppper_bound);
819 }
else if (uppper_bound > 0 && *result > uppper_bound) {
820 *result = uppper_bound;
823 *result = 0 - *result;
826 crm_trace(
"Found int: %d. Stopped at str[%d]='%c'", *result, lpc, str[lpc]);
835 gboolean is_time = FALSE;
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);
845 while (isspace((
int)interval_str[0]) == FALSE) {
849 if (interval_str[0] ==
'T') {
854 rc = parse_int(interval_str, 10, 0, &an_int);
860 ch = interval_str[0];
863 crm_trace(
"Testing %c=%d, rc=%d", ch, an_int, rc);
870 diff->years = an_int;
875 diff->seconds += an_int * 60;
877 diff->months = an_int;
881 diff->days += an_int * 7;
884 diff->days += an_int;
887 diff->seconds += an_int * 60 * 60;
890 diff->seconds += an_int;
907 gboolean invalid = FALSE;
908 const char *original = period_str;
911 CRM_CHECK(period_str != NULL,
return NULL);
912 CRM_CHECK(strlen(period_str) > 0,
return NULL);
917 if (period_str[0] ==
'P') {
923 period_str = strstr(original,
"/");
925 CRM_CHECK(period_str[0] ==
'/', invalid = TRUE;
929 if (period_str[0] ==
'P') {
935 }
else if (period->
diff != NULL) {
941 CRM_CHECK(period_str != NULL,
goto bail);
945 if (period->
start == NULL && period->
end == NULL) {
946 crm_err(
"Invalid time period: %s", original);
949 }
else if (period->
start == NULL && period->
diff == NULL) {
950 crm_err(
"Invalid time period: %s", original);
953 }
else if (period->
end == NULL && period->
diff == NULL) {
954 crm_err(
"Invalid time period: %s", original);
966 if (period->
end == NULL && period->
diff == NULL) {
969 if (period->
start == NULL) {
972 }
else if (period->
end == NULL) {
985 crm_trace(
"target=%p, source=%p", target, source);
987 CRM_CHECK(target != NULL && source != NULL,
return);
989 target->years = source->years;
990 target->days = source->days;
991 target->months = source->months;
992 target->seconds = source->seconds;
993 target->offset = source->offset;
1002 ha_set_tm_time(
crm_time_t * target,
struct tm *source)
1011 target->seconds = 0;
1013 target->duration = FALSE;
1015 if (source->tm_year > 0) {
1017 target->years = 1900 + source->tm_year;
1020 if (source->tm_yday >= 0) {
1022 target->days = 1 + source->tm_yday;
1025 if (source->tm_hour >= 0) {
1026 target->seconds += 60 * 60 * source->tm_hour;
1028 if (source->tm_min >= 0) {
1029 target->seconds += 60 * source->tm_min;
1031 if (source->tm_sec >= 0) {
1032 target->seconds += source->tm_sec;
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);
1040 target->offset += 60 * 60 * h_offset;
1041 target->offset += 60 * m_offset;
1047 ha_set_tm_time(target, localtime(source));
1056 CRM_CHECK(dt != NULL && value != NULL,
return NULL);
1061 utc = crm_get_utc_time(value);
1063 answer->years += utc->years;
1078 CRM_CHECK(dt != NULL && value != NULL,
return NULL);
1080 utc = crm_get_utc_time(value);
1081 answer = crm_get_utc_time(dt);
1082 answer->duration = TRUE;
1084 answer->years -= utc->years;
1085 if(utc->months != 0) {
1101 CRM_CHECK(dt != NULL && value != NULL,
return NULL);
1105 utc = crm_get_utc_time(value);
1107 answer->years -= utc->years;
1108 if(utc->months != 0) {
1124 ydays = year_days(dt->years);
1128 CRM_CHECK(dt->days <= ydays,
return FALSE);
1130 CRM_CHECK(dt->seconds >= 0,
return FALSE);
1131 CRM_CHECK(dt->seconds < 24 * 60 * 60,
return FALSE);
1136 #define do_cmp_field(l, r, field) \
1138 if(l->field > r->field) { \
1139 crm_trace("%s: %d > %d", \
1140 #field, l->field, r->field); \
1142 } else if(l->field < r->field) { \
1143 crm_trace("%s: %d < %d", \
1144 #field, l->field, r->field); \
1156 if (a == NULL && b == NULL) {
1158 }
else if (a == NULL) {
1160 }
else if (b == NULL) {
1164 t1 = crm_get_utc_time(a);
1165 t2 = crm_get_utc_time(b);
1180 int seconds = 24 * 60 * 60;
1182 crm_trace(
"Adding %d seconds to %d (max=%d)", extra, a_time->seconds, seconds);
1184 a_time->seconds += extra;
1185 while (a_time->seconds >= seconds) {
1186 a_time->seconds -= seconds;
1190 while (a_time->seconds < 0) {
1191 a_time->seconds += seconds;
1200 int lower_bound = 1;
1203 crm_trace(
"Adding %d days to %.4d-%.3d", extra, a_time->years, a_time->days);
1205 a_time->days += extra;
1206 while (a_time->days > ydays) {
1208 a_time->days -= ydays;
1212 if(a_time->duration) {
1216 while (a_time->days < lower_bound) {
1229 crm_trace(
"Adding %d months to %.4d-%.2d-%.2d", extra, y, m, d);
1232 for (lpc = extra; lpc > 0; lpc--) {
1240 for (lpc = -extra; lpc > 0; lpc--) {
1255 crm_trace(
"Calculated %.4d-%.2d-%.2d", y, m, d);
1258 a_time->days = get_ordinal_days(y, m, d);
1261 crm_trace(
"Got %.4d-%.2d-%.2d", y, m, d);
1285 a_time->years += extra;
1289 ha_get_tm_time(
struct tm *target,
crm_time_t *source)
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,
1300 .tm_gmtoff = source->offset
1316 .months = dt->months,
1318 .seconds = dt->seconds,
1319 .offset = dt->offset,
1320 .duration = dt->duration
1333 .years = hr_dt->
years,
1335 .days = hr_dt->
days,
1360 struct timeval tv_now;
1363 if (gettimeofday(&tv_now, NULL) == 0) {
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;
1396 ha_get_tm_time(&tm, &dt);
1397 sprintf(nano_s,
"%06d000", hr_dt->
useconds);
1399 while ((format[scanned_pos]) !=
'\0') {
1401 mark_s = strchr(&format[scanned_pos],
'%');
1403 fmt_pos = mark_s - format;
1405 while ((format[fmt_pos+fmt_len] !=
'\0') &&
1406 (format[fmt_pos+fmt_len] >=
'0') &&
1407 (format[fmt_pos+fmt_len] <=
'9')) {
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);
1417 if (format[scanned_pos] !=
'\0') {
1420 fmt_pos = scanned_pos;
1423 scanned_pos = strlen(format);
1424 fmt_pos = scanned_pos;
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"
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
1435 printed_pos = scanned_pos;
1438 #ifdef GCC_FORMAT_NONLITERAL_CHECKING_ENABLED
1439 #pragma GCC diagnostic push
1440 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
1442 date_len += snprintf(&date_s[date_len], max-date_len,
1444 #ifdef GCC_FORMAT_NONLITERAL_CHECKING_ENABLED
1445 #pragma GCC diagnostic pop
1451 return (date_len == 0)?NULL:strdup(date_s);
#define CRM_CHECK(expr, failure_action)
void crm_time_add_years(crm_time_t *dt, int value)
void crm_time_add_seconds(crm_time_t *dt, int value)
#define crm_time_log_timeofday
struct crm_time_s crm_time_t
gboolean check_for_ordinal(const char *str)
crm_time_period_t * crm_time_parse_period(const char *period_str)
int crm_time_weeks_in_year(int year)
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)
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)
crm_time_t * parse_date(const char *date_str)
#define do_cmp_field(l, r, field)
#define do_crm_log_alias(level, file, function, line, fmt, args...)
Log a message as if it came from a different code location.
#define crm_time_log_duration
char * strndup(const char *str, size_t len)
void crm_time_add_hours(crm_time_t *dt, int value)
crm_time_hr_t * crm_time_hr_new(const char *date_time)
void crm_time_add_weeks(crm_time_t *dt, int value)
bool crm_time_leapyear(int year)
crm_time_t * crm_time_calculate_duration(crm_time_t *dt, crm_time_t *value)
void crm_time_add_months(crm_time_t *dt, int value)
#define crm_trace(fmt, args...)
void crm_time_set_timet(crm_time_t *target, time_t *source)
long long int crm_time_get_seconds_since_epoch(crm_time_t *dt)
void crm_time_add_minutes(crm_time_t *dt, int value)
void crm_time_hr_free(crm_time_hr_t *hr_dt)
#define crm_time_log(level, prefix, dt, flags)
void crm_time_set_hr_dt(crm_time_t *target, crm_time_hr_t *hr_dt)
int crm_time_january1_weekday(int year)
#define crm_time_log_with_timezone
long long int crm_time_get_seconds(crm_time_t *dt)
crm_time_t * crm_time_add(crm_time_t *dt, crm_time_t *value)
#define HAVE_STRUCT_TM_TM_GMTOFF
crm_time_hr_t * crm_time_hr_convert(crm_time_hr_t *target, crm_time_t *dt)
crm_time_hr_t * crm_time_timeval_hr_convert(crm_time_hr_t *target, struct timeval *tv)
int crm_time_get_gregorian(crm_time_t *dt, uint32_t *y, uint32_t *m, uint32_t *d)
#define crm_err(fmt, args...)
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)
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)
crm_time_t * crm_time_new(const char *string)
int crm_time_compare(crm_time_t *dt, crm_time_t *rhs)
bool crm_time_check(crm_time_t *dt)
crm_time_t * crm_time_subtract(crm_time_t *dt, crm_time_t *value)
char * crm_time_as_string(crm_time_t *dt, int flags)
#define safe_str_eq(a, b)
int crm_time_get_isoweek(crm_time_t *dt, uint32_t *y, uint32_t *w, uint32_t *d)
#define crm_time_log_date
void crm_time_add_days(crm_time_t *dt, int value)
int crm_time_days_in_month(int month, int year)
void crm_time_free(crm_time_t *dt)
struct crm_time_us crm_time_hr_t