/* GNUPLOT - time.c */
/*[
* Copyright 1986 - 1993, 1998, 2004 Thomas Williams, Colin Kelley
*
* Permission to use, copy, and distribute this software and its
* documentation for any purpose with or without fee is hereby granted,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation.
*
* Permission to modify the software is granted, but not the right to
* distribute the complete modified source code. Modifications are to
* be distributed as patches to the released version. Permission to
* distribute binaries produced by compiling modified sources is granted,
* provided you
* 1. distribute the corresponding source modifications from the
* released version in the form of a patch file along with the binaries,
* 2. add special version identification to distinguish your version
* in addition to the base release version number,
* 3. provide your name and address as the primary contact for the
* support of your modified version, and
* 4. retain our contact information in regard to use of the base
* software.
* Permission to distribute the released version of the source code along
* with corresponding source modifications in the form of a patch file is
* granted with same provisions 2 through 4 for binary distributions.
*
* This software is provided "as is" without express or implied warranty
* to the extent permitted by applicable law.
]*/
/* This module either adds a routine gstrptime() to read a formatted time,
* augmenting the standard suite of time routines provided by ansi,
* or it completely replaces the whole lot with a new set of routines
* which count time relative to the EPOCH date. Default is to use the
* new routines. Define USE_SYSTEM_TIME to use the system routines, at your
* own risk. One problem in particular is that not all systems allow
* the time with integer value 0 to be represented symbolically, which
* prevents use of relative times. Also, the system routines do not allow
* you to read in fractional seconds.
*/
#include "gp_time.h"
#include "util.h"
#include "variable.h"
static char *read_int __PROTO((char *s, int nr, int *d));
static char *
read_int(char *s, int nr, int *d)
{
int result = 0;
while (--nr >= 0 && *s >= '0' && *s <= '9')
result = result * 10 + (*s++ - '0');
*d = result;
return (s);
}
#ifndef USE_SYSTEM_TIME
/* a new set of routines to completely replace the ansi ones
* Use at your own risk
*/
static int gdysize __PROTO((int yr));
static int mndday[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
static size_t xstrftime __PROTO((char *buf, int bsz, const char *fmt, struct tm * tm, double usec, double fulltime));
/* days in year */
static int
gdysize(int yr)
{
if (!(yr % 4)) {
if ((!(yr % 100)) && yr % 400)
return (365);
return (366);
}
return (365);
}
/* gstrptime() interprets a time_spec format string
* and fills in a time structure that can be passed to gmtime() to
* recover number of seconds from the EPOCH date.
* Return value:
* DT_TIMEDATE indicates "normal" format elements corresponding to
* a date that is returned in tm, with fractional seconds
* returned in usec
* DT_DMS indicates relative time format elements were encountered
* (tH tM tS). The relative time in seconds is returned
* in reltime.
* DT_BAD time format could not be interpreted
*
* parameters and return values revised for gnuplot version 5.3
*/
td_type
gstrptime(char *s, char *fmt, struct tm *tm, double *usec, double *reltime)
{
int yday = 0;
TBOOLEAN sanity_check_date = FALSE;
TBOOLEAN reltime_formats = FALSE;
tm->tm_mday = 1;
tm->tm_mon = tm->tm_hour = tm->tm_min = tm->tm_sec = 0;
/* make relative times work (user-defined tic step) */
tm->tm_year = ZERO_YEAR;
/* Fractional seconds will be returned separately, since
* there is no slot for the fraction in struct tm.
*/
*usec = 0.0;
/* we do not yet calculate wday or yday, so make them illegal
* [but yday will be read by %j]
*/
tm->tm_yday = tm->tm_wday = -1;
/* If the format requests explicit day, month, or year, then we will
* do sanity checking to make sure the input makes sense.
* For backward compatibility with gnuplot versions through 4.6.6
* hour, minute, seconds default to zero with no error return
* if the corresponding field cannot be found or interpreted.
*/
if (strstr(fmt,"%d")) {
tm->tm_mday = -1;
sanity_check_date = TRUE;
}
if (strstr(fmt,"%y") || strstr(fmt,"%Y")) {
tm->tm_year = -1;
sanity_check_date = TRUE;
}
if (strstr(fmt,"%m") || strstr(fmt,"%B") || strstr(fmt,"%b")) {
tm->tm_mon = -1;
sanity_check_date = TRUE;
}
/* Relative time formats tH tM tS cannot be mixed with date formats */
if (strstr(fmt,"%t")) {
reltime_formats = TRUE;
*reltime = 0.0;
sanity_check_date = FALSE;
}
while (*fmt) {
if (*fmt != '%') {
if (*fmt == ' ') {
/* space in format means zero or more spaces in input */
while (*s == ' ')
++s;
++fmt;
continue;
} else if (*fmt == *s) {
++s;
++fmt;
continue;
} else
break; /* literal match has failed */
}
/* we are processing a percent escape */
switch (*++fmt) {
case 'b': /* abbreviated month name */
{
int m;
for (m = 0; m < 12; ++m)
if (strncasecmp(s, abbrev_month_names[m],
strlen(abbrev_month_names[m])) == 0) {
s += strlen(abbrev_month_names[m]);
goto found_abbrev_mon;
}
/* get here => not found */
int_warn(DATAFILE, "Bad abbreviated month name");
m = 0;
found_abbrev_mon:
tm->tm_mon = m;
break;
}
case 'B': /* full month name */
{
int m;
for (m = 0; m < 12; ++m)
if (strncasecmp(s, full_month_names[m],
strlen(full_month_names[m])) == 0) {
s += strlen(full_month_names[m]);
goto found_full_mon;
}
/* get here => not found */
int_warn(DATAFILE, "Bad full month name");
m = 0;
found_full_mon:
tm->tm_mon = m;
break;
}
case 'd': /* read a day of month */
s = read_int(s, 2, &tm->tm_mday);
break;
case 'm': /* month number */
s = read_int(s, 2, &tm->tm_mon);
--tm->tm_mon;
break;
case 'y': /* year number */
s = read_int(s, 2, &tm->tm_year);
/* In line with the current UNIX98 specification by
* The Open Group and major Unix vendors,
* two-digit years 69-99 refer to the 20th century, and
* values in the range 00-68 refer to the 21st century.
*/
if (tm->tm_year <= 68)
tm->tm_year += 100;
tm->tm_year += 1900;
break;
case 'Y':
s = read_int(s, 4, &tm->tm_year);
break;
case 'j':
s = read_int(s, 3, &tm->tm_yday);
tm->tm_yday--;
sanity_check_date = TRUE;
yday++;
break;
case 'H':
s = read_int(s, 2, &tm->tm_hour);
break;
case 'M':
s = read_int(s, 2, &tm->tm_min);
break;
case 'S':
s = read_int(s, 2, &tm->tm_sec);
if (*s == '.' || (decimalsign && *s == *decimalsign))
*usec = atof(s);
break;
case 's':
/* read EPOCH data
* EPOCH is the std. unix timeformat seconds since 01.01.1970 UTC
*/
{
char *fraction = strchr(s, decimalsign ? *decimalsign : '.');
double ufraction = 0;
double when = strtod (s, &s) - SEC_OFFS_SYS;
ggmtime(tm, when);
if (fraction && fraction < s)
ufraction = atof(fraction);
if (ufraction < 1.) /* Filter out e.g. 123.456e7 */
*usec = ufraction;
*reltime = when; /* not used unless return DT_DMS */
break;
}
case 't':
/* Relative time formats tH tM tS */
{
double cont = 0;
fmt++;
if (*fmt == 'H') {
cont = 3600. * strtod(s, &s);
} else if (*fmt == 'M') {
cont = 60. * strtod(s, &s);
} else if (*fmt == 'S') {
cont = strtod(s, &s);
} else {
return DT_BAD;
}
if (*reltime < 0)
*reltime -= fabs(cont);
else
*reltime += cont;
/* FIXME: reltime > 0 && cont < 0 should be disallowed */
/* FIXME: leading precision field should be accepted but ignored */
break;
}
default:
int_warn(DATAFILE, "Bad time format in string");
}
fmt++;
}
/* Relative times are easy. Just return the value in reltime */
if (reltime_formats) {
return DT_DMS;
}
FPRINTF((stderr, "read date-time : %02d/%02d/%d:%02d:%02d:%02d\n", tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec));
/* now sanity check the date/time entered, normalising if necessary
* read_int cannot read a -ve number, but can read %m=0 then decrement
* it to -1
*/
#define S (tm->tm_sec)
#define M (tm->tm_min)
#define H (tm->tm_hour)
if (S >= 60) {
M += S / 60;
S %= 60;
}
if (M >= 60) {
H += M / 60;
M %= 60;
}
if (H >= 24) {
if (yday)
tm->tm_yday += H / 24;
tm->tm_mday += H / 24;
H %= 24;
}
#undef S
#undef M
#undef H
FPRINTF((stderr, "normalised time : %02d/%02d/%d:%02d:%02d:%02d\n", tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec));
if (sanity_check_date) {
if (yday) {
if (tm->tm_yday < 0) {
return DT_BAD;
}
/* we just set month to jan, day to yday, and let the
* normalising code do the work.
*/
tm->tm_mon = 0;
/* yday is 0->365, day is 1->31 */
tm->tm_mday = tm->tm_yday + 1;
}
if (tm->tm_mon < 0) {
return DT_BAD;
}
if (tm->tm_mday < 1) {
return DT_BAD;
}
if (tm->tm_mon > 11) {
tm->tm_year += tm->tm_mon / 12;
tm->tm_mon %= 12;
} {
int days_in_month;
while (tm->tm_mday > (days_in_month = (mndday[tm->tm_mon] + (tm->tm_mon == 1 && (gdysize(tm->tm_year) > 365))))) {
if (++tm->tm_mon == 12) {
++tm->tm_year;
tm->tm_mon = 0;
}
tm->tm_mday -= days_in_month;
}
}
}
return DT_TIMEDATE;
}
size_t
gstrftime(char *s, size_t bsz, const char *fmt, double l_clock)
{
struct tm tm;
double usec;
ggmtime(&tm, l_clock);
usec = l_clock - (double)floor(l_clock);
return xstrftime(s, bsz, fmt, &tm, usec, l_clock);
}
static size_t
xstrftime(
char *str, /* output buffer */
int bsz, /* remaining space available in buffer */
const char *fmt,
struct tm *tm,
double usec,
double fulltime)
{
size_t l = 0; /* chars written so far */
int incr = 0; /* chars just written */
char *s = str;
TBOOLEAN sign_printed = FALSE;
if (bsz <= 0)
return 0;
memset(str, '\0', bsz);
while (*fmt != '\0') {
if (*fmt != '%') {
if (l >= bsz-1)
return 0;
*s++ = *fmt++;
l++;
} else {
/* set up format modifiers */
int w = 0;
int z = 0;
int p = 0;
if (*++fmt == '0') {
z = 1;
++fmt;
}
while (*fmt >= '0' && *fmt <= '9') {
w = w * 10 + (*fmt - '0');
++fmt;
}
if (*fmt == '.') {
++fmt;
while (*fmt >= '0' && *fmt <= '9') {
p = p * 10 + (*fmt - '0');
++fmt;
}
if (p > 6) p = 6;
}
switch (*fmt++) {
/* some shorthands : check that there is space in the
* output string. */
#define CHECK_SPACE(n) do { \
if ((l+(n)) > bsz) return 0; \
} while (0)
/* copy a fixed string, checking that there's room */
#define COPY_STRING(z) do { \
CHECK_SPACE(strlen(z)) ; \
strcpy(s, z); \
} while (0)
/* format a string, using default spec if none given w
* and z are width and zero-flag dw and dz are the
* defaults for these In fact, CHECK_SPACE(w) is not a
* sufficient test, since sprintf("%2d", 365) outputs
* three characters
*/
#define FORMAT_STRING(dz, dw, x) do { \
if (w==0) { \
w=(dw); \
if (!z) \
z=(dz); \
} \
incr = snprintf(s, bsz-l-1, z ? "%0*d" : "%*d", w, (x)); \
CHECK_SPACE(incr); \
} while(0)
case '%':
CHECK_SPACE(1);
*s = '%';
break;
case 'a':
COPY_STRING(abbrev_day_names[tm->tm_wday]);
break;
case 'A':
COPY_STRING(full_day_names[tm->tm_wday]);
break;
case 'b':
case 'h':
COPY_STRING(abbrev_month_names[tm->tm_mon]);
break;
case 'B':
COPY_STRING(full_month_names[tm->tm_mon]);
break;
case 'd':
FORMAT_STRING(1, 2, tm->tm_mday); /* %02d */
break;
case 'D':
if (!xstrftime(s, bsz - l, "%m/%d/%y", tm, 0., fulltime))
return 0;
break;
case 'F':
if (!xstrftime(s, bsz - l, "%Y-%m-%d", tm, 0., fulltime))
return 0;
break;
case 'H':
FORMAT_STRING(1, 2, tm->tm_hour); /* %02d */
break;
case 'I':
FORMAT_STRING(1, 2, (tm->tm_hour + 11) % 12 + 1); /* %02d */
break;
case 'j':
FORMAT_STRING(1, 3, tm->tm_yday + 1); /* %03d */
break;
/* not in linux strftime man page. Not really needed now */
case 'k':
FORMAT_STRING(0, 2, tm->tm_hour); /* %2d */
break;
case 'l':
FORMAT_STRING(0, 2, (tm->tm_hour + 11) % 12 + 1); /* %2d */
break;
case 'm':
FORMAT_STRING(1, 2, tm->tm_mon + 1); /* %02d */
break;
case 'M':
FORMAT_STRING(1, 2, tm->tm_min); /* %02d */
break;
case 'p':
CHECK_SPACE(2);
strcpy(s, (tm->tm_hour < 12) ? "am" : "pm");
break;
case 'r':
if (!xstrftime(s, bsz - l, "%I:%M:%S %p", tm, 0., fulltime))
return 0;
break;
case 'R':
if (!xstrftime(s, bsz - l, "%H:%M", tm, 0., fulltime))
return 0;
break;
case 's':
CHECK_SPACE(12); /* large enough for year 9999 */
sprintf(s, "%.0f", gtimegm(tm));
break;
case 'S':
FORMAT_STRING(1, 2, tm->tm_sec); /* %02d */
/* EAM FIXME - need to implement an actual format specifier */
if (p > 0) {
double base = pow(10., (double)p);
int msec = floor(0.5 + base * usec);
char *f = &s[strlen(s)];
CHECK_SPACE(p+1);
sprintf(f, ".%0*d", p, msec<(int)base?msec:(int)base-1);
}
break;
case 'T':
if (!xstrftime(s, bsz - l, "%H:%M:%S", tm, 0., fulltime))
return 0;
break;
case 't': /* Time (as opposed to Date) formats */
{
int tminute, tsecond;
switch (*fmt++) {
case 'H':
/* +/- fractional hours (not wrapped at 24h) */
if (p > 0) {
incr = snprintf(s, bsz-l-1, "%*.*f", w, p, fulltime/3600.);
CHECK_SPACE(incr);
break;
}
/* Set flag in case minutes come next */
if (fulltime < 0) {
CHECK_SPACE(1); /* the minus sign */
*s++ = '-';
l++;
}
sign_printed = TRUE;
/* +/- integral hour truncated toward zero */
sprintf(s, "%0*d", w, (int)floor(fabs(fulltime/3600.)));
/* Subtract the hour component from the total */
fulltime -= sgn(fulltime) * 3600. * floor(fabs(fulltime/3600.));
break;
case 'M':
/* +/- fractional minutes (not wrapped at 60m) */
if (p > 0) {
incr = snprintf(s, bsz-l-1, "%*.*f", w, p,
sign_printed ? fabs(fulltime)/60. : fulltime/60.);
CHECK_SPACE(incr);
break;
}
/* +/- integral minute truncated toward zero */
tminute = floor((fabs(fulltime/60.)));
if (fulltime < 0 && !sign_printed) {
*s++ = '-';
l++;
}
sign_printed = TRUE;
FORMAT_STRING(1, 2, tminute); /* %02d */
/* Subtract the minute component from the total */
fulltime -= sgn(fulltime) * 60. * floor(fabs(fulltime/60.));
break;
case 'S':
/* +/- fractional seconds */
tsecond = floor(fabs(fulltime));
if (fulltime < 0) {
if (usec > 0)
usec = 1.0 - usec;
if (!sign_printed) {
*s++ = '-';
l++;
}
}
FORMAT_STRING(1, 2, tsecond); /* %02d */
if (p > 0) {
double base = pow(10., (double)p);
int msec = floor(0.5 + base * usec);
char *f = &s[strlen(s)];
CHECK_SPACE(p+1);
sprintf(f, ".%0*d", p, msec<(int)base?msec:(int)base-1);
}
break;
default:
break;
}
break;
}
case 'W': /* mon 1 day of week */
{
int week;
if (tm->tm_yday <= tm->tm_wday) {
week = 1;
if ((tm->tm_mday - tm->tm_yday) > 4) {
week = 52;
}
if (tm->tm_yday == tm->tm_wday && tm->tm_wday == 0)
week = 52;
} else {
/* sun prev week */
int bw = tm->tm_yday - tm->tm_wday;
if (tm->tm_wday > 0)
bw += 7; /* sun end of week */
week = (int) bw / 7;
if ((bw % 7) > 2) /* jan 1 is before friday */
week++;
}
FORMAT_STRING(1, 2, week); /* %02d */
break;
}
case 'U': /* sun 1 day of week */
{
int week, bw;
if (tm->tm_yday <= tm->tm_wday) {
week = 1;
if ((tm->tm_mday - tm->tm_yday) > 4) {
week = 52;
}
} else {
/* sat prev week */
bw = tm->tm_yday - tm->tm_wday - 1;
if (tm->tm_wday >= 0)
bw += 7; /* sat end of week */
week = (int) bw / 7;
if ((bw % 7) > 1) { /* jan 1 is before friday */
week++;
}
}
FORMAT_STRING(1, 2, week); /* %02d */
break;
}
case 'w': /* day of week, sun=0 */
FORMAT_STRING(1, 2, tm->tm_wday); /* %02d */
break;
case 'y':
FORMAT_STRING(1, 2, tm->tm_year % 100); /* %02d */
break;
case 'Y':
FORMAT_STRING(1, 4, tm->tm_year); /* %04d */
break;
} /* switch */
while (*s != '\0') {
s++;
l++;
}
#undef CHECK_SPACE
#undef COPY_STRING
#undef FORMAT_STRING
} /* switch(fmt letter) */
} /* if(fmt letter not '%') */
return (l);
}
/* time_t */
double
gtimegm(struct tm *tm)
{
int i;
/* returns sec from year ZERO_YEAR, defined in gp_time.h */
double dsec = 0.;
if (tm->tm_year < ZERO_YEAR) {
for (i = tm->tm_year; i < ZERO_YEAR; i++) {
dsec -= (double) gdysize(i);
}
} else {
for (i = ZERO_YEAR; i < tm->tm_year; i++) {
dsec += (double) gdysize(i);
}
}
if (tm->tm_mday > 0) {
for (i = 0; i < tm->tm_mon; i++) {
dsec += (double) mndday[i] + (i == 1 && (gdysize(tm->tm_year) > 365));
}
dsec += (double) tm->tm_mday - 1;
} else {
dsec += (double) tm->tm_yday;
}
dsec *= (double) 24;
dsec += tm->tm_hour;
dsec *= 60.0;
dsec += tm->tm_min;
dsec *= 60.0;
dsec += tm->tm_sec;
FPRINTF((stderr, "broken-down time : %02d/%02d/%d:%02d:%02d:%02d = %g seconds\n", tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_hour,
tm->tm_min, tm->tm_sec, dsec));
return (dsec);
}
int
ggmtime(struct tm *tm, double l_clock)
{
/* l_clock is relative to ZERO_YEAR, jan 1, 00:00:00,defined in plot.h */
int i, days;
/* dodgy way of doing wday - i hope it works ! */
int wday = JAN_FIRST_WDAY; /* eg 6 for 2000 */
FPRINTF((stderr, "%g seconds = ", l_clock));
if (fabs(l_clock) > 1.e12) { /* Some time in the year 33688 */
int_warn(NO_CARET, "time value out of range");
return(-1);
}
tm->tm_year = ZERO_YEAR;
tm->tm_mday = tm->tm_yday = tm->tm_mon = tm->tm_hour = tm->tm_min = tm->tm_sec = 0;
if (l_clock < 0) {
while (l_clock < 0) {
int days_in_year = gdysize(--tm->tm_year);
l_clock += days_in_year * DAY_SEC; /* 24*3600 */
/* adding 371 is noop in modulo 7 arithmetic, but keeps wday +ve */
wday += 371 - days_in_year;
}
} else {
for (;;) {
int days_in_year = gdysize(tm->tm_year);
if (l_clock < days_in_year * DAY_SEC)
break;
l_clock -= days_in_year * DAY_SEC;
tm->tm_year++;
/* only interested in result modulo 7, but %7 is expensive */
wday += (days_in_year - 364);
}
}
tm->tm_yday = (int) (l_clock / DAY_SEC);
l_clock -= tm->tm_yday * DAY_SEC;
tm->tm_hour = (int) l_clock / 3600;
l_clock -= tm->tm_hour * 3600;
tm->tm_min = (int) l_clock / 60;
l_clock -= tm->tm_min * 60;
tm->tm_sec = (int) l_clock;
days = tm->tm_yday;
/* wday%7 should be day of week of first day of year */
tm->tm_wday = (wday + days) % 7;
while (days >= (i = mndday[tm->tm_mon] + (tm->tm_mon == 1 && (gdysize(tm->tm_year) > 365)))) {
days -= i;
tm->tm_mon++;
}
tm->tm_mday = days + 1;
FPRINTF((stderr, "broken-down time : %02d/%02d/%d:%02d:%02d:%02d\n", tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec));
return (0);
}
#else /* USE_SYSTEM_TIME */
/* define gnu time routines in terms of system time routines */
size_t
gstrftime(char *buf, size_t bufsz, const char *fmt, double l_clock)
{
time_t t = (time_t) l_clock;
return strftime(buf, bufsz, fmt, gmtime(&t));
}
double
gtimegm(struct tm *tm)
{
return (double) mktime(tm);
}
int
ggmtime(struct tm *tm, double l_clock)
{
time_t t = (time_t) l_clock;
struct tm *m = gmtime(&t);
*tm = *m; /* can any non-ansi compilers not do this ? */
return 0;
}
/* supplemental routine gstrptime() to read a formatted time */
char *
gstrptime(char *s, char *fmt, struct tm *tm)
{
FPRINTF((stderr, "gstrptime(\"%s\", \"%s\")\n", s, fmt));
/* linux does not appear to like years before 1902
* NT complains if its before 1970
* initialise fields to midnight, 1st Jan, 1970 (for relative times)
*/
tm->tm_sec = tm->tm_min = tm->tm_hour = 0;
tm->tm_mday = 1;
tm->tm_mon = 0;
tm->tm_year = 70;
/* oops - it goes wrong without this */
tm->tm_isdst = 0;
for (; *fmt && *s; ++fmt) {
if (*fmt != '%') {
if (*s != *fmt)
return s;
++s;
continue;
}
assert(*fmt == '%');
switch (*++fmt) {
case 0:
/* uh oh - % is last character in format */
return s;
case '%':
/* literal % */
if (*s++ != '%')
return s - 1;
continue;
#define NOTHING /* nothing */
#define LETTER(L, width, field, extra) \
case L: \
s=read_int(s,width,&tm->field); \
extra; \
continue;
LETTER('d', 2, tm_mday, NOTHING);
LETTER('m', 2, tm_mon, NOTHING);
LETTER('y', 2, tm_year, NOTHING);
LETTER('Y', 4, tm_year, tm->tm_year -= 1900);
LETTER('H', 2, tm_hour, NOTHING);
LETTER('M', 2, tm_min, NOTHING);
LETTER('S', 2, tm_sec, NOTHING);
#undef NOTHING
#undef LETTER
default:
int_error(DATAFILE, "incorrect time format character");
}
}
FPRINTF((stderr, "Before mktime : %d/%d/%d:%d:%d:%d\n", tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec));
/* mktime range-checks the time */
if (mktime(tm) == -1) {
FPRINTF((stderr, "mktime() was not happy\n"));
int_error(DATAFILE, "Invalid date/time [mktime() did not like it]");
}
FPRINTF((stderr, "After mktime : %d/%d/%d:%d:%d:%d\n", tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_hour, tm->tm_min, tm->tm_sec));
return s;
}
#endif /* USE_SYSTEM_TIME */