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 };
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] ==
'+') {
608 }
else if (offset_str[0] ==
'-') {
612 offset = crm_time_parse_sec(offset_str);
621 crm_time_parse(
const char *time_str,
crm_time_t * a_time)
624 char *offset_s = NULL;
628 if (a_time == NULL) {
633 dt->seconds = crm_time_parse_sec(time_str);
635 offset_s = strstr(time_str,
"Z");
636 if (offset_s == NULL) {
637 offset_s = strstr(time_str,
" ");
642 while (isspace(offset_s[0])) {
646 dt->offset = crm_time_parse_offset(offset_s);
647 crm_time_get_sec(dt->offset, &h, &m, &s);
648 crm_trace(
"Got tz: %c%2.d:%.2d", dt->offset < 0 ?
'-' :
'+', h, m);
664 CRM_CHECK(date_str != NULL,
return NULL);
665 CRM_CHECK(strlen(date_str) > 0,
return NULL);
667 if (date_str[0] ==
'T' || date_str[2] ==
':') {
670 dt = crm_time_parse(date_str, dt);
685 rc = sscanf(date_str,
"%d-%d-%d", &year, &month, &day);
688 rc = sscanf(date_str,
"%4d%2d%2d", &year, &month, &day);
692 crm_err(
"Invalid month: %d", month);
693 }
else if (day > 31) {
694 crm_err(
"Invalid day: %d", day);
697 dt->days = get_ordinal_days(year, month, day);
698 crm_trace(
"Got gergorian date: %.4d-%.3d", year, dt->days);
704 rc = sscanf(date_str,
"%d-%d", &year, &day);
707 if (day > year_days(year)) {
708 crm_err(
"Invalid day: %d (max=%d)", day, year_days(year));
717 rc = sscanf(date_str,
"%d-W%d-%d", &year, &week, &day);
722 }
else if (day < 1 || day > 7) {
723 crm_err(
"Invalid day: %d", day);
755 crm_err(
"Couldn't parse %s", date_str);
758 time_s = strstr(date_str,
" ");
759 if (time_s == NULL) {
760 time_s = strstr(date_str,
"T");
765 crm_time_parse(time_s, dt);
776 parse_int(
const char *str,
int field_width,
int uppper_bound,
int *result)
780 int intermediate = 0;
781 gboolean fraction = FALSE;
782 gboolean negate = FALSE;
789 if (strlen(str) <= 0) {
793 if (str[offset] ==
'T') {
797 if (str[offset] ==
'.' || str[offset] ==
',') {
801 }
else if (str[offset] ==
'-') {
804 }
else if (str[offset] ==
'+' || str[offset] ==
':') {
808 for (; (fraction || lpc < field_width) && isdigit((
int)str[offset]); lpc++) {
810 intermediate = (str[offset] -
'0') / (10 ^ lpc);
813 intermediate = str[offset] -
'0';
815 *result += intermediate;
819 *result = (int)(*result * uppper_bound);
821 }
else if (uppper_bound > 0 && *result > uppper_bound) {
822 *result = uppper_bound;
825 *result = 0 - *result;
828 crm_trace(
"Found int: %d. Stopped at str[%d]='%c'", *result, lpc, str[lpc]);
837 gboolean is_time = FALSE;
840 CRM_CHECK(interval_str != NULL,
goto bail);
841 CRM_CHECK(strlen(interval_str) > 0,
goto bail);
842 CRM_CHECK(interval_str[0] ==
'P',
goto bail);
847 while (isspace((
int)interval_str[0]) == FALSE) {
851 if (interval_str[0] ==
'T') {
856 rc = parse_int(interval_str, 10, 0, &an_int);
862 ch = interval_str[0];
865 crm_trace(
"Testing %c=%d, rc=%d", ch, an_int, rc);
872 diff->years = an_int;
877 diff->seconds += an_int * 60;
879 diff->months = an_int;
883 diff->days += an_int * 7;
886 diff->days += an_int;
889 diff->seconds += an_int * 60 * 60;
892 diff->seconds += an_int;
909 gboolean invalid = FALSE;
910 const char *original = period_str;
913 CRM_CHECK(period_str != NULL,
return NULL);
914 CRM_CHECK(strlen(period_str) > 0,
return NULL);
919 if (period_str[0] ==
'P') {
925 period_str = strstr(original,
"/");
927 CRM_CHECK(period_str[0] ==
'/', invalid = TRUE;
931 if (period_str[0] ==
'P') {
937 }
else if (period->
diff != NULL) {
943 CRM_CHECK(period_str != NULL,
goto bail);
947 if (period->
start == NULL && period->
end == NULL) {
948 crm_err(
"Invalid time period: %s", original);
951 }
else if (period->
start == NULL && period->
diff == NULL) {
952 crm_err(
"Invalid time period: %s", original);
955 }
else if (period->
end == NULL && period->
diff == NULL) {
956 crm_err(
"Invalid time period: %s", original);
968 if (period->
end == NULL && period->
diff == NULL) {
971 if (period->
start == NULL) {
974 }
else if (period->
end == NULL) {
987 crm_trace(
"target=%p, source=%p", target, source);
989 CRM_CHECK(target != NULL && source != NULL,
return);
991 target->years = source->years;
992 target->days = source->days;
993 target->months = source->months;
994 target->seconds = source->seconds;
995 target->offset = source->offset;
1004 ha_set_tm_time(
crm_time_t * target,
struct tm *source)
1013 target->seconds = 0;
1015 target->duration = FALSE;
1017 if (source->tm_year > 0) {
1019 target->years = 1900 + source->tm_year;
1022 if (source->tm_yday >= 0) {
1024 target->days = 1 + source->tm_yday;
1027 if (source->tm_hour >= 0) {
1028 target->seconds += 60 * 60 * source->tm_hour;
1030 if (source->tm_min >= 0) {
1031 target->seconds += 60 * source->tm_min;
1033 if (source->tm_sec >= 0) {
1034 target->seconds += source->tm_sec;
1038 h_offset =
GMTOFF(source) / (3600);
1039 m_offset = (
GMTOFF(source) - (3600 * h_offset)) / (60);
1040 crm_trace(
"Offset (s): %ld, offset (hh:mm): %.2d:%.2d",
GMTOFF(source), h_offset, m_offset);
1042 target->offset += 60 * 60 * h_offset;
1043 target->offset += 60 * m_offset;
1049 ha_set_tm_time(target, localtime(source));
1058 CRM_CHECK(dt != NULL && value != NULL,
return NULL);
1063 utc = crm_get_utc_time(value);
1065 answer->years += utc->years;
1080 CRM_CHECK(dt != NULL && value != NULL,
return NULL);
1082 utc = crm_get_utc_time(value);
1083 answer = crm_get_utc_time(dt);
1084 answer->duration = TRUE;
1086 answer->years -= utc->years;
1087 if(utc->months != 0) {
1103 CRM_CHECK(dt != NULL && value != NULL,
return NULL);
1107 utc = crm_get_utc_time(value);
1109 answer->years -= utc->years;
1110 if(utc->months != 0) {
1126 ydays = year_days(dt->years);
1130 CRM_CHECK(dt->days <= ydays,
return FALSE);
1132 CRM_CHECK(dt->seconds >= 0,
return FALSE);
1133 CRM_CHECK(dt->seconds < 24 * 60 * 60,
return FALSE);
1138 #define do_cmp_field(l, r, field) \ 1140 if(l->field > r->field) { \ 1141 crm_trace("%s: %d > %d", \ 1142 #field, l->field, r->field); \ 1144 } else if(l->field < r->field) { \ 1145 crm_trace("%s: %d < %d", \ 1146 #field, l->field, r->field); \ 1158 if (a == NULL && b == NULL) {
1160 }
else if (a == NULL) {
1162 }
else if (b == NULL) {
1166 t1 = crm_get_utc_time(a);
1167 t2 = crm_get_utc_time(b);
1182 int seconds = 24 * 60 * 60;
1184 crm_trace(
"Adding %d seconds to %d (max=%d)", extra, a_time->seconds, seconds);
1186 a_time->seconds += extra;
1187 while (a_time->seconds >= seconds) {
1188 a_time->seconds -= seconds;
1192 while (a_time->seconds < 0) {
1193 a_time->seconds += seconds;
1202 int lower_bound = 1;
1205 crm_trace(
"Adding %d days to %.4d-%.3d", extra, a_time->years, a_time->days);
1207 a_time->days += extra;
1208 while (a_time->days > ydays) {
1210 a_time->days -= ydays;
1214 if(a_time->duration) {
1218 while (a_time->days < lower_bound) {
1231 crm_trace(
"Adding %d months to %.4d-%.2d-%.2d", extra, y, m, d);
1234 for (lpc = extra; lpc > 0; lpc--) {
1242 for (lpc = -extra; lpc > 0; lpc--) {
1257 crm_trace(
"Calculated %.4d-%.2d-%.2d", y, m, d);
1260 a_time->days = get_ordinal_days(y, m, d);
1263 crm_trace(
"Got %.4d-%.2d-%.2d", y, m, d);
1287 a_time->years += extra;
1291 ha_get_tm_time(
struct tm *target,
crm_time_t *source)
1293 *target = (
struct tm) {
1294 .tm_year = source->years - 1900,
1295 .tm_mday = source->days,
1296 .tm_sec = source->seconds % 60,
1297 .tm_min = ( source->seconds / 60 ) % 60,
1298 .tm_hour = source->seconds / 60 / 60,
1302 .tm_gmtoff = source->offset
1318 .months = dt->months,
1320 .seconds = dt->seconds,
1321 .offset = dt->offset,
1322 .duration = dt->duration
1335 .years = hr_dt->
years,
1337 .days = hr_dt->
days,
1362 struct timeval tv_now;
1365 if (gettimeofday(&tv_now, NULL) == 0) {
1388 int max = 128, scanned_pos = 0, printed_pos = 0, fmt_pos = 0,
1389 date_len = 0, nano_digits = 0;
1390 char nano_s[10], date_s[max+1], nanofmt_s[5] =
"%", *tmp_fmt_s;
1398 ha_get_tm_time(&tm, &dt);
1399 sprintf(nano_s,
"%06d000", hr_dt->
useconds);
1401 while ((format[scanned_pos]) !=
'\0') {
1402 mark_s = strchr(&format[scanned_pos],
'%');
1406 fmt_pos = mark_s - format;
1407 while ((format[fmt_pos+fmt_len] !=
'\0') &&
1408 (format[fmt_pos+fmt_len] >=
'0') &&
1409 (format[fmt_pos+fmt_len] <=
'9')) {
1412 scanned_pos = fmt_pos + fmt_len + 1;
1413 if (format[fmt_pos+fmt_len] ==
'N') {
1414 nano_digits = atoi(&format[fmt_pos+1]);
1415 nano_digits = (nano_digits > 6)?6:nano_digits;
1416 nano_digits = (nano_digits < 0)?0:nano_digits;
1417 sprintf(&nanofmt_s[1],
".%ds", nano_digits);
1419 if (format[scanned_pos] !=
'\0') {
1422 fmt_pos = scanned_pos;
1425 scanned_pos = strlen(format);
1426 fmt_pos = scanned_pos;
1428 tmp_fmt_s =
strndup(&format[printed_pos], fmt_pos - printed_pos);
1429 #ifdef GCC_FORMAT_NONLITERAL_CHECKING_ENABLED 1430 #pragma GCC diagnostic push 1431 #pragma GCC diagnostic ignored "-Wformat-nonliteral" 1433 date_len += strftime(&date_s[date_len], max-date_len, tmp_fmt_s, &tm);
1434 #ifdef GCC_FORMAT_NONLITERAL_CHECKING_ENABLED 1435 #pragma GCC diagnostic pop 1437 printed_pos = scanned_pos;
1440 #ifdef GCC_FORMAT_NONLITERAL_CHECKING_ENABLED 1441 #pragma GCC diagnostic push 1442 #pragma GCC diagnostic ignored "-Wformat-nonliteral" 1444 date_len += snprintf(&date_s[date_len], max-date_len,
1446 #ifdef GCC_FORMAT_NONLITERAL_CHECKING_ENABLED 1447 #pragma GCC diagnostic pop 1453 return (date_len == 0)?NULL:strdup(date_s);
#define CRM_CHECK(expr, failure_action)
bool crm_time_leapyear(int year)
crm_time_t * crm_time_parse_duration(const char *interval_str)
crm_time_t * crm_time_subtract(crm_time_t *dt, crm_time_t *value)
void crm_time_set_timet(crm_time_t *target, time_t *source)
crm_time_t * crm_time_add(crm_time_t *dt, crm_time_t *value)
#define crm_time_log_timeofday
crm_time_t * crm_time_new(const char *date_time)
crm_time_t * parse_date(const char *date_str)
int crm_time_compare(crm_time_t *a, crm_time_t *b)
struct crm_time_s crm_time_t
gboolean check_for_ordinal(const char *str)
void crm_time_add_minutes(crm_time_t *a_time, int extra)
void crm_time_add_weeks(crm_time_t *a_time, int extra)
void crm_time_free(crm_time_t *dt)
#define do_cmp_field(l, r, field)
crm_time_hr_t * crm_time_timeval_hr_convert(crm_time_hr_t *target, struct timeval *tv)
#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_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_period_t * crm_time_parse_period(const char *period_str)
int crm_time_get_gregorian(crm_time_t *dt, uint *y, uint *m, uint *d)
void crm_time_add_seconds(crm_time_t *a_time, int extra)
bool crm_time_check(crm_time_t *dt)
long long crm_time_get_seconds(crm_time_t *dt)
void crm_time_add_days(crm_time_t *a_time, int extra)
#define crm_trace(fmt, args...)
int crm_time_get_isoweek(crm_time_t *dt, uint *y, uint *w, uint *d)
void crm_time_add_hours(crm_time_t *a_time, int extra)
#define crm_time_log(level, prefix, dt, flags)
int crm_time_days_in_month(int month, int year)
#define crm_time_log_with_timezone
int crm_time_get_timezone(crm_time_t *dt, uint *h, uint *m)
void crm_time_add_years(crm_time_t *a_time, int extra)
char * crm_time_format_hr(const char *format, crm_time_hr_t *hr_dt)
crm_time_hr_t * crm_time_hr_new(const char *date_time)
#define HAVE_STRUCT_TM_TM_GMTOFF
long long crm_time_get_seconds_since_epoch(crm_time_t *dt)
void crm_time_hr_free(crm_time_hr_t *hr_dt)
#define crm_err(fmt, args...)
void crm_time_add_months(crm_time_t *a_time, int extra)
int crm_time_weeks_in_year(int year)
int crm_time_january1_weekday(int year)
crm_time_t * crm_time_calculate_duration(crm_time_t *dt, crm_time_t *value)
crm_time_hr_t * crm_time_hr_convert(crm_time_hr_t *target, crm_time_t *dt)
int crm_time_get_ordinal(crm_time_t *dt, uint *y, uint *d)
char * crm_time_as_string(crm_time_t *date_time, int flags)
void crm_time_set_hr_dt(crm_time_t *target, crm_time_hr_t *hr_dt)
#define safe_str_eq(a, b)
#define crm_time_log_date
int crm_time_get_timeofday(crm_time_t *dt, uint *h, uint *m, uint *s)
void crm_time_set(crm_time_t *target, crm_time_t *source)
struct crm_time_us crm_time_hr_t