Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F1701932
iso8601.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
32 KB
Referenced Files
None
Subscribers
None
iso8601.c
View Options
/*
* Copyright (C) 2005 Andrew Beekhof <andrew@beekhof.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Primary reference:
* http://en.wikipedia.org/wiki/ISO_8601 (as at 2005-08-01)
*
* Secondary references:
* http://hydracen.com/dx/iso8601.htm
* http://www.personal.ecu.edu/mccartyr/ISOwdALG.txt
* http://www.personal.ecu.edu/mccartyr/isowdcal.html
* http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm
*
*/
#include <crm_internal.h>
#include <crm/crm.h>
#include <time.h>
#include <ctype.h>
#include <crm/common/iso8601.h>
gboolean gregorian_to_ordinal(ha_time_t *a_date);
gboolean ordinal_to_gregorian(ha_time_t *a_date);
gboolean ordinal_to_weekdays(ha_time_t *a_date);
void normalize_time(ha_time_t *a_time);
/*
* Andrew's code was originally written for OSes whose "struct tm" contains:
* long tm_gmtoff; :: Seconds east of UTC
* const char *tm_zone; :: Timezone abbreviation
* Some OSes lack these, instead having:
* time_t (or long) timezone;
:: "difference between UTC and local standard time"
* char *tzname[2] = { "...", "..." };
* I (David Lee) confess to not understanding the details. So my attempted
* generalisations for where their use is necessary may be flawed.
*
* 1. Does "difference between ..." subtract the same or opposite way?
* 2. Should it use "altzone" instead of "timezone"?
* 3. Should it use tzname[0] or tzname[1]? Interaction with timezone/altzone?
*/
#if defined(HAVE_STRUCT_TM_TM_GMTOFF)
#define GMTOFF(tm) ((tm)->tm_gmtoff)
#else
/* Note: extern variable; macro argument not actually used. */
#define GMTOFF(tm) (timezone)
#endif
char *
date_to_string(ha_time_t *date_time, int flags)
{
char *date_s = NULL;
char *time_s = NULL;
char *offset_s = NULL;
char *result_s = NULL;
ha_time_t *dt = NULL;
if(flags & ha_log_local) {
crm_debug_6("Local version");
dt = date_time;
} else {
dt = date_time->normalized;
}
CRM_CHECK(dt != NULL, return NULL);
if(flags & ha_log_date) {
crm_malloc0(date_s, 32);
if(date_s == NULL) {
return NULL;
} else if(flags & ha_date_weeks) {
snprintf(date_s, 31, "%d-W%.2d-%d",
dt->weekyears, dt->weeks, dt->weekdays);
} else if(flags & ha_date_ordinal) {
snprintf(date_s, 31, "%d-%.3d",dt->years, dt->yeardays);
} else {
snprintf(date_s, 31, "%.4d-%.2d-%.2d",
dt->years, dt->months, dt->days);
}
}
if(flags & ha_log_time) {
int offset = 0;
crm_malloc0(time_s, 32);
if(time_s == NULL) {
goto cleanup;
}
snprintf(time_s, 31, "%.2d:%.2d:%.2d",
dt->hours, dt->minutes, dt->seconds);
if(dt->offset != NULL) {
offset =(dt->offset->hours * 100) + dt->offset->minutes;
}
crm_malloc0(offset_s, 32);
if((flags & ha_log_local) == 0 || offset == 0) {
snprintf(offset_s, 31, "Z");
} else {
int hr = dt->offset->hours;
int mins = dt->offset->minutes;
if(hr < 0) {
hr = 0 - hr;
}
if(mins < 0) {
mins = 0 - mins;
}
snprintf(offset_s, 31, " %s%.2d:%.2d",
offset>0?"+":"-", hr, mins);
}
}
crm_malloc0(result_s, 100);
snprintf(result_s, 100, "%s%s%s%s",
date_s?date_s:"", (date_s!=NULL&&time_s!=NULL)?" ":"",
time_s?time_s:"", offset_s?offset_s:"");
cleanup:
crm_free(date_s);
crm_free(time_s);
crm_free(offset_s);
return result_s;
}
void
log_date(int log_level, const char *prefix, ha_time_t *date_time, int flags)
{
char *date_s = date_to_string(date_time, flags);
do_crm_log(log_level, "%s%s%s",
prefix?prefix:"", prefix?": ":"",
date_s?date_s:"__invalid_date__");
crm_free(date_s);
}
void
log_time_period(int log_level, ha_time_period_t *dtp, int flags)
{
log_date(log_level, "Period start:", dtp->start, flags);
log_date(log_level, "Period end:", dtp->end, flags);
}
ha_time_t*
parse_time_offset(char **offset_str)
{
ha_time_t *new_time = NULL;
crm_malloc0(new_time, sizeof(ha_time_t));
crm_malloc0(new_time->has, sizeof(ha_has_time_t));
if((*offset_str)[0] == 'Z') {
} else if((*offset_str)[0] == '+'
|| (*offset_str)[0] == '-'
|| isdigit((int) (*offset_str)[0])) {
gboolean negate = FALSE;
if((*offset_str)[0] == '-') {
negate = TRUE;
(*offset_str)++;
}
parse_time(offset_str, new_time, FALSE);
if(negate) {
new_time->hours = 0 - new_time->hours;
new_time->minutes = 0 - new_time->minutes;
new_time->seconds = 0 - new_time->seconds;
}
} else {
#if defined(HAVE_STRUCT_TM_TM_GMTOFF)
time_t now = time(NULL);
struct tm *now_tm = localtime(&now);
#endif
int h_offset = GMTOFF(now_tm) / (3600);
int m_offset = (GMTOFF(now_tm) - (3600 * h_offset)) / (60);
if(h_offset < 0 && m_offset < 0) {
m_offset = 0 - m_offset;
}
new_time->hours = h_offset;
new_time->minutes = m_offset;
new_time->has->hours = TRUE;
new_time->has->minutes = TRUE;
}
return new_time;
}
ha_time_t*
parse_time(char **time_str, ha_time_t *a_time, gboolean with_offset)
{
ha_time_t *new_time = a_time;
tzset();
if(a_time == NULL) {
new_time = new_ha_date(FALSE);
}
CRM_CHECK(new_time != NULL, return NULL);
CRM_CHECK(new_time->has != NULL, free_ha_date(new_time); return NULL);
/* reset the time fields */
new_time->hours = 0;
new_time->minutes = 0;
new_time->seconds = 0;
crm_debug_4("Get hours...");
new_time->has->hours = FALSE;
if(parse_int(time_str, 2, 24, &new_time->hours)) {
new_time->has->hours = TRUE;
}
crm_debug_4("Get minutes...");
new_time->has->minutes = FALSE;
if(parse_int(time_str, 2, 60, &new_time->minutes)) {
new_time->has->minutes = TRUE;
}
crm_debug_4("Get seconds...");
new_time->has->seconds = FALSE;
if(parse_int(time_str, 2, 60, &new_time->seconds)){
new_time->has->seconds = TRUE;
}
if(with_offset) {
crm_debug_4("Get offset...");
while(isspace((int) (*time_str)[0])) {
(*time_str)++;
}
new_time->offset = parse_time_offset(time_str);
normalize_time(new_time);
}
return new_time;
}
void
normalize_time(ha_time_t *a_time)
{
CRM_CHECK(a_time != NULL, return);
CRM_CHECK(a_time->has != NULL, return);
if(a_time->normalized == NULL) {
crm_malloc0(a_time->normalized, sizeof(ha_time_t));
}
if(a_time->normalized->has == NULL) {
crm_malloc0(a_time->normalized->has, sizeof(ha_has_time_t));
}
ha_set_time(a_time->normalized, a_time, FALSE);
if(a_time->offset != NULL) {
if(a_time->offset->has->hours) {
sub_hours(a_time->normalized, a_time->offset->hours);
}
if(a_time->offset->has->minutes) {
sub_minutes(a_time->normalized,a_time->offset->minutes);
}
if(a_time->offset->has->seconds) {
sub_seconds(a_time->normalized,a_time->offset->seconds);
}
}
CRM_CHECK(is_date_sane(a_time), return);
}
ha_time_t *
parse_date(char **date_str)
{
gboolean is_done = FALSE;
gboolean converted = FALSE;
ha_time_t *new_time = NULL;
CRM_CHECK(date_str != NULL, return NULL);
CRM_CHECK(strlen(*date_str) > 0, return NULL);
if((*date_str)[0] == 'T' || (*date_str)[2] == ':') {
/* Just a time supplied - Infer current date */
new_time = new_ha_date(TRUE);
parse_time(date_str, new_time, TRUE);
normalize_time(new_time);
is_done = TRUE;
} else {
crm_malloc0(new_time, sizeof(ha_time_t));
crm_malloc0(new_time->has, sizeof(ha_has_time_t));
}
while(is_done == FALSE) {
char ch = (*date_str)[0];
crm_debug_5("Switching on ch=%c (len=%d)",
ch, (int)strlen(*date_str));
if(ch == 0) {
/* all done */
is_done = TRUE;
break;
} else if(ch == '/') {
/* all done - interval marker */
is_done = TRUE;
break;
} else if(ch == 'W') {
CRM_CHECK(new_time->has->weeks == FALSE, ;);
(*date_str)++;
if(parse_int(date_str, 2, 53, &new_time->weeks)){
new_time->has->weeks = TRUE;
new_time->weekyears = new_time->years;
new_time->has->weekyears = new_time->has->years;
}
if((*date_str)[0] == '-') {
(*date_str)++;
if(parse_int(date_str, 1, 7, &new_time->weekdays)) {
new_time->has->weekdays = TRUE;
}
}
if(new_time->weekdays == 0
|| new_time->has->weekdays == FALSE) {
new_time->weekdays = 1;
new_time->has->weekdays = TRUE;
}
} else if(ch == '-') {
(*date_str)++;
if(check_for_ordinal(*date_str)) {
if(parse_int(date_str, 3, 366, &new_time->yeardays)) {
new_time->has->yeardays = TRUE;
}
}
} else if(ch == 'O') {
/* ordinal date */
(*date_str)++;
if(parse_int(date_str, 3, 366, &new_time->yeardays)){
new_time->has->yeardays = TRUE;
}
} else if(ch == 'T' || ch == ' ') {
if(new_time->has->yeardays) {
converted = convert_from_ordinal(new_time);
} else if(new_time->has->weekdays) {
converted = convert_from_weekdays(new_time);
} else {
converted = convert_from_gregorian(new_time);
}
(*date_str)++;
parse_time(date_str, new_time, TRUE);
is_done = TRUE;
} else if(isdigit((int) ch)) {
if(new_time->has->years == FALSE
&& parse_int(date_str, 4, 9999, &new_time->years)) {
new_time->has->years = TRUE;
} else if(check_for_ordinal(*date_str) && parse_int(
date_str, 3,
is_leap_year(new_time->years)?366:365,
&new_time->yeardays)) {
new_time->has->yeardays = TRUE;
} else if(new_time->has->months == FALSE
&& parse_int(date_str, 2, 12, &new_time->months)) {
new_time->has->months = TRUE;
} else if(new_time->has->days == FALSE) {
if(parse_int(date_str, 2,
days_per_month(new_time->months, new_time->years),
&new_time->days)) {
new_time->has->days = TRUE;
}
}
} else {
crm_err("Unexpected characters at: %s", *date_str);
is_done = TRUE;
break;
}
}
if(converted) {
} else if(new_time->has->yeardays) {
convert_from_ordinal(new_time);
} else if(new_time->has->weekdays) {
convert_from_weekdays(new_time);
} else {
convert_from_gregorian(new_time);
}
normalize_time(new_time);
log_date(LOG_DEBUG_3, "Unpacked", new_time, ha_log_date|ha_log_time);
CRM_CHECK(is_date_sane(new_time), return NULL);
return new_time;
}
ha_time_t*
parse_time_duration(char **interval_str)
{
gboolean is_time = FALSE;
ha_time_t *diff = NULL;
CRM_CHECK(interval_str != NULL, goto bail);
CRM_CHECK(strlen(*interval_str) > 0, goto bail);
CRM_CHECK((*interval_str)[0] == 'P', goto bail);
(*interval_str)++;
crm_malloc0(diff, sizeof(ha_time_t));
crm_malloc0(diff->has, sizeof(ha_has_time_t));
while(isspace((int) (*interval_str)[0]) == FALSE) {
int an_int = 0;
char ch = 0;
if((*interval_str)[0] == 'T') {
is_time = TRUE;
(*interval_str)++;
}
if(parse_int(interval_str, 10, 0, &an_int) == FALSE) {
break;
}
ch = (*interval_str)[0];
(*interval_str)++;
crm_debug_4("%c=%d", ch, an_int);
switch(ch) {
case 0:
return diff;
break;
case 'Y':
diff->years = an_int;
diff->has->years = TRUE;
break;
case 'M':
if(is_time) {
diff->minutes = an_int;
diff->has->minutes = TRUE;
} else {
diff->months = an_int;
diff->has->months = TRUE;
}
break;
case 'W':
diff->weeks = an_int;
diff->has->weeks = TRUE;
break;
case 'D':
diff->days = an_int;
diff->has->days = TRUE;
diff->yeardays = an_int;
diff->has->yeardays = TRUE;
break;
case 'H':
diff->hours = an_int;
diff->has->hours = TRUE;
break;
case 'S':
diff->seconds = an_int;
diff->has->seconds = TRUE;
break;
default:
break;
}
}
return diff;
bail:
if(diff) {
crm_free(diff->has);
}
crm_free(diff);
return NULL;
}
ha_time_period_t*
parse_time_period(char **period_str)
{
gboolean invalid = FALSE;
const char *original = *period_str;
ha_time_period_t *period = NULL;
CRM_CHECK(period_str != NULL, return NULL);
CRM_CHECK(strlen(*period_str) > 0, return NULL);
tzset();
crm_malloc0(period, sizeof(ha_time_period_t));
if((*period_str)[0] == 'P') {
period->diff = parse_time_duration(period_str);
} else {
period->start = parse_date(period_str);
}
if((*period_str)[0] != 0) {
CRM_CHECK((*period_str)[0] == '/', invalid = TRUE; goto bail);
(*period_str)++;
if((*period_str)[0] == 'P') {
period->diff = parse_time_duration(period_str);
} else {
period->end = parse_date(period_str);
}
} else if(period->diff != NULL) {
/* just aduration starting from now */
time_t now = time(NULL);
crm_malloc0(period->start, sizeof(ha_time_t));
crm_malloc0(period->start->has, sizeof(ha_has_time_t));
crm_malloc0(period->start->offset, sizeof(ha_time_t));
crm_malloc0(period->start->offset->has, sizeof(ha_has_time_t));
ha_set_timet_time(period->start, &now);
normalize_time(period->start);
} else {
invalid = TRUE;
CRM_CHECK((*period_str)[0] == '/', goto bail);
goto bail;
}
/* sanity checks */
if(period->start == NULL && period->end == NULL) {
crm_err("Invalid time period: %s", original);
invalid = TRUE;
} else if(period->start == NULL && period->diff == NULL) {
crm_err("Invalid time period: %s", original);
invalid = TRUE;
} else if(period->end == NULL && period->diff == NULL) {
crm_err("Invalid time period: %s", original);
invalid = TRUE;
}
bail:
if(invalid) {
crm_free(period->start);
crm_free(period->end);
crm_free(period->diff);
crm_free(period);
return NULL;
}
if(period->end == NULL && period->diff == NULL) {
}
if(period->start == NULL) {
period->start = subtract_duration(period->end, period->diff);
normalize_time(period->start);
} else if(period->end == NULL) {
period->end = add_time(period->start, period->diff);
normalize_time(period->end);
}
is_date_sane(period->start);
is_date_sane(period->end);
return period;
}
int month2days[13] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
/* http://www.personal.ecu.edu/mccartyr/ISOwdALG.txt */
int
january1(int year)
{
int YY = (year - 1) % 100;
int C = (year - 1) - YY;
int G = YY + YY/4;
int jan1 = 1 + (((((C / 100) % 4) * 5) + G) % 7);
crm_debug_6("YY=%d, C=%d, G=%d", YY, C, G);
crm_debug_5("January 1 %.4d: %d", year, jan1);
return jan1;
}
int
weeks_in_year(int year)
{
int weeks = 52;
int jan1 = january1(year);
/* if jan1 == thursday */
if(jan1 == 4) {
weeks++;
} else {
jan1 = january1(year+1);
/* if dec31 == thursday aka. jan1 of next year is a friday */
if(jan1 == 5) {
weeks++;
}
}
return weeks;
}
gboolean
convert_from_gregorian(ha_time_t *a_date)
{
CRM_CHECK(gregorian_to_ordinal(a_date), return FALSE);
CRM_CHECK(ordinal_to_weekdays(a_date), return FALSE);
return TRUE;
}
gboolean
gregorian_to_ordinal(ha_time_t *a_date)
{
CRM_CHECK(a_date->has->years, return FALSE);
CRM_CHECK(a_date->has->months, return FALSE);
CRM_CHECK(a_date->has->days, return FALSE);
CRM_CHECK(a_date->months > 0, return FALSE);
CRM_CHECK(a_date->days > 0, return FALSE);
a_date->yeardays = month2days[a_date->months-1];
a_date->yeardays += a_date->days;
a_date->has->yeardays = TRUE;
if(is_leap_year(a_date->years) && a_date->months > 2) {
(a_date->yeardays)++;
}
crm_debug_4("Converted %.4d-%.2d-%.2d to %.4d-%.3d",
a_date->years, a_date->months, a_date->days,
a_date->years, a_date->yeardays);
return TRUE;
}
gboolean
convert_from_ordinal(ha_time_t *a_date)
{
CRM_CHECK(ordinal_to_gregorian(a_date), return FALSE);
CRM_CHECK(ordinal_to_weekdays(a_date), return FALSE);
return TRUE;
}
gboolean ordinal_to_gregorian(ha_time_t *a_date)
{
/* Day of the year this month ends on */
int m_end = 0;
CRM_CHECK(a_date->has->years, return FALSE);
CRM_CHECK(a_date->has->yeardays, return FALSE);
CRM_CHECK(a_date->yeardays > 0, return FALSE);
if(is_leap_year(a_date->years) && a_date->yeardays > 366) {
crm_err("Year %.4d only has 366 days (supplied %.3d)",
a_date->years, a_date->yeardays);
a_date->yeardays = 366;
} else if(!is_leap_year(a_date->years) && a_date->yeardays > 365) {
crm_err("Year %.4d only has 365 days (supplied %.3d)",
a_date->years, a_date->yeardays);
a_date->yeardays = 365;
}
a_date->days = a_date->yeardays;
a_date->months = 0;
do {
a_date->months++;
m_end += days_per_month(a_date->months, a_date->years);
a_date->days -= days_per_month(a_date->months-1, a_date->years);
crm_debug_6("month %d: %d vs. %d - current day: %d",
a_date->months, a_date->yeardays,
m_end, a_date->days);
} while (a_date->months < 12 && m_end < a_date->yeardays);
CRM_CHECK(a_date->months > 0, return FALSE);
CRM_CHECK(a_date->days <= days_per_month(a_date->months, a_date->years),
return FALSE);
a_date->has->days = TRUE;
a_date->has->months = TRUE;
a_date->has->years = TRUE;
crm_debug_4("Converted %.4d-%.3d to %.4d-%.2d-%.2d",
a_date->years, a_date->yeardays,
a_date->years, a_date->months, a_date->days);
return TRUE;
}
gboolean
ordinal_to_weekdays(ha_time_t *a_date)
{
int year_num = 0;
int jan1 = january1(a_date->years);
int h = -1;
CRM_CHECK(a_date->has->years, return FALSE);
CRM_CHECK(a_date->has->yeardays, return FALSE);
CRM_CHECK(a_date->yeardays > 0, return FALSE);
h = a_date->yeardays + jan1 - 1;
a_date->weekdays = 1 + ((h-1) % 7);
a_date->has->weekdays = TRUE;
if(a_date->yeardays <= (8-jan1) && jan1 > 4) {
year_num = a_date->years - 1;
a_date->weeks = weeks_in_year(year_num);
a_date->has->weeks = TRUE;
} else {
year_num = a_date->years;
}
if(year_num == a_date->years) {
int i = 365;
if(is_leap_year(year_num)) {
i = 366;
}
if( (i - a_date->yeardays) < (4 - a_date->weekdays) ) {
year_num = a_date->years + 1;
a_date->weeks = 1;
a_date->has->weeks = TRUE;
}
}
if(year_num == a_date->years) {
int j = a_date->yeardays + (7-a_date->weekdays) + (jan1 - 1);
a_date->weeks = j / 7;
a_date->has->weeks = TRUE;
if(jan1 > 4) {
a_date->weeks -= 1;
}
}
a_date->weekyears = year_num;
a_date->has->weekyears = TRUE;
crm_debug_4("Converted %.4d-%.3d to %.4dW%.2d-%d",
a_date->years, a_date->yeardays,
a_date->weekyears, a_date->weeks, a_date->weekdays);
return TRUE;
}
gboolean
convert_from_weekdays(ha_time_t *a_date)
{
gboolean conversion = FALSE;
int jan1 = january1(a_date->weekyears);
CRM_CHECK(a_date->has->weekyears, return FALSE);
CRM_CHECK(a_date->has->weeks, return FALSE);
CRM_CHECK(a_date->has->weekdays, return FALSE);
CRM_CHECK(a_date->weeks > 0, return FALSE);
CRM_CHECK(a_date->weekdays > 0, return FALSE);
CRM_CHECK(a_date->weekdays < 8, return FALSE);
a_date->has->years = TRUE;
a_date->years = a_date->weekyears;
a_date->has->yeardays = TRUE;
a_date->yeardays = (7 * (a_date->weeks-1));
/* break up the addition to make sure overflows are correctly handled */
if(a_date->yeardays == 0) {
a_date->yeardays = a_date->weekdays;
} else {
add_yeardays(a_date, a_date->weekdays);
}
crm_debug_5("Pre-conversion: %dW%d-%d to %.4d-%.3d",
a_date->weekyears, a_date->weeks, a_date->weekdays,
a_date->years, a_date->yeardays);
conversion = ordinal_to_gregorian(a_date);
if(conversion) {
if(jan1 < 4) {
sub_days(a_date, jan1-1);
} else if(jan1 > 4) {
add_days(a_date, jan1-4);
}
}
return conversion;
}
void
ha_set_time(ha_time_t *lhs, ha_time_t *rhs, gboolean offset)
{
crm_debug_6("lhs=%p, rhs=%p, offset=%d", lhs, rhs, offset);
CRM_CHECK(lhs != NULL && rhs != NULL, return);
CRM_CHECK(lhs->has != NULL && rhs->has != NULL, return);
lhs->years = rhs->years;
lhs->has->years = rhs->has->years;
lhs->weekyears = rhs->weekyears;
lhs->has->weekyears = rhs->has->weekyears;
lhs->months = rhs->months;
lhs->has->months = rhs->has->months;
lhs->weeks = rhs->weeks;
lhs->has->weeks = rhs->has->weeks;
lhs->days = rhs->days;
lhs->has->days = rhs->has->days;
lhs->weekdays = rhs->weekdays;
lhs->has->weekdays = rhs->has->weekdays;
lhs->yeardays = rhs->yeardays;
lhs->has->yeardays = rhs->has->yeardays;
lhs->hours = rhs->hours;
lhs->has->hours = rhs->has->hours;
lhs->minutes = rhs->minutes;
lhs->has->minutes = rhs->has->minutes;
lhs->seconds = rhs->seconds;
lhs->has->seconds = rhs->has->seconds;
if(lhs->offset) {
reset_time(lhs->offset);
}
if(offset && rhs->offset) {
ha_set_time(lhs->offset, rhs->offset, FALSE);
}
}
void
ha_set_tm_time(ha_time_t *lhs, struct tm *rhs)
{
int wday = rhs->tm_wday;
int h_offset = 0;
int m_offset = 0;
if(rhs->tm_year > 0) {
/* years since 1900 */
lhs->years = 1900 + rhs->tm_year;
lhs->has->years = TRUE;
}
if(rhs->tm_yday >= 0) {
/* days since January 1 [0-365] */
lhs->yeardays = 1 + rhs->tm_yday;
lhs->has->yeardays =TRUE;
}
if(rhs->tm_hour >= 0) {
lhs->hours = rhs->tm_hour;
lhs->has->hours =TRUE;
}
if(rhs->tm_min >= 0) {
lhs->minutes = rhs->tm_min;
lhs->has->minutes =TRUE;
}
if(rhs->tm_sec >= 0) {
lhs->seconds = rhs->tm_sec;
lhs->has->seconds =TRUE;
}
convert_from_ordinal(lhs);
/* months since January [0-11] */
CRM_CHECK(rhs->tm_mon < 0 || lhs->months == (1 + rhs->tm_mon), return);
/* day of the month [1-31] */
CRM_CHECK(rhs->tm_mday < 0 || lhs->days == rhs->tm_mday, return);
/* days since Sunday [0-6] */
if(wday == 0) {
wday= 7;
}
CRM_CHECK(rhs->tm_wday < 0 || lhs->weekdays == wday, return);
CRM_CHECK(lhs->offset != NULL, return);
CRM_CHECK(lhs->offset->has != NULL, return);
/* tm_gmtoff == offset from UTC in seconds */
h_offset = GMTOFF(rhs) / (3600);
m_offset = (GMTOFF(rhs) - (3600 * h_offset)) / (60);
crm_debug_6("Offset (s): %ld, offset (hh:mm): %.2d:%.2d",
GMTOFF(rhs), h_offset, m_offset);
lhs->offset->hours = h_offset;
lhs->offset->has->hours = TRUE;
lhs->offset->minutes = m_offset;
lhs->offset->has->minutes = TRUE;
normalize_time(lhs);
}
void
ha_set_timet_time(ha_time_t *lhs, time_t *rhs)
{
ha_set_tm_time(lhs, localtime(rhs));
}
ha_time_t *
add_time(ha_time_t *lhs, ha_time_t *rhs)
{
ha_time_t *answer = NULL;
CRM_CHECK(lhs != NULL && rhs != NULL, return NULL);
answer = new_ha_date(FALSE);
ha_set_time(answer, lhs, TRUE);
normalize_time(lhs);
normalize_time(answer);
if(rhs->has->years) {
add_years(answer, rhs->years);
}
if(rhs->has->months) {
add_months(answer, rhs->months);
}
if(rhs->has->weeks) {
add_weeks(answer, rhs->weeks);
}
if(rhs->has->days) {
add_days(answer, rhs->days);
}
add_hours(answer, rhs->hours);
add_minutes(answer, rhs->minutes);
add_seconds(answer, rhs->seconds);
normalize_time(answer);
return answer;
}
ha_time_t *
subtract_time(ha_time_t *lhs, ha_time_t *rhs)
{
ha_time_t *answer = NULL;
CRM_CHECK(lhs != NULL && rhs != NULL, return NULL);
answer = new_ha_date(FALSE);
ha_set_time(answer, lhs, TRUE);
normalize_time(lhs);
normalize_time(rhs);
normalize_time(answer);
sub_seconds(answer, rhs->seconds);
sub_minutes(answer, rhs->minutes);
sub_hours(answer, rhs->hours);
answer->yeardays -= rhs->yeardays;
while(answer->yeardays < 0) {
answer->yeardays += is_leap_year(answer->years)?356:355;
answer->years--;
}
answer->days -= rhs->days;
while(answer->days < 0) {
answer->days += days_per_month(answer->months, answer->years);
answer->months--;
}
answer->months -= rhs->months;
while(answer->months < 0) {
answer->months += 12;
/* answer->years--; : done in the yeardays section */
}
answer->years -= rhs->years;
return answer;
}
ha_time_t *
subtract_duration(ha_time_t *lhs, ha_time_t *rhs)
{
ha_time_t *answer = NULL;
CRM_CHECK(lhs != NULL && rhs != NULL, return NULL);
answer = new_ha_date(FALSE);
ha_set_time(answer, lhs, TRUE);
normalize_time(lhs);
normalize_time(rhs);
normalize_time(answer);
sub_seconds(answer, rhs->seconds);
sub_minutes(answer, rhs->minutes);
sub_hours(answer, rhs->hours);
sub_days(answer, rhs->days);
sub_weeks(answer, rhs->weeks);
sub_months(answer, rhs->months);
sub_years(answer, rhs->years);
normalize_time(answer);
return answer;
}
/* ha_time_interval_t* */
/* parse_time_interval(char **interval_str) */
/* { */
/* return NULL; */
/* } */
int month_days[14] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 29 };
int
days_per_month(int month, int year)
{
if(month == 2 && is_leap_year(year)) {
month = 13;
}
return month_days[month];
}
gboolean
is_leap_year(int year)
{
gboolean is_leap = FALSE;
if(year % 4 == 0) {
is_leap = TRUE;
}
if(year % 100 == 0 && year % 400 != 0 ) {
is_leap = FALSE;
}
return is_leap;
}
gboolean
parse_int(char **str, int field_width, int uppper_bound, int *result)
{
int lpc = 0;
int intermediate = 0;
gboolean fraction = FALSE;
gboolean negate = FALSE;
CRM_CHECK(str != NULL, return FALSE);
CRM_CHECK(*str != NULL, return FALSE);
CRM_CHECK(result != NULL, return FALSE);
*result = 0;
if(strlen(*str) <= 0) {
return FALSE;
}
if((*str)[0] == 'T') {
(*str)++;
}
if((*str)[0] == '.' || (*str)[0] == ',') {
fraction = TRUE;
field_width = -1;
(*str)++;
} else if((*str)[0] == '-') {
negate = TRUE;
(*str)++;
} else if((*str)[0] == '+'
|| (*str)[0] == ':') {
(*str)++;
}
for(; (fraction || lpc < field_width) && isdigit((int) (*str)[0]); lpc++) {
if(fraction) {
intermediate = ((*str)[0] - '0')/(10^lpc);
} else {
*result *= 10;
intermediate = (*str)[0] - '0';
}
*result += intermediate;
(*str)++;
}
if(fraction) {
*result = (int)(*result * uppper_bound);
} else if(uppper_bound > 0 && *result > uppper_bound) {
*result = uppper_bound;
}
if(negate) {
*result = 0 - *result;
}
if(lpc > 0) {
crm_debug_5("Found int: %d. Stopped at str[%d]='%c'", *result, lpc, (*str)[lpc]);
return TRUE;
}
return FALSE;
}
gboolean
check_for_ordinal(const char *str)
{
if(isdigit((int) str[2]) == FALSE) {
crm_debug_6("char 3 == %c", str[2]);
return FALSE;
}
if(isspace((int) str[3])) {
return TRUE;
} else if(str[3] == 0) {
return TRUE;
} else if(str[3] == 'T') {
return TRUE;
} else if(str[3] == '/') {
return TRUE;
}
crm_debug_6("char 4 == %c", str[3]);
return FALSE;
}
int str_lookup(const char *str, enum date_fields field)
{
return 0;
}
void
reset_time(ha_time_t *a_time)
{
a_time->years = 0;
a_time->has->years = FALSE;
a_time->weekyears = 0;
a_time->has->weekyears = FALSE;
a_time->months = 0;
a_time->has->months = FALSE;
a_time->weeks = 0;
a_time->has->weeks = FALSE;
a_time->days = 0;
a_time->has->days = FALSE;
a_time->weekdays = 0;
a_time->has->weekdays = FALSE;
a_time->yeardays = 0;
a_time->has->yeardays = FALSE;
a_time->hours = 0;
a_time->has->hours = FALSE;
a_time->minutes = 0;
a_time->has->minutes = FALSE;
a_time->seconds = 0;
a_time->has->seconds = FALSE;
}
void
reset_tm(struct tm *some_tm)
{
some_tm->tm_sec = -1; /* seconds after the minute [0-60] */
some_tm->tm_min = -1; /* minutes after the hour [0-59] */
some_tm->tm_hour = -1; /* hours since midnight [0-23] */
some_tm->tm_mday = -1; /* day of the month [1-31] */
some_tm->tm_mon = -1; /* months since January [0-11] */
some_tm->tm_year = -1; /* years since 1900 */
some_tm->tm_wday = -1; /* days since Sunday [0-6] */
some_tm->tm_yday = -1; /* days since January 1 [0-365] */
some_tm->tm_isdst = -1; /* Daylight Savings Time flag */
#if defined(HAVE_STRUCT_TM_TM_GMTOFF)
some_tm->tm_gmtoff = -1; /* offset from CUT in seconds */
#endif
#if defined(HAVE_TM_ZONE)
some_tm->tm_zone = NULL;/* timezone abbreviation */
#endif
}
gboolean
is_date_sane(ha_time_t *a_date)
{
int ydays = 0;
int mdays = 0;
int weeks = 0;
CRM_CHECK(a_date != NULL, return FALSE);
ydays = is_leap_year(a_date->years)?366:365;
mdays = days_per_month(a_date->months, a_date->years);
weeks = weeks_in_year(a_date->weekyears);
crm_debug_5("max ydays: %d, max mdays: %d, max weeks: %d",
ydays, mdays, weeks);
CRM_CHECK(a_date->has->years, return FALSE);
CRM_CHECK(a_date->has->weekyears, return FALSE);
CRM_CHECK(a_date->has->months, return FALSE);
CRM_CHECK(a_date->months > 0, return FALSE);
CRM_CHECK(a_date->months <= 12, return FALSE);
CRM_CHECK(a_date->has->weeks, return FALSE);
CRM_CHECK(a_date->weeks > 0, return FALSE);
CRM_CHECK(a_date->weeks <= weeks, return FALSE);
CRM_CHECK(a_date->has->days, return FALSE);
CRM_CHECK(a_date->days > 0, return FALSE);
CRM_CHECK(a_date->days <= mdays, return FALSE);
CRM_CHECK(a_date->has->weekdays, return FALSE);
CRM_CHECK(a_date->weekdays > 0, return FALSE);
CRM_CHECK(a_date->weekdays <= 7, return FALSE);
CRM_CHECK(a_date->has->yeardays, return FALSE);
CRM_CHECK(a_date->yeardays > 0, return FALSE);
CRM_CHECK(a_date->yeardays <= ydays, return FALSE);
CRM_CHECK(a_date->hours >= 0, return FALSE);
CRM_CHECK(a_date->hours < 24, return FALSE);
CRM_CHECK(a_date->minutes >= 0, return FALSE);
CRM_CHECK(a_date->minutes < 60, return FALSE);
CRM_CHECK(a_date->seconds >= 0, return FALSE);
CRM_CHECK(a_date->seconds <= 60, return FALSE);
return TRUE;
}
#define do_cmp_field(lhs, rhs, field) \
{ \
if(lhs->field > rhs->field) { \
crm_debug_2("%s: %d > %d", \
#field, lhs->field, rhs->field); \
return 1; \
} else if(lhs->field < rhs->field) { \
crm_debug_2("%s: %d < %d", \
#field, lhs->field, rhs->field); \
return -1; \
} \
}
int
compare_date(ha_time_t *lhs, ha_time_t *rhs)
{
if(lhs == NULL && rhs == NULL) {
return 0;
} else if(lhs == NULL) {
return -1;
} else if(rhs == NULL) {
return 1;
}
normalize_time(lhs);
normalize_time(rhs);
do_cmp_field(lhs->normalized, rhs->normalized, years);
do_cmp_field(lhs->normalized, rhs->normalized, yeardays);
do_cmp_field(lhs->normalized, rhs->normalized, hours);
do_cmp_field(lhs->normalized, rhs->normalized, minutes);
do_cmp_field(lhs->normalized, rhs->normalized, seconds);
return 0;
}
ha_time_t *
new_ha_date(gboolean set_to_now)
{
time_t tm_now;
ha_time_t *now = NULL;
tzset();
crm_malloc0(now, sizeof(ha_time_t));
crm_malloc0(now->has, sizeof(ha_has_time_t));
crm_malloc0(now->offset, sizeof(ha_time_t));
crm_malloc0(now->offset->has, sizeof(ha_has_time_t));
if(set_to_now) {
tm_now = time(NULL);
now->tm_now = tm_now;
ha_set_timet_time(now, &tm_now);
}
return now;
}
void
free_ha_date(ha_time_t *a_date)
{
if(a_date == NULL) {
return;
}
free_ha_date(a_date->normalized);
free_ha_date(a_date->offset);
crm_free(a_date->has);
crm_free(a_date);
}
void
log_tm_date(int log_level, struct tm *some_tm)
{
const char *tzn;
#if defined(HAVE_TM_ZONE)
tzn = some_tm->tm_zone;
#elif defined(HAVE_TZNAME)
tzn = tzname[0];
#else
tzn = NULL;
#endif
do_crm_log(log_level,
"%.2d/%.2d/%.4d %.2d:%.2d:%.2d %s"
" (wday=%d, yday=%d, dst=%d, offset=%ld)",
some_tm->tm_mday,
some_tm->tm_mon,
1900+some_tm->tm_year,
some_tm->tm_hour,
some_tm->tm_min,
some_tm->tm_sec,
tzn,
some_tm->tm_wday==0?7:some_tm->tm_wday,
1+some_tm->tm_yday,
some_tm->tm_isdst,
GMTOFF(some_tm));
}
ha_time_t *the_epoch = NULL;
#define update_seconds(date, field, multiplier) do { \
before = in_seconds; \
in_seconds += a_date->field; \
in_seconds *= multiplier; \
if(before > in_seconds) { \
crm_crit("Date wrap detected: %s", #field); \
return 0; \
} \
} while(0)
unsigned long long date_in_seconds(ha_time_t *a_date)
{
unsigned long long before = 0;
unsigned long long in_seconds = 0;
/* normalize_time(a_date); */
update_seconds(a_date, years, 365);
update_seconds(a_date, yeardays, 24);
update_seconds(a_date, hours, 60);
update_seconds(a_date, minutes, 60);
update_seconds(a_date, seconds, 1);
return in_seconds;
}
unsigned long long date_in_seconds_since_epoch(ha_time_t *a_date)
{
ha_time_t *since_epoch = NULL;
unsigned long long in_seconds = 0;
normalize_time(a_date);
if(the_epoch == NULL) {
char *EPOCH = crm_strdup("1970-01-01");
the_epoch = parse_date(&EPOCH);
normalize_time(the_epoch);
crm_free(EPOCH);
}
since_epoch = subtract_time(a_date, the_epoch);
in_seconds = date_in_seconds(since_epoch);
free_ha_date(since_epoch);
return in_seconds;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Tue, Oct 29, 8:14 PM (1 d, 19 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
942573
Default Alt Text
iso8601.c (32 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment