42 #if defined(HAVE_STRUCT_TM_TM_GMTOFF) 43 # define GMTOFF(tm) ((tm)->tm_gmtoff) 46 # define GMTOFF(tm) (-timezone+daylight) 68 utc->years = dt->years;
70 utc->seconds = dt->seconds;
77 utc->months = dt->months;
94 if (date_time == NULL) {
135 int YY = (year - 1) % 100;
136 int C = (year - 1) - YY;
138 int jan1 = 1 + (((((C / 100) % 4) * 5) + G) % 7);
140 crm_trace(
"YY=%d, C=%d, G=%d", YY, C, G);
141 crm_trace(
"January 1 %.4d: %d", year, jan1);
165 int month_days[14] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 29 };
179 gboolean is_leap = FALSE;
184 if (year % 100 == 0 && year % 400 != 0) {
195 for (lpc = 1; lpc < m; lpc++) {
207 if (log_level < LOG_CRIT) {
209 prefix ? prefix :
"", prefix ?
": " :
"", date_s ? date_s :
"__invalid_date__");
212 prefix ? prefix :
"", prefix ?
": " :
"",
213 date_s ? date_s :
"__invalid_date__");
219 crm_time_get_sec(
int sec, uint * h, uint * m, uint * s)
221 uint hours, minutes, seconds;
229 hours = seconds / (60 * 60);
230 seconds -= 60 * 60 * hours;
232 minutes = seconds / (60);
233 seconds -= 60 * minutes;
235 crm_trace(
"%d == %.2d:%.2d:%.2d", sec, hours, minutes, seconds);
247 return crm_time_get_sec(dt->seconds, h, m, s);
255 return crm_time_get_sec(dt->seconds, h, m, &s);
263 long long in_seconds = 0;
265 utc = crm_get_utc_time(dt);
267 for (lpc = 1; lpc < utc->years; lpc++) {
268 int dmax = year_days(lpc);
270 in_seconds += 60 * 60 * 24 * dmax;
280 if (utc->months > 0) {
281 in_seconds += 60 * 60 * 24 * 30 * utc->months;
285 in_seconds += 60 * 60 * 24 * (utc->days - 1);
287 in_seconds += utc->seconds;
293 #define EPOCH_SECONDS 62135596800ULL 307 for (months = 1; months <= 12 && days > 0; months++) {
317 }
else if (dt->months) {
328 crm_trace(
"%.4d-%.3d -> %.4d-%.2d-%.2d", dt->years, dt->days, dt->years, months, days);
354 h = dt->days + jan1 - 1;
355 *d = 1 + ((h - 1) % 7);
358 if (dt->days <= (8 - jan1) && jan1 > 4) {
360 year_num = dt->years - 1;
364 year_num = dt->years;
368 if (year_num == dt->years) {
369 int dmax = year_days(year_num);
370 int correction = 4 - *d;
372 if ((dmax - dt->days) < correction) {
373 crm_trace(
"year++, jan1=%d, i=%d vs. %d", jan1, dmax - dt->days, correction);
374 year_num = dt->years + 1;
380 if (year_num == dt->years) {
381 int j = dt->days + (7 - *d) + (jan1 - 1);
390 crm_trace(
"Converted %.4d-%.3d to %.4d-W%.2d-%d", dt->years, dt->days, *y, *w, *d);
401 char *offset_s = NULL;
402 char *result_s = NULL;
406 if (date_time == NULL) {
411 utc = crm_get_utc_time(date_time);
419 uint h = 0, m = 0, s = 0;
423 crm_time_get_sec(dt->seconds, &h, &m, &s);
425 if (date_s == NULL) {
430 offset += snprintf(date_s+offset,
DATE_MAX - offset,
"%4d year%s ", dt->years, dt->years>1?
"s":
"");
433 offset += snprintf(date_s+offset,
DATE_MAX - offset,
"%2d month%s ", dt->months, dt->months>1?
"s":
"");
436 offset += snprintf(date_s+offset,
DATE_MAX - offset,
"%2d day%s ", dt->days, dt->days>1?
"s":
"");
439 offset += snprintf(date_s+offset,
DATE_MAX - offset,
"%d seconds ( ", dt->seconds);
441 offset += snprintf(date_s+offset,
DATE_MAX - offset,
"%u hour%s ", h, h>1?
"s":
"");
444 offset += snprintf(date_s+offset,
DATE_MAX - offset,
"%u minute%s ", m, m>1?
"s":
"");
447 offset += snprintf(date_s+offset,
DATE_MAX - offset,
"%u second%s ", s, s>1?
"s":
"");
449 offset += snprintf(date_s+offset,
DATE_MAX - offset,
")");
455 date_s = calloc(1, 34);
456 if (date_s == NULL) {
462 snprintf(date_s, 32,
"%lld", s);
468 snprintf(date_s, 32,
"%lld", s);
476 snprintf(date_s, 34,
"%u-W%.2u-%u", y, w, d);
484 snprintf(date_s, 22,
"%u-%.3u", y, d);
492 snprintf(date_s, 33,
"%.4u-%.2u-%.2u", y, m, d);
500 time_s = calloc(1, 33);
501 if (time_s == NULL) {
506 snprintf(time_s, 33,
"%.2u:%.2u:%.2u", h, m, s);
509 if (dt->offset != 0) {
510 crm_time_get_sec(dt->offset, &h, &m, &s);
513 offset_s = calloc(1, 31);
514 if ((flags & crm_time_log_with_timezone) == 0 || dt->offset == 0) {
515 crm_trace(
"flags %6x %6x", flags, crm_time_log_with_timezone);
516 snprintf(offset_s, 31,
"Z");
519 snprintf(offset_s, 24,
" %c%.2u:%.2u", dt->offset < 0 ?
'-' :
'+', h, m);
524 result_s = calloc(1, 100);
526 snprintf(result_s, 100,
"%s%s%s%s",
527 date_s ? date_s :
"", (date_s != NULL && time_s != NULL) ?
" " :
"",
528 time_s ? time_s :
"", offset_s ? offset_s :
"");
540 crm_time_parse_sec(
const char *time_str)
547 rc = sscanf(time_str,
"%d:%d:%d", &hour, &minute, &second);
549 rc = sscanf(time_str,
"%2d%2d%2d", &hour, &minute, &second);
552 if (rc > 0 && rc < 4) {
553 crm_trace(
"Got valid time: %.2d:%.2d:%.2d", hour, minute, second);
555 crm_err(
"Invalid hour: %d", hour);
556 }
else if (minute >= 60) {
557 crm_err(
"Invalid minute: %d", minute);
558 }
else if (second >= 60) {
559 crm_err(
"Invalid second: %d", second);
561 second += (minute * 60);
562 second += (hour * 60 * 60);
565 crm_err(
"Bad time: %s (%d)", time_str, rc);
571 crm_time_parse_offset(
const char *offset_str)
576 if (offset_str == NULL) {
577 #if defined(HAVE_STRUCT_TM_TM_GMTOFF) 578 time_t now = time(NULL);
579 struct tm *now_tm = localtime(&now);
581 int h_offset =
GMTOFF(now_tm) / (3600);
582 int m_offset = (
GMTOFF(now_tm) - (3600 * h_offset)) / (60);
584 if (h_offset < 0 && m_offset < 0) {
585 m_offset = 0 - m_offset;
587 offset += (60 * 60 * h_offset);
588 offset += (60 * m_offset);
590 }
else if (offset_str[0] ==
'Z') {
592 }
else if (offset_str[0] ==
'+' || offset_str[0] ==
'-' || isdigit((
int)offset_str[0])) {
593 gboolean negate = FALSE;
595 if (offset_str[0] ==
'-') {
599 offset = crm_time_parse_sec(offset_str);
608 crm_time_parse(
const char *time_str,
crm_time_t * a_time)
611 char *offset_s = NULL;
615 if (a_time == NULL) {
620 dt->seconds = crm_time_parse_sec(time_str);
622 offset_s = strstr(time_str,
"Z");
623 if (offset_s == NULL) {
624 offset_s = strstr(time_str,
" ");
629 while (isspace(offset_s[0])) {
633 dt->offset = crm_time_parse_offset(offset_s);
634 crm_time_get_sec(dt->offset, &h, &m, &s);
635 crm_trace(
"Got tz: %c%2.d:%.2d", dt->offset < 0 ?
'-' :
'+', h, m);
651 CRM_CHECK(date_str != NULL,
return NULL);
652 CRM_CHECK(strlen(date_str) > 0,
return NULL);
654 if (date_str[0] ==
'T' || date_str[2] ==
':') {
657 dt = crm_time_parse(date_str, dt);
672 rc = sscanf(date_str,
"%d-%d-%d", &year, &month, &day);
675 rc = sscanf(date_str,
"%4d%2d%2d", &year, &month, &day);
679 crm_err(
"Invalid month: %d", month);
680 }
else if (day > 31) {
681 crm_err(
"Invalid day: %d", day);
684 dt->days = get_ordinal_days(year, month, day);
685 crm_trace(
"Got gergorian date: %.4d-%.3d", year, dt->days);
691 rc = sscanf(date_str,
"%d-%d", &year, &day);
694 if (day > year_days(year)) {
695 crm_err(
"Invalid day: %d (max=%d)", day, year_days(year));
704 rc = sscanf(date_str,
"%d-W%d-%d", &year, &week, &day);
709 }
else if (day < 1 || day > 7) {
710 crm_err(
"Invalid day: %d", day);
742 crm_err(
"Couldn't parse %s", date_str);
745 time_s = strstr(date_str,
" ");
746 if (time_s == NULL) {
747 time_s = strstr(date_str,
"T");
752 crm_time_parse(time_s, dt);
763 parse_int(
const char *str,
int field_width,
int uppper_bound,
int *result)
767 int intermediate = 0;
768 gboolean fraction = FALSE;
769 gboolean negate = FALSE;
780 if (str[offset] ==
'T') {
784 if (str[offset] ==
'.' || str[offset] ==
',') {
788 }
else if (str[offset] ==
'-') {
791 }
else if (str[offset] ==
'+' || str[offset] ==
':') {
795 for (; (fraction || lpc < field_width) && isdigit((
int)str[offset]); lpc++) {
797 intermediate = (str[offset] -
'0') / (10 ^ lpc);
800 intermediate = str[offset] -
'0';
802 *result += intermediate;
806 *result = (int)(*result * uppper_bound);
808 }
else if (uppper_bound > 0 && *result > uppper_bound) {
809 *result = uppper_bound;
812 *result = 0 - *result;
815 crm_trace(
"Found int: %d. Stopped at str[%d]='%c'", *result, lpc, str[lpc]);
824 gboolean is_time = FALSE;
828 CRM_CHECK(strlen(period_s) > 0,
goto bail);
829 CRM_CHECK(period_s[0] ==
'P',
goto bail);
834 while (isspace((
int)period_s[0]) == FALSE) {
838 if (period_s[0] ==
'T') {
843 rc = parse_int(period_s, 10, 0, &an_int);
852 crm_trace(
"Testing %c=%d, rc=%d", ch, an_int, rc);
859 diff->years = an_int;
864 diff->seconds += an_int * 60;
866 diff->months = an_int;
870 diff->days += an_int * 7;
873 diff->days += an_int;
876 diff->seconds += an_int * 60 * 60;
879 diff->seconds += an_int;
896 gboolean invalid = FALSE;
897 const char *original = period_str;
900 CRM_CHECK(period_str != NULL,
return NULL);
901 CRM_CHECK(strlen(period_str) > 0,
return NULL);
906 if (period_str[0] ==
'P') {
912 period_str = strstr(original,
"/");
914 CRM_CHECK(period_str[0] ==
'/', invalid = TRUE;
918 if (period_str[0] ==
'P') {
924 }
else if (period->
diff != NULL) {
930 CRM_CHECK(period_str != NULL,
goto bail);
934 if (period->
start == NULL && period->
end == NULL) {
935 crm_err(
"Invalid time period: %s", original);
938 }
else if (period->
start == NULL && period->
diff == NULL) {
939 crm_err(
"Invalid time period: %s", original);
942 }
else if (period->
end == NULL && period->
diff == NULL) {
943 crm_err(
"Invalid time period: %s", original);
955 if (period->
end == NULL && period->
diff == NULL) {
958 if (period->
start == NULL) {
961 }
else if (period->
end == NULL) {
974 crm_trace(
"target=%p, source=%p", target, source);
976 CRM_CHECK(target != NULL && source != NULL,
return);
978 target->years = source->years;
979 target->days = source->days;
980 target->months = source->months;
981 target->seconds = source->seconds;
982 target->offset = source->offset;
991 ha_set_tm_time(
crm_time_t * target,
struct tm *source)
1000 target->seconds = 0;
1002 target->duration = FALSE;
1004 if (source->tm_year > 0) {
1006 target->years = 1900 + source->tm_year;
1009 if (source->tm_yday >= 0) {
1011 target->days = 1 + source->tm_yday;
1014 if (source->tm_hour >= 0) {
1015 target->seconds += 60 * 60 * source->tm_hour;
1017 if (source->tm_min >= 0) {
1018 target->seconds += 60 * source->tm_min;
1020 if (source->tm_sec >= 0) {
1021 target->seconds += source->tm_sec;
1025 h_offset =
GMTOFF(source) / (3600);
1026 m_offset = (
GMTOFF(source) - (3600 * h_offset)) / (60);
1027 crm_trace(
"Offset (s): %ld, offset (hh:mm): %.2d:%.2d",
GMTOFF(source), h_offset, m_offset);
1029 target->offset += 60 * 60 * h_offset;
1030 target->offset += 60 * m_offset;
1036 ha_set_tm_time(target, localtime(source));
1045 CRM_CHECK(dt != NULL && value != NULL,
return NULL);
1050 utc = crm_get_utc_time(value);
1052 answer->years += utc->years;
1067 CRM_CHECK(dt != NULL && value != NULL,
return NULL);
1069 utc = crm_get_utc_time(value);
1070 answer = crm_get_utc_time(dt);
1071 answer->duration = TRUE;
1073 answer->years -= utc->years;
1074 if(utc->months != 0) {
1090 CRM_CHECK(dt != NULL && value != NULL,
return NULL);
1094 utc = crm_get_utc_time(value);
1096 answer->years -= utc->years;
1097 if(utc->months != 0) {
1113 ydays = year_days(dt->years);
1117 CRM_CHECK(dt->days <= ydays,
return FALSE);
1119 CRM_CHECK(dt->seconds >= 0,
return FALSE);
1120 CRM_CHECK(dt->seconds < 24 * 60 * 60,
return FALSE);
1125 #define do_cmp_field(l, r, field) \ 1127 if(l->field > r->field) { \ 1128 crm_trace("%s: %d > %d", \ 1129 #field, l->field, r->field); \ 1131 } else if(l->field < r->field) { \ 1132 crm_trace("%s: %d < %d", \ 1133 #field, l->field, r->field); \ 1145 if (a == NULL && b == NULL) {
1147 }
else if (a == NULL) {
1149 }
else if (b == NULL) {
1153 t1 = crm_get_utc_time(a);
1154 t2 = crm_get_utc_time(b);
1169 int seconds = 24 * 60 * 60;
1171 crm_trace(
"Adding %d seconds to %d (max=%d)", extra, a_time->seconds, seconds);
1173 a_time->seconds += extra;
1174 while (a_time->seconds >= seconds) {
1175 a_time->seconds -= seconds;
1179 while (a_time->seconds < 0) {
1180 a_time->seconds += seconds;
1189 int lower_bound = 1;
1192 crm_trace(
"Adding %d days to %.4d-%.3d", extra, a_time->years, a_time->days);
1194 a_time->days += extra;
1195 while (a_time->days > ydays) {
1197 a_time->days -= ydays;
1201 if(a_time->duration) {
1205 while (a_time->days < lower_bound) {
1218 crm_trace(
"Adding %d months to %.4d-%.2d-%.2d", extra, y, m, d);
1221 for (lpc = extra; lpc > 0; lpc--) {
1229 for (lpc = -extra; lpc > 0; lpc--) {
1244 crm_trace(
"Calculated %.4d-%.2d-%.2d", y, m, d);
1247 a_time->days = get_ordinal_days(y, m, d);
1250 crm_trace(
"Got %.4d-%.2d-%.2d", y, m, d);
1274 a_time->years += extra;
1278 ha_get_tm_time(
struct tm *target,
crm_time_t *source)
1280 *target = (
struct tm) {
1281 .tm_year = source->years - 1900,
1282 .tm_mday = source->days,
1283 .tm_sec = source->seconds % 60,
1284 .tm_min = ( source->seconds / 60 ) % 60,
1285 .tm_hour = source->seconds / 60 / 60,
1289 .tm_gmtoff = source->offset
1305 .months = dt->months,
1307 .seconds = dt->seconds,
1308 .offset = dt->offset,
1309 .duration = dt->duration
1322 .years = hr_dt->
years,
1324 .days = hr_dt->
days,
1349 struct timeval tv_now;
1352 if (gettimeofday(&tv_now, NULL) == 0) {
1375 int max = 128, scanned_pos = 0, printed_pos = 0, fmt_pos = 0,
1376 date_len = 0, nano_digits = 0;
1377 char nano_s[10], date_s[max+1], nanofmt_s[5] =
"%", *tmp_fmt_s;
1385 ha_get_tm_time(&tm, &dt);
1386 sprintf(nano_s,
"%06d000", hr_dt->
useconds);
1388 while ((format[scanned_pos]) !=
'\0') {
1389 mark_s = strchr(&format[scanned_pos],
'%');
1393 fmt_pos = mark_s - format;
1394 while ((format[fmt_pos+fmt_len] !=
'\0') &&
1395 (format[fmt_pos+fmt_len] >=
'0') &&
1396 (format[fmt_pos+fmt_len] <=
'9')) {
1399 scanned_pos = fmt_pos + fmt_len + 1;
1400 if (format[fmt_pos+fmt_len] ==
'N') {
1401 nano_digits = atoi(&format[fmt_pos+1]);
1402 nano_digits = (nano_digits > 6)?6:nano_digits;
1403 nano_digits = (nano_digits < 0)?0:nano_digits;
1404 sprintf(&nanofmt_s[1],
".%ds", nano_digits);
1406 if (format[scanned_pos] !=
'\0') {
1409 fmt_pos = scanned_pos;
1412 scanned_pos = strlen(format);
1413 fmt_pos = scanned_pos;
1415 tmp_fmt_s =
strndup(&format[printed_pos], fmt_pos - printed_pos);
1416 #ifdef GCC_FORMAT_NONLITERAL_CHECKING_ENABLED 1417 #pragma GCC diagnostic push 1418 #pragma GCC diagnostic ignored "-Wformat-nonliteral" 1420 date_len += strftime(&date_s[date_len], max-date_len, tmp_fmt_s, &tm);
1421 #ifdef GCC_FORMAT_NONLITERAL_CHECKING_ENABLED 1422 #pragma GCC diagnostic pop 1424 printed_pos = scanned_pos;
1427 #ifdef GCC_FORMAT_NONLITERAL_CHECKING_ENABLED 1428 #pragma GCC diagnostic push 1429 #pragma GCC diagnostic ignored "-Wformat-nonliteral" 1431 date_len += snprintf(&date_s[date_len], max-date_len,
1433 #ifdef GCC_FORMAT_NONLITERAL_CHECKING_ENABLED 1434 #pragma GCC diagnostic pop 1440 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_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)
crm_time_t * crm_time_parse_duration(const char *period_s)
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