/* ======================================================= *
* Copyright 1998-2005 Stephen C. Grubb *
* http://ploticus.sourceforge.net *
* Covered by GPL; see the file ./Copyright for details. *
* ======================================================= */
/* TIMES.C - time arithmetic and format conversion library */
#include <stdio.h>
#include <string.h>
#include <ctype.h>
extern int TDH_err(), GL_systime(), DT_maketime();
/* Compile flag NO_DT may be used to disable all date/time functionality.
standard units = (double) minutes since 0:00:00.0
--seconds are expressed as decimal portion of 1 minute
input formats for which arithmetic is supported:
format input output
HHMM hh:mm or hh:mm:ss (output is hh:mm)
HHMMSS hh:mm or hh:mm:ss (output is hh:mm:ss)
MMSS mm:ss (output is mm:ss)
output formats: hh:mm hh:mma hh:mm:ss hh:mm:ssa mm:ss
(a=use am/pm notation; A yeilds capitals e.g. AM or PM)
For any arithmetic or output format, the decimal format of the seconds
component can be controlled by using a printf double format spec instead
of 'ss'. For example: hh:mm:%02.2f
To get current time in minutes past midnight, use tomin( "now", &sec );
To get current time in current format use frommin( -1.0, result );
*/
#ifndef NO_DT
#define HHMM 0
#define MMSS 1
#define HHMMSS 2
#define stricmp(s,t) strcasecmp(s,t)
#define strnicmp(s,t,u) strncasecmp(s,t,u)
#define err(a,b,c) TDH_err(a,b,c)
#define NUMBER 0
#define ALPHA 1
static int format = HHMM;
static int Hr = 0, Min = 0;
static double Sec = 0.0;
static char Dispfmt[30] = "%d:%02d";
static char Curfmt[30] = "hh:mm";
static int Nodaylimit = 0;
#endif
double atof();
/* ============================= */
int
DT_time_initstatic()
{
Hr = 0; Min = 0; Sec = 0.0;
strcpy( Dispfmt, "%d:%02d" );
strcpy( Curfmt, "hh:mm" );
return( 0 );
}
/* ============================= */
/* SETTIMEFMT - set the "current time format" */
int
DT_settimefmt( fmt )
char *fmt;
{
#ifdef NO_DT
return( err( 7950, "date/time support not included in this build", "" ));
}
#else
/* hhh = hours not limited to one day, eg. 32:00 or 122:44 would be valid - scg 6/18/03 */
if( strncmp( fmt, "hhh", 3 )==0 ) {
Nodaylimit = 1;
strcpy( fmt, &fmt[1] );
}
if( stricmp( fmt, "hh:mm" )==0 ) {
strcpy( Dispfmt, "%d:%02d" );
format = HHMM;
}
else if( strnicmp( fmt, "mm:", 3 )==0 ) {
format = MMSS;
if( fmt[3] == 's' ) strcpy( Dispfmt, "%d:%02g" ); /* added 3/3/02 */
else sprintf( Dispfmt, "%%d:%s", &fmt[3] ); /* added 3/3/02 */
}
else if( strnicmp( fmt, "hh:mm:", 6 )==0 ) {
format = HHMMSS;
if( fmt[6] == 's' ) strcpy( Dispfmt, "%d:%02d:%02g" ); /* added 3/3/02 */
else sprintf( Dispfmt, "%%d:%%02d:%s", &fmt[6] ); /* added 3/3/02 */
}
else return( -1 );
strcpy( Curfmt, fmt );
return( 0 );
}
/* ============================= */
/* TOMIN - take a time in the "current format" and return # minutes since 00:00:00 */
/* Return 0 on valid input; return non-zero on invalid input */
int
DT_tomin( s, result )
char *s; /* time */
double *result; /* returned */
{
int i;
char t[128];
int nt;
int tlen;
if( stricmp( s, "now" )==0 ) {
GL_systime( &Hr, &Min, &i );
Sec = (double)i;
DT_maketime( Hr, Min, Sec, t );
}
else strcpy( t, s );
/* validate t */
tlen = strlen( t );
if( !isdigit( (int) t[0]) || !isdigit( (int) t[tlen-1]) /* || !isdigit( (int) t[tlen-2]) */ ) /* relaxed 7/17/01 */
{ *result = 0.0; return( 1 ); }
if( format == HHMM || format == HHMMSS ) {
if( tlen < 3 ) { *result = 0.0; return( 2 ); } /* sanity check */
Sec = 0.0;
nt = sscanf( t, "%d:%d:%lf", &Hr, &Min, &Sec );
if( nt == 2 ) *result = (Hr * 60.0) + Min;
else if( nt == 3 ) *result = (Hr * 60.0) + Min + (Sec/60.0);
else { *result = 0.0; return( 3 ); } /* error */
if( Hr < 0 || Min > 59 || Min < 0 || Sec >= 60.0 || Sec < 0.0 ) return( 5 ); /* scg 6/18/03 */
if( !Nodaylimit && ( Hr > 24 || ( Hr == 24 && Min != 0 ))) return( 5 ); /* scg 6/18/03 */
return( 0 );
}
else if( format == MMSS ) {
if( strlen( s ) < 4 ) { *result = 0.0; return( 4 ); } /* sanity check */
nt = sscanf( s, "%d:%lf", &Min, &Sec );
if( nt != 2 ) { *result = 0.0; return( 6 ); } /* error */
if( Min > 59 || Min < 0 || Sec >= 60.0 || Sec < 0.0 ) return( 7 );
*result = Min + (Sec/60.0);
}
return( 0 );
}
/* ============================ */
/* FROMMIN - take # minutes since 00:00:00 and return time string in current format */
int
DT_frommin( s, result )
double s; /* sec may be < 0 for "now" */
char *result;
{
int i;
if( s < 0.0 ) {
GL_systime( &Hr, &Min, &i );
Sec = (double)i;
}
else {
Hr = (int)(s/60.0);
Min = ((int)(s)-(Hr*60));
/* Sec = s - (double)((Hr*60) + (Min)); */ /* fixed scg 3/1/02 */
Sec = (s - (double)((Hr*60) + (Min))) * 60.0;
if( Sec < 0.0000001 ) Sec = 0.0; /* adjust for rounding error */
}
if( !Nodaylimit && Hr == 24 && Min == 0 && Sec == 0 ) Hr = 0; /* scg 9/29/03 */
DT_maketime( Hr, Min, Sec, result );
return( 0 );
}
/* ============================= */
/* GETHMS - get hour, min, sec components of most recent time
processed by tomin() for frommin() */
int
DT_gethms( hour, min, sec )
int *hour, *min;
double *sec;
{
*hour = Hr;
*min = Min;
*sec = Sec;
return( 0 );
}
/* ============================= */
/* MAKETIME - given h m s, build time string using current format. */
int
DT_maketime( hr, min, sec, result )
int hr, min;
double sec;
char *result;
{
if( format == HHMM ) sprintf( result, Dispfmt, hr, min );
else if( format == MMSS ) sprintf( result, Dispfmt, min, sec );
else if( format == HHMMSS ) sprintf( result, Dispfmt, hr, min, sec );
return( 0 );
}
/* ============================== */
/* take time in current format and convert to outformat */
int
DT_formattime( s, outformat, result )
char *s, *outformat, *result;
{
char oldformat[30];
double min;
char c;
char ampm[4];
char fmt[40];
int i;
strcpy( fmt, outformat );
DT_tomin( s, &min );
/* in case we do am/pm */
strcpy( ampm, "" );
c = fmt[ strlen( fmt ) - 1];
if( c == 'a' || c == 'A' ) {
if( Hr == 12 && Min == 0 ) strcpy( ampm, "N" ); /* scg 2/27/02 */
else if( Hr >= 12 && Hr < 24 ) strcpy( ampm, "PM" ); /* added < 24 scg 2/27/02 */
else strcpy( ampm, "AM" );
if( c == 'a' ) for( i = 0; ampm[i] != '\0'; i++ ) ampm[i] = tolower(ampm[i]);
fmt[ strlen( fmt ) - 1 ] = '\0';
if( Hr > 12 ) {
min -= 720.0;
Hr -= 12;
}
}
if( stricmp( fmt, "hh" )==0 ) sprintf( result, "%02d", Hr );
else if( stricmp( fmt, "h" )==0 ) sprintf( result, "%0d", Hr );
else if( stricmp( fmt, "mm" )==0 ) sprintf( result, "%02d", Min );
else if( stricmp( fmt, "m" )==0 ) sprintf( result, "%d", Min );
else if( stricmp( fmt, "ss" )==0 ) sprintf( result, "%g", Sec );
else if( fmt[0] == '%' ) sprintf( result, fmt, Sec );
else {
strcpy( oldformat, Curfmt ); /* scg 3/3/02 */
DT_settimefmt( fmt );
DT_frommin( min, result );
DT_settimefmt( oldformat ); /* scg 3/3/02 */
/* format = oldformat; */
}
if( ampm[0] != '\0' ) {
if( result[0] == '0' && result[1] != ':' ) sprintf( result, "%s%s", &result[1], ampm );
else strcat( result, ampm );
}
return( 0 );
}
/* =============================== */
/* TIMEDIFF - find difference between two times */
int
DT_timediff( s1, s2, diff )
char *s1, *s2;
double *diff; /* s1-s2 difference in minutes */
{
double min1, min2;
DT_tomin( s1, &min1 );
DT_tomin( s2, &min2 );
*diff = min1 - min2;
return( 0 );
}
#endif
/* =============================== */
/* TIMEFUNCTIONS - script entry point for time functions.
Return 0 if function found and executed normally.
Return 1 on error.
Return 2 if function not found here.
*/
int
DT_timefunctions( hash, name, arg, nargs, result, typ )
int hash;
char *name;
char *arg[];
int nargs;
char *result;
int *typ;
{
int stat;
#ifdef NO_DT
return( err( 198, "time functions not supported in this build", "" ));
}
#else
*typ = ALPHA;
if( hash == 400 ) { /* $tomin(t) take t (a value in the current time notation). Result is the equivalent,
expressed in # of minutes since 0:00:00. Result is float,
with any seconds expressed as the decimal portion of a minute. */
double f;
stat = DT_tomin( arg[0], &f );
sprintf( result, "%g", f );
*typ = NUMBER;
return( 0 );
}
if( hash == 1348 ) { /* $formattime() */
stat = DT_formattime( arg[0], arg[1], result );
if( stat != 0 ) { err( 1697, "$formattime failed", arg[1] ); return( 1 ); }
return( 0 );
}
if( hash == 1002 ) { /* $timevalid() */
double x;
stat = DT_tomin( arg[0], &x );
if( stat == 0 ) sprintf( result, "1" );
else sprintf( result, "0" );
*typ = NUMBER;
return( 0 );
}
if( hash == 706 ) { /* $frommin(m) inverse of $tomin(), where m is a float minutes value.
* Result is equivalent time in current notation. */
stat = DT_frommin( atof( arg[0] ), result );
return( 0 );
}
if( hash == 753 ) { /* $timediff(t1,t2) - find the difference between two times (both in
* current notation). Result is expressed in float minutes (any
* seconds expressed as fraction of a minute) */
double diff;
DT_timediff( arg[0], arg[1], &diff );
sprintf( result, "%g", diff );
*typ = NUMBER;
return( 0 );
}
if( hash == 1397 ) { /* $settimefmt(fmt) - set the "current time format" */
stat = DT_settimefmt( arg[0] );
if( stat != 0 ) {
err( 1614, "$settimefmt - invalid format", arg[0] );
return( 1 );
}
strcpy( result, "0" );
*typ = NUMBER;
return( 0 );
}
if( hash == 262 ) { /* $time() - result is current time in hh:mm:ss format */
int hr, min, sec;
GL_systime( &hr, &min, &sec );
sprintf( result, "%02d:%02d:%02d", hr, min, sec );
return( 0 );
}
if( hash == 621 ) { /* $timesec() - return number of seconds since midnight for current time */
int hr, min, sec;
GL_systime( &hr, &min, &sec );
sprintf( result, "%ld", (((hr*(long)60) + min)*(long)60) + sec );
*typ = NUMBER;
return( 0 );
}
return( err( 198, "unrecognized function", name ) );
}
#endif
/* ======================================================= *
* Copyright 1998-2005 Stephen C. Grubb *
* http://ploticus.sourceforge.net *
* Covered by GPL; see the file ./Copyright for details. *
* ======================================================= */
syntax highlighted by Code2HTML, v. 0.9.1