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);
410 char *offset_s = NULL;
411 char *result_s = NULL;
415 if (date_time == NULL) {
420 utc = crm_get_utc_time(date_time);
428 uint h = 0, m = 0, s = 0;
429 int offset = 0, max = 128;
431 date_s = calloc(1, max+1);
432 crm_time_get_sec(dt->seconds, &h, &m, &s);
434 if (date_s == NULL) {
439 offset += snprintf(date_s+offset, max-offset,
"%4d year%s ", dt->years, dt->years>1?
"s":
"");
442 offset += snprintf(date_s+offset, max-offset,
"%2d month%s ", dt->months, dt->months>1?
"s":
"");
445 offset += snprintf(date_s+offset, max-offset,
"%2d day%s ", dt->days, dt->days>1?
"s":
"");
448 offset += snprintf(date_s+offset, max-offset,
"%d seconds ( ", dt->seconds);
450 offset += snprintf(date_s+offset, max-offset,
"%d hour%s ", h, h>1?
"s":
"");
453 offset += snprintf(date_s+offset, max-offset,
"%d minute%s ", m, m>1?
"s":
"");
456 offset += snprintf(date_s+offset, max-offset,
"%d second%s ", s, s>1?
"s":
"");
458 offset += snprintf(date_s+offset, max-offset,
")");
464 date_s = calloc(1, 32);
465 if (date_s == NULL) {
471 snprintf(date_s, 31,
"%lld", s);
477 snprintf(date_s, 31,
"%lld", s);
485 snprintf(date_s, 31,
"%d-W%.2d-%d", y, w, d);
493 snprintf(date_s, 31,
"%d-%.3d", y, d);
501 snprintf(date_s, 31,
"%.4d-%.2d-%.2d", y, m, d);
509 time_s = calloc(1, 32);
510 if (time_s == NULL) {
515 snprintf(time_s, 31,
"%.2d:%.2d:%.2d", h, m, s);
518 if (dt->offset != 0) {
519 crm_time_get_sec(dt->offset, &h, &m, &s);
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");
528 snprintf(offset_s, 31,
" %c%.2d:%.2d", dt->offset < 0 ?
'-' :
'+', h, m);
533 result_s = calloc(1, 100);
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 :
"");
549 crm_time_parse_sec(
const char *time_str)
556 rc = sscanf(time_str,
"%d:%d:%d", &hour, &minute, &second);
558 rc = sscanf(time_str,
"%2d%2d%2d", &hour, &minute, &second);
561 if (rc > 0 && rc < 4) {
562 crm_trace(
"Got valid time: %.2d:%.2d:%.2d", hour, minute, second);
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);
570 second += (minute * 60);
571 second += (hour * 60 * 60);
574 crm_err(
"Bad time: %s (%d)", time_str, rc);
580 crm_time_parse_offset(
const char *offset_str)
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);
590 int h_offset =
GMTOFF(now_tm) / (3600);
591 int m_offset = (
GMTOFF(now_tm) - (3600 * h_offset)) / (60);
593 if (h_offset < 0 && m_offset < 0) {
594 m_offset = 0 - m_offset;
596 offset += (60 * 60 * h_offset);
597 offset += (60 * m_offset);
599 }
else if (offset_str[0] ==
'Z') {
601 }
else if (offset_str[0] ==
'+' || offset_str[0] ==
'-' || isdigit((
int)offset_str[0])) {
602 gboolean negate = FALSE;
604 if (offset_str[0] ==
'-') {
608 offset = crm_time_parse_sec(offset_str);
617 crm_time_parse(
const char *time_str,
crm_time_t * a_time)
620 char *offset_s = NULL;
624 if (a_time == NULL) {
629 dt->seconds = crm_time_parse_sec(time_str);
631 offset_s = strstr(time_str,
"Z");
632 if (offset_s == NULL) {
633 offset_s = strstr(time_str,
" ");
638 while (isspace(offset_s[0])) {
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);
660 CRM_CHECK(date_str != NULL,
return NULL);
661 CRM_CHECK(strlen(date_str) > 0,
return NULL);
663 if (date_str[0] ==
'T' || date_str[2] ==
':') {
666 dt = crm_time_parse(date_str, dt);
681 rc = sscanf(date_str,
"%d-%d-%d", &year, &month, &day);
684 rc = sscanf(date_str,
"%4d%2d%2d", &year, &month, &day);
688 crm_err(
"Invalid month: %d", month);
689 }
else if (day > 31) {
690 crm_err(
"Invalid day: %d", day);
693 dt->days = get_ordinal_days(year, month, day);
694 crm_trace(
"Got gergorian date: %.4d-%.3d", year, dt->days);
700 rc = sscanf(date_str,
"%d-%d", &year, &day);
703 if (day > year_days(year)) {
704 crm_err(
"Invalid day: %d (max=%d)", day, year_days(year));
713 rc = sscanf(date_str,
"%d-W%d-%d", &year, &week, &day);
718 }
else if (day < 1 || day > 7) {
719 crm_err(
"Invalid day: %d", day);
751 crm_err(
"Couldn't parse %s", date_str);
754 time_s = strstr(date_str,
" ");
755 if (time_s == NULL) {
756 time_s = strstr(date_str,
"T");
761 crm_time_parse(time_s, dt);
772 parse_int(
const char *str,
int field_width,
int uppper_bound,
int *result)
776 int intermediate = 0;
777 gboolean fraction = FALSE;
778 gboolean negate = FALSE;
785 if (strlen(str) <= 0) {
789 if (str[offset] ==
'T') {
793 if (str[offset] ==
'.' || str[offset] ==
',') {
797 }
else if (str[offset] ==
'-') {
800 }
else if (str[offset] ==
'+' || str[offset] ==
':') {
804 for (; (fraction || lpc < field_width) && isdigit((
int)str[offset]); lpc++) {
806 intermediate = (str[offset] -
'0') / (10 ^ lpc);
809 intermediate = str[offset] -
'0';
811 *result += intermediate;
815 *result = (int)(*result * uppper_bound);
817 }
else if (uppper_bound > 0 && *result > uppper_bound) {
818 *result = uppper_bound;
821 *result = 0 - *result;
824 crm_trace(
"Found int: %d. Stopped at str[%d]='%c'", *result, lpc, str[lpc]);
833 gboolean is_time = FALSE;
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);
843 while (isspace((
int)interval_str[0]) == FALSE) {
847 if (interval_str[0] ==
'T') {
852 rc = parse_int(interval_str, 10, 0, &an_int);
858 ch = interval_str[0];
861 crm_trace(
"Testing %c=%d, rc=%d", ch, an_int, rc);
868 diff->years = an_int;
873 diff->seconds += an_int * 60;
875 diff->months = an_int;
879 diff->days += an_int * 7;
882 diff->days += an_int;
885 diff->seconds += an_int * 60 * 60;
888 diff->seconds += an_int;
905 gboolean invalid = FALSE;
906 const char *original = period_str;
909 CRM_CHECK(period_str != NULL,
return NULL);
910 CRM_CHECK(strlen(period_str) > 0,
return NULL);
915 if (period_str[0] ==
'P') {
921 period_str = strstr(original,
"/");
923 CRM_CHECK(period_str[0] ==
'/', invalid = TRUE;
927 if (period_str[0] ==
'P') {
933 }
else if (period->
diff != NULL) {
939 CRM_CHECK(period_str != NULL,
goto bail);
943 if (period->
start == NULL && period->
end == NULL) {
944 crm_err(
"Invalid time period: %s", original);
947 }
else if (period->
start == NULL && period->
diff == NULL) {
948 crm_err(
"Invalid time period: %s", original);
951 }
else if (period->
end == NULL && period->
diff == NULL) {
952 crm_err(
"Invalid time period: %s", original);
964 if (period->
end == NULL && period->
diff == NULL) {
967 if (period->
start == NULL) {
970 }
else if (period->
end == NULL) {
983 crm_trace(
"target=%p, source=%p", target, source);
985 CRM_CHECK(target != NULL && source != NULL,
return);
987 target->years = source->years;
988 target->days = source->days;
989 target->months = source->months;
990 target->seconds = source->seconds;
991 target->offset = source->offset;
1000 ha_set_tm_time(
crm_time_t * target,
struct tm *source)
1009 target->seconds = 0;
1011 target->duration = FALSE;
1013 if (source->tm_year > 0) {
1015 target->years = 1900 + source->tm_year;
1018 if (source->tm_yday >= 0) {
1020 target->days = 1 + source->tm_yday;
1023 if (source->tm_hour >= 0) {
1024 target->seconds += 60 * 60 * source->tm_hour;
1026 if (source->tm_min >= 0) {
1027 target->seconds += 60 * source->tm_min;
1029 if (source->tm_sec >= 0) {
1030 target->seconds += source->tm_sec;
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);
1038 target->offset += 60 * 60 * h_offset;
1039 target->offset += 60 * m_offset;
1045 ha_set_tm_time(target, localtime(source));
1054 CRM_CHECK(dt != NULL && value != NULL,
return NULL);
1059 utc = crm_get_utc_time(value);
1061 answer->years += utc->years;
1076 CRM_CHECK(dt != NULL && value != NULL,
return NULL);
1078 utc = crm_get_utc_time(value);
1079 answer = crm_get_utc_time(dt);
1080 answer->duration = TRUE;
1082 answer->years -= utc->years;
1083 if(utc->months != 0) {
1099 CRM_CHECK(dt != NULL && value != NULL,
return NULL);
1103 utc = crm_get_utc_time(value);
1105 answer->years -= utc->years;
1106 if(utc->months != 0) {
1122 ydays = year_days(dt->years);
1126 CRM_CHECK(dt->days <= ydays,
return FALSE);
1128 CRM_CHECK(dt->seconds >= 0,
return FALSE);
1129 CRM_CHECK(dt->seconds < 24 * 60 * 60,
return FALSE);
1134 #define do_cmp_field(l, r, field) \ 1136 if(l->field > r->field) { \ 1137 crm_trace("%s: %d > %d", \ 1138 #field, l->field, r->field); \ 1140 } else if(l->field < r->field) { \ 1141 crm_trace("%s: %d < %d", \ 1142 #field, l->field, r->field); \ 1154 if (a == NULL && b == NULL) {
1156 }
else if (a == NULL) {
1158 }
else if (b == NULL) {
1162 t1 = crm_get_utc_time(a);
1163 t2 = crm_get_utc_time(b);
1178 int seconds = 24 * 60 * 60;
1180 crm_trace(
"Adding %d seconds to %d (max=%d)", extra, a_time->seconds, seconds);
1182 a_time->seconds += extra;
1183 while (a_time->seconds >= seconds) {
1184 a_time->seconds -= seconds;
1188 while (a_time->seconds < 0) {
1189 a_time->seconds += seconds;
1198 int lower_bound = 1;
1201 crm_trace(
"Adding %d days to %.4d-%.3d", extra, a_time->years, a_time->days);
1203 a_time->days += extra;
1204 while (a_time->days > ydays) {
1206 a_time->days -= ydays;
1210 if(a_time->duration) {
1214 while (a_time->days < lower_bound) {
1227 crm_trace(
"Adding %d months to %.4d-%.2d-%.2d", extra, y, m, d);
1230 for (lpc = extra; lpc > 0; lpc--) {
1238 for (lpc = -extra; lpc > 0; lpc--) {
1253 crm_trace(
"Calculated %.4d-%.2d-%.2d", y, m, d);
1256 a_time->days = get_ordinal_days(y, m, d);
1259 crm_trace(
"Got %.4d-%.2d-%.2d", y, m, d);
1283 a_time->years += extra;
1287 ha_get_tm_time(
struct tm *target,
crm_time_t *source)
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,
1298 .tm_gmtoff = source->offset
1314 .months = dt->months,
1316 .seconds = dt->seconds,
1317 .offset = dt->offset,
1318 .duration = dt->duration
1331 .years = hr_dt->
years,
1333 .days = hr_dt->
days,
1358 struct timeval tv_now;
1361 if (gettimeofday(&tv_now, NULL) == 0) {
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;
1394 ha_get_tm_time(&tm, &dt);
1395 sprintf(nano_s,
"%06d000", hr_dt->
useconds);
1397 while ((format[scanned_pos]) !=
'\0') {
1399 mark_s = strchr(&format[scanned_pos],
'%');
1401 fmt_pos = mark_s - format;
1403 while ((format[fmt_pos+fmt_len] !=
'\0') &&
1404 (format[fmt_pos+fmt_len] >=
'0') &&
1405 (format[fmt_pos+fmt_len] <=
'9')) {
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);
1415 if (format[scanned_pos] !=
'\0') {
1418 fmt_pos = scanned_pos;
1421 scanned_pos = strlen(format);
1422 fmt_pos = scanned_pos;
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" 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 1433 printed_pos = scanned_pos;
1436 #ifdef GCC_FORMAT_NONLITERAL_CHECKING_ENABLED 1437 #pragma GCC diagnostic push 1438 #pragma GCC diagnostic ignored "-Wformat-nonliteral" 1440 date_len += snprintf(&date_s[date_len], max-date_len,
1442 #ifdef GCC_FORMAT_NONLITERAL_CHECKING_ENABLED 1443 #pragma GCC diagnostic pop 1449 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