/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- datime_month_name_2_num
- datime_month_num_2_name
- get_ftime
- get_time
- datime_hour12_2_hour24
- datime_get_ampm
- run_year
- days_in_month
- isleap
- juldate
- datdif
/* Date/time functions
Rick Smereka, Copyright (C) 2002-2004.
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 of the License, or
(at your option) any later version.
This program 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 program; if not, get a copy via the Internet at
http://gnu.org/copyleft/gpl.html or write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston,
MA 02111-1307 USA
You can contact the author via email at rsmereka@future-lab.com
Original Linux version. Moved function 'get_time' from 'parse.c'
to this module. May/2002, Rick Smereka
Ported to 32-bit Windows. Jun/2002, Rick Smereka
Ported to DOS and QNX 4.x. Jul/2002, Rick Smereka
Changed function 'get_time' to return a compact date/time
string instead of using 'asctime'. Sep/2002, Rick Smereka
Ported to Debian Linux. Oct/2002, Rick Smereka
Added functions 'run_year' and 'get_ftime'.
Ported to Debian Linux. Nov/2002, Rick Smereka
Added functions 'days_in_month' and 'isleap'.
Jan/2004, Rick Smereka
Added functions 'juldate' and 'datdif'. Dec/2004,
Rick Smereka */
#include "stdhead.h"
// julian base year
#define DATIME_JUL_BASE 1954
/* month short names */
char *smonth[] = { "", "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
"JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
/* private function */
static int datime_get_ampm(char *, char *);
int datime_month_name_2_num(char *mname)
{
/* Convert a month name to a month number. Only the first three
characters of the month name are compared so you may use the
long or short month names. January is considered month one.
Function returns the month number upon success, zero otherwise. */
int len, i;
if (mname == (char *)NULL)
return(FALSE);
len = strlen(mname);
/* must have a minimum of three characters */
if (len < 3)
return(FALSE);
for(i = 1; i <= 12; i++)
if (!strnicmp(smonth[i], mname, 3))
return(i);
return(FALSE);
}
int datime_month_num_2_name(int mnum, char *mname)
{
/* Translate a month number (1=Jan) to the short month name.
Function returns 'TRUE' upon success with the month name
loaded into 'mname' (which must already be allocated to
sufficient size by the caller), 'FALSE' otherwise. */
if (mnum <= 0 || mnum > 12)
return(FALSE);
if (mname == (char *)NULL)
return(FALSE);
strcpy(mname, smonth[mnum]);
return(TRUE);
}
void get_ftime(char *tbuf)
{
/* Format and return the current time string. Returned format is:
yyyy/mm/dd hh:mm:ss
Buffer 'tbuf' must already be allocated by the caller
to a minimum size of 20 bytes. */
char raw_time[15], year[5], month[3], day[3], hour[3];
char minute[3], second[3];
get_time(raw_time);
strncpy(year, raw_time, 4);
year[4] = EOS;
strncpy(month, &raw_time[4], 2);
month[2] = EOS;
strncpy(day, &raw_time[6], 2);
day[2] = EOS;
strncpy(hour, &raw_time[8], 2);
hour[2] = EOS;
strncpy(minute, &raw_time[10], 2);
minute[2] = EOS;
strncpy(second, &raw_time[12], 2);
second[2] = EOS;
sprintf(tbuf, "%s/%s/%s %s:%s:%s", year, month, day, hour, minute, second);
}
void get_time(char *tbuf)
{
/* Format and return the current time string. Format of the time string
is:
yyyymmddhhmmss
Buffer 'tbuf' must be allocated to at least 15 bytes by the caller. */
time_t tod;
struct tm *tmbuf;
if (tbuf == (char *)NULL)
return;
tod = time(NULL);
tmbuf = localtime(&tod);
sprintf(tbuf, "%d%02d%02d%02d%02d%02d", tmbuf->tm_year + 1900,
tmbuf->tm_mon + 1, tmbuf->tm_mday, tmbuf->tm_hour,
tmbuf->tm_min, tmbuf->tm_sec);
}
int datime_hour12_2_hour24(char *intime, char *outime, int sep_flag)
{
/* Convert a time string expressed in 12 hour format
to a time string expressed in 24 format. The input
time string ('intime') may be in any of the following
formats:
hh[:mm][:ss]p, hh[:mm][:ss] p, hh[:mm][:ss]pm, hh[:mm][:ss] pm
hh[:mm][:ss]a, hh[:mm][:ss] a, hh[:mm][:ss]am, hh[:mm][:ss] am
hh[:mm][:ss]m, hh[:mm][:ss] m, hh[:mm][:ss]n, hh[:mm][:ss] n
Where 'p' and 'pm' are the same, 'a' and 'am' are also the
same. A trailing 'm' indicates midnight and a trailing
'n' indicates noon. When a trailing 'm' or 'n' is used,
the time is assumed to be '12:00' regardless of any
other hour/minute value. Spaces may or may not be present
after the time and before the 'am' or 'pm' designator. The
colon separator is required in the input time string. The flag
'sep_flag' is used to indicate whether the output time
string should have a colon separator. The minute and seconds fields
are completly optional. The output time string always contains
two digits each for the hour, minute and optional seconds.
The hour and minute are always present in the output string.
Seconds are only present in the output string if present in
the input string. Function returns 'TRUE' with the converted
time loaded into 'outime' upon success. Function returns
'FALSE' otherwise. */
char *new_inp, wrd[10], ap;
int hr, min, sec, is_sec, nwords, len, i;
if (intime == (char *)NULL || !strlen(intime))
return(FALSE);
if (outime == (char *)NULL)
return(FALSE);
outime[0] = EOS;
len = strlen(intime);
hr = min = sec = is_sec = 0;
ap = EOS;
if ((new_inp = (char *)malloc(len + 1)) == (char *)NULL)
return(FALSE);
/* remove all spaces from the input time string */
strip_space(intime, new_inp);
nwords = ll_words(new_inp, ':');
if (nwords > 3)
{
free(new_inp);
return(FALSE);
}
/* take apart input time string */
for(i = 1; i <= nwords; i++)
{
if (!ll_word(new_inp, wrd, i, ':'))
{
free(new_inp);
return(FALSE);
}
/* on the last part of the input time string, get
the 'am'/'pm' designator */
if (i == nwords)
if (!datime_get_ampm(wrd, &ap))
{
free(new_inp);
return(FALSE);
}
switch(i)
{
case 1:
/* hour */
if (!qatoi(wrd, &hr))
{
free(new_inp);
return(FALSE);
}
break;
case 2:
/* minute */
if (!qatoi(wrd, &min))
{
free(new_inp);
return(FALSE);
}
break;
case 3:
/* second */
if (!qatoi(wrd, &sec))
{
free(new_inp);
return(FALSE);
}
is_sec = TRUE;
break;
};
}
// printf("hr=%d,min=%d,sec=%d,is_sec=%d,ap=%c\n", hr, min, sec, is_sec, ap);
free(new_inp);
/* build 24hr time */
/* first, adjust time */
switch(ap)
{
case 'A':
if (hr == 12)
hr = 0;
break;
case 'P':
/* adjust hour if necessary */
if (hr != 12)
hr += 12;
break;
case 'M':
/* midnight is always hour zero, minute zero */
hr = min = 0;
break;
case 'N':
/* noon is always hour 12, minute zero */
hr = 12;
min = 0;
break;
};
if (sep_flag)
if (is_sec)
sprintf(outime, "%02d:%02d:%02d", hr, min, sec);
else
sprintf(outime, "%02d:%02d", hr, min);
else
if (is_sec)
sprintf(outime, "%02d%02d%02d", hr, min, sec);
else
sprintf(outime, "%02d%02d", hr, min);
return(TRUE);
}
static int datime_get_ampm(char *wrd, char *ap)
{
/* Get the 'am', 'pm' designator in the time string 'wrd'.
If found, the designator will be removed from 'wrd' and
a single character will be loaded into 'ap'. Acceptable
designators are 'a', 'am', 'p', 'pm', 'n' and 'm'.
Function returns 'TRUE' upon success, 'FALSE' otherwise. */
char ch;
int len, i, pos;
if (wrd == (char *)NULL || !strlen(wrd))
return(FALSE);
if (ap == (char *)NULL)
return(FALSE);
len = strlen(wrd);
*ap = EOS;
/* loop to identify the designator */
for(i = 0, pos = 0; i < len; i++)
{
ch = toupper(wrd[i]);
if (ch >= '0' && ch <= '9')
continue;
/* set position of first non-digit */
if (!pos)
pos = i;
/* if it's a space, ignore */
if (ch == ' ')
continue;
/* load first character of designator */
*ap = ch;
break;
}
/* error on no designator */
if (*ap == EOS)
return(FALSE);
/* designator must be on of 'a', 'p', 'm' or 'n' */
if (*ap != 'A' && *ap != 'P' && *ap != 'M' && *ap != 'N')
{
*ap = EOS;
return(FALSE);
}
/* elimiate designator */
wrd[pos] = EOS;
return(TRUE);
}
int run_year(void)
{
/* Get the year of program run via 'get_time' function.
Function returns year as a number upon success,
zero otherwise. */
char tbuf[20], year_char[5];
int year;
get_time(tbuf);
strncpy(year_char, tbuf, 4);
year_char[4] = EOS;
if (!qatoi(year_char, &year))
return(0);
return(year);
}
int days_in_month(int year, int month)
{
/* Determine the number of days in a month taking into account
leap years. Function returns the number of days in 'month'
upon success, zero otherwise. */
static int numdays[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int leap;
if (month < 1 || month > 12)
return(0);
leap = isleap(year);
if (month == 2 && leap)
return(29);
return(numdays[month]);
}
int isleap(int year)
{
/* Determine whether the 'year' is a leap year. Function returns
'TRUE' if the 'year' is a leap year, 'FALSE' otherwise. */
return((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
}
int juldate(char *dte, int *julout)
{
/* Convert a date in the form 'yyyymmdd' to a Julian
value using 'DATIME_JUL_BASE' as the base year. Function
returns 'TRUE' upon success with the julian date
value loaded into 'julout' upon success. Function
returns 'FALSE' otherwise. */
char tmp[5];
int d_year, d_mo, d_day, ret, i;
if (dte == (char *)NULL || strlen(dte) != 8)
return(FALSE);
if (julout == (int *)NULL)
return(FALSE);
*julout = 0;
strncpy(tmp, dte, 4);
tmp[4] = EOS;
if (!qatoi(tmp, &d_year))
return(FALSE);
strncpy(tmp, &dte[4], 2);
tmp[2] = EOS;
if (!qatoi(tmp, &d_mo))
return(FALSE);
strncpy(tmp, &dte[6], 2);
tmp[2] = EOS;
if (!qatoi(tmp, &d_day))
return(FALSE);
ret = d_day;
// for every month preceding the current, add days
for(i = 1; i < d_mo; i++)
ret += days_in_month(d_year, i);
// add days from preceding years
for(i = DATIME_JUL_BASE; i < d_year; i++)
if (isleap(i))
ret += 366;
else
ret += 365;
*julout = ret;
return(TRUE);
}
int datdif(char *d1, char *d2, int *dif)
{
/* Find the number of days difference between two dates.
'd1' is assumed to be the later of the two dates.
Dates are expected in the form 'yyyymmdd'.
Function returns 'TRUE' upon success with the number
of days difference loaded into 'dif' upon success.
Function returns 'FALSE' otherwise. */
int jul1, jul2;
if (d1 == (char *)NULL || d2 == (char *)NULL || dif == (int *)NULL)
return(FALSE);
if (!juldate(d1, &jul1))
return(FALSE);
if (!juldate(d2, &jul2))
return(FALSE);
*dif = jul1 - jul2;
return(TRUE);
}