[net.sources] date+ - print date plus specified time increment

rod@pecnos.UUCP (Robert O. Domitz) (02/20/86)

I have found this program useful over the past eight months.  About four
months ago, I was moved to a XELOS system (our proprietary version of
System V) and found the format options of the 'date(1)' routine.  To make
the program more useful, I modified Dan LaLiberte's set of options to
more closely imitate the set of options in the 'date(1)' routine.  Although
I've been using this now for about three months in this form, my workload
has finally slowed down enough to allow me the time to post this to 
net.sources.

I would like to thank Dan LaLiberte for posting his original routine.
To give credit where credit is due, here are excerpts from the header
of the original posting:

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Path: petsd!vax135!houxm!ihnp4!inuxc!pur-ee!uiucdcs!seefromline
From: liberte@uiucdcs.Uiuc.ARPA
Subject: date+ - add specified time to date
Message-ID: <12600026@uiucdcs>
Date: Fri, 12-Jul-85 00:23:00 EDT
Date-Received: Fri, 12-Jul-85 20:07:06 EDT


The recent date-oriented postings prompted me to finally get this out.  
What prompted its creation was the fact that I had to write yet another
single-purpose add-something-to-the-current-date program.  Also, I noticed a
recent posting of a script that used `at` with a "+ #" option that we do
not have.  

Now you can do things like:
	at `date+ 2 hours` < reminder
or	set lastmonth = `date+ -1 month "%y.%n"`

Date+ has more options than I know what to do with, but it's the kind of
program that needs options.  So send me your suggestions.  It is written
for Berkeley 4.2.

Daniel LaLiberte   217-333-8426
University of Illinois, Urbana-Champaign
Department of Computer Science
1304 W Springfield
Urbana, IL  61801

liberte@uiucdcs.Uiuc.ARPA
ihnp4!uiucdcs!liberte
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# date+.1 date+.c

echo x - date+.1
cat > "date+.1" << '//E*O*F date+.1//'
.TH DATE+ 1 
.UC 4
.SH NAME
date+ \- print date plus specified time
.SH SYNOPSIS
.B date+
[
.I number unit
]... [
.I format
]
.SH DESCRIPTION
The
.I date+
command increments the current time by the specified amount of time given
as several 
.I number unit
pairs.  The
.I unit
may begin with
.B sec min hour day week mon 
or
.B year.
Trailing characters are ignored.  The positive or negative floating point
.I number
is truncated if the unit is month or year.
.de mI
.ti -4
\\$1\ \ 
..
.PP
The optional
.I format
specifies how to print out the date and time information.
A percent sign introduces a conversion operator;
the next character specifies the desired conversion.
Other characters are simply printed.
The conversion characters and their meanings are:
.sp
.in +6
.mI n
insert a newline character.
.mI t
insert a tab character.
.mI S
seconds.
.mI M
minutes.
.mI H
hours.
.mI T
time as HH:MM:SS.
.mI d
day number within the month (01-31).
.\" .mI D
.\" day number without leading zero.
.mI m
month number (01-12).
.mI h
month name (3 character).
.mI y
year number - 1900.
.mI w
weekday number (0 is Sunday).
.mI a
weekday name (3 character).
.mI D
date as mm/dd/yy.
.mI j
day number within the year (1-365).
.mI Z
number of seconds since 00:00:00 GMT Jan 1, 1970.
.in -6
.ne 7
.PP
The default format is
.ti +2
.nf
"%H:%M %h %d"
.fi
which is suitable as input to the 
.I at (1)
command.
Note that if the format string has any special characters
(including spaces) then they must be protected by quoting.
.SH EXAMPLE
.nf
at `date+ 2 hours`
echo Time for a break > /dev/ttyme
^D
date+ -1 month "%y.%n"		# Return yy.mm for previous month
.fi
.SH SEE\ ALSO
.I at (1),
.I date (1)
.SH AUTHOR
Daniel LaLiberte, University of Illinois, Urbana-Champaign
.br
System V version:
Robert O. Domitz, Concurrent Computer Corporation, Tinton Falls, NJ.
.SH BUGS
Dates that don't exist, e.g., Feb 31, can be produced by
adding months or years.  Producing dates before Jan 1, 1970
will give strange results.
//E*O*F date+.1//

echo x - date+.c
cat > "date+.c" << '//E*O*F date+.c//'
/* date+ - add specified time to current date */

/* Please send additions, bug fixes, portifications, etc. to:
 *
 *	Daniel LaLiberte
 *	ihnp4!uiucdcs!liberte
 *	University of Illinois, Urbana-Champaign
 *	Department of Computer Science
 */

/* This is written for BSD42 */

/* This was revised for SYSTEM V by:
 *
 *	Robert O. Domitz
 *	...!vax135!petsd!pecnos!rod
 *	Concurrent Computer Corporation
 *	106 Apple Street
 *	Tinton Falls, NJ  07724
 */

#include <stdio.h>
#include <time.h>

long tloc;
long time();

char *ctime();
struct tm *localtime();

struct tm *ts;

double atof();


int argc;	/* global argument passing */
char **argv;



main (Argc, Argv)
/* return time + 1st arg hours */

int Argc;
char *Argv[];

{
	argc = Argc;
	argv = Argv;
	incrdate();
	printdate();

} /* main */



incrdate()	/* increment date from arguments */
{
	static char *unit[] =
	{
		"sec", "min", "hour", "day", "week", "mon", "year", ""	};

	static int conv[] =	/* conversion factor */
	{
		1, 60, 3600, 86400, 604800, 0, 0	};

	int i;
	double value;
	long total;	/* cummulative total increment in whole seconds */
	double monthincr = 0.0,	/* store increment of month and year */
	yearincr = 0.0; 	/* since months and years are not uniform */

	time(&tloc);	/* current time */
	argc--; 
	argv++;

	while (argc &&
	    ((**argv == '.') ||
	    (**argv == '-') || 
	    (**argv == '+') || 
	    (**argv >= '0' && **argv <= '9'))) {
		value = atof(argv[0]);
/*		printf("%s = %f", argv[0], value); */

		argv++; 
		argc--;
		if (argc == 0) missing();
		else {	/* search for unit */
			for (i = 0;	(i < 7) &&
				(0 != strncmp(argv[0], unit[i], 
					strlen(unit[i])));)
				i++;
			if (i == 7) missing();
			else { 
				argv++; 
				argc--;
				if (i < 5) value *= conv[i];
				if (i == 5) monthincr += value;
				if (i == 6) yearincr += value;
			}
/*			printf(" %s (%f seconds)\n", unit[i], value); */
		}

		total += value;
	}


	tloc += total;
	ts = localtime(&tloc);
	ts->tm_mon += monthincr;
	ts->tm_year += yearincr;

} /* getincr */


missing()
{
	fprintf(stderr, "date+: missing unit\n");
	exit (1);
} 


printdate()
{
	char *format;

	static char *month[] = 
	    {
		"Jan", "Feb", "Mar", "Apr", "May", "Jun", 
		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"	};

	static char *day[] =
	    {
		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"	};


	if (argc == 0) {	/* put default format on argv */
		argv[0] = "%H:%M %h %d";
		argc++;
	}

	while (argc > 0) {
		format = argv[0];

		while (*format) {
			if (*format != '%')
				putchar(*format);
			else if (format[1]) 

				switch(*++format) {
				case 'n':
					putchar ('\n');
					break;
				case 't':
					putchar ('\t');
					break;
				case 'S': 
					printf("%02d", ts->tm_sec);  
					break;
				case 'Z': 
					printf("%d", tloc);  
					break;
				case 'M': 
					printf("%02d", ts->tm_min);  
					break;
				case 'H': 
					printf("%02d", ts->tm_hour);  
					break;
				case 'T':
					printf("%02d:%02d:%02d",
						ts->tm_hour, ts->tm_min,
						ts->tm_sec);
					break;
				case 'd': 
					printf("%02d", ts->tm_mday);  
					break;
/*				case 'D': 
					printf("%d", ts->tm_mday);  
					break;			*/
				case 'm': 
					printf("%02d", ts->tm_mon + 1);  
					break;
				case 'h': 
					printf("%s", month[ts->tm_mon]);  
					break;
				case 'y': 
					printf("%02d", ts->tm_year);  
					break;
				case 'w': 
					printf("%1d", ts->tm_wday);  
					break;
				case 'a': 
					printf("%s", day[ts->tm_wday]);  
					break;
				case 'D':
					printf("%02d/%02d/%02d",
						ts->tm_mon + 1, ts->tm_mday,
						ts->tm_year);
					break;
				case 'j': 
					printf("%d", ts->tm_yday);  
					break;

				default:  
	fprintf(stderr, "date+: Bad format character: '%c'\n", *format); 
					exit(1);
				}

			format++;
		} /* while (*format) */

		argc--; 
		argv++;
		if (argc > 0) 
			putchar(' ');
	} /* while (argc > 0) */

	putchar('\n');
} /* printdate */
//E*O*F date+.c//

echo Possible errors detected by \'wc\' [hopefully none]:
temp=/tmp/shar$$
trap "rm -f $temp; exit" 0 1 2 3 15
cat > $temp <<\!!!
    104    364   1995 date+.1
    219    542   3916 date+.c
    323    906   5911 total
!!!
wc  date+.1 date+.c | sed 's=[^ ]*/==' | diff -b $temp -
exit 0