slicing the date
John Woods
john at frog.UUCP
Tue Apr 4 04:38:00 AEST 1989
> I have tried the '+' notation on the 'date' command to get it to format its
> output. The OS running here (I believe 4.3BSD) does not accept that.
The following is a date program which I firmly believe matches the manual
page for DATE(BU_CMD) from the SVID Issue 2. (if not, I'd appreciate hearing
about what I screwed up) It includes code for setting the date, but you
might want to #define NOSETDATE and install this as "Date" rather than trust
it to be the real thing. Note that doing the date formatting stuff took only
about half an hour, including time to find out why my daughter was crying...
It uses rindex(), which you can #define to be strrchr() if you have a SysV
library.
-----------------------cut-here----------------------------------------
/*
* SVID issue 2 compliant DATE(BU_CMD) command.
*
* If you don't want to make this a real date command (likely a good idea),
* compile it with NOSETDATE to remove the setdate feature.
*
* Written by John Woods, frog!john, Sat Apr 1 13:14:00 -- 14:52:00
* (note: not an april fools' joke!)
* (K) All rights reversed
*/
#include <stdio.h>
#include <time.h>
#include <ctype.h>
extern char *ctime(), *rindex();
char *argv0 = "date";
usage() {
#ifdef NOSETDATE
fprintf(stderr,"usage:\t%s\n\t%s +format_string\n",
#else /* !NOSETDATE */
fprintf(stderr,"usage:\t%s\n\t%s mmddhhmm[yy]\n\t%s +format_string\n",
argv0,
#endif /* !NOSETDATE */
argv0,argv0);
exit(1);
}
main(argc, argv)
char **argv;
{
long now;
char *p;
if (p = rindex(argv0 = argv[0], '/'))
argv0 = p+1;
if (argc > 2) {
usage();
/* NOTREACHED */
}
if (argc < 2) {
now = time(0);
printf("%s", ctime(&now));
exit(0);
}
argv++; /* point to key argument */
if (**argv == '+') {
exit(Format(*argv));
}
#ifdef NOSETDATE
usage();
#else /* !NOSETDATE */
SetDate(*argv);
exit(0);
#endif /* !NOSETDATE */
}
Format(format)
char *format;
{
int i;
long now;
struct tm *n;
now = time(0);
n = localtime(&now);
format++; /* skip + */
while (*format) {
if (*format == '%') {
format++;
switch(*format) {
default: /* just print Q for unrecognized %Q */
case '%': putchar(*format);
break;
case '\000': putchar('%');
return 0; /* print the % */
case 'n': putchar('\n');
break;
case 't': putchar('\t');
break;
case 'm': /* month of year */
pnum2(n->tm_mon+1);
break;
case 'd': /* day of month */
pnum2(n->tm_mday);
break;
case 'y': /* last two digits of year */
/* in 2000, this becomes confusing */
pnum2(n->tm_year%100);
break;
case 'D': /* date as mm/dd/yy */
pnum2(n->tm_mon+1); putchar('/');
pnum2(n->tm_mday); putchar('/');
pnum2(n->tm_year%100);
break;
case 'H': /* hour - 00 to 23 */
pnum2(n->tm_hour); break;
case 'M': /* minute - 00 to 59 */
pnum2(n->tm_min); break;
case 'S': /* second - 00 to 61 (ANSI C and NIST fault)*/
pnum2(n->tm_sec); break;
case 'T': /* time as HH:MM:SS */
pnum2(n->tm_hour); putchar(':');
pnum2(n->tm_min); putchar(':');
pnum2(n->tm_sec); break;
case 'j': /* julienne day - 001 to 366 */
/* yes, I know it is supposed to be called
* Julian Day, but that really IS something
* quite different, so I deliberately
* mispeled it.
*/
pnum3(n->tm_yday+1); break;
case 'w': /* day of week - Sunday = 0 */
putchar('0' + n->tm_wday);
break;
case 'a': /* abbr. day of week */
printf("%3.3s",
&"SunMonTueWedThuFriSat"[n->tm_wday*3]
);
break;
case 'h': /* abbr. month */
printf("%3.3s",
&"JanFebMarAprMayJunJulAugSepOctNovDec"
[n->tm_mon*3]
);
break;
case 'r': /* time in am/pm notation */
i = n->tm_hour%12; if (i == 0) i = 12;
pnum2(i); putchar(':');
pnum2(n->tm_min); putchar(':');
pnum2(n->tm_sec); putchar(' ');
putchar(n->tm_hour > 11 ? 'P' : 'A');
putchar('M');
break;
}
}
else putchar(*format);
format++;
}
putchar('\n');
return 0;
}
pnum2(v)
int v;
{
putchar((v/10) + '0');
putchar(v%10 + '0');
}
pnum3(v)
int v;
{
putchar((v/100) + '0');
v %= 100;
putchar((v/10) + '0');
putchar(v%10 + '0');
}
#ifndef NOSETDATE
/* note: this table is editted for non-leap years*/
int monthlen[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
#define SECPERMIN 60
#define SECPERHOUR (60*60)
#define SECPERDAY (24*60*60)
#define SECPERYEAR (365*SECPERDAY)
SetDate(sd)
char *sd;
{
extern long timezone;
extern int daylight;
long now;
struct tm *nt;
int i, Year;
/* attempt time conversion */
if ((i = strlen(sd)) != 8 && i != 10) {
bad: fprintf(stderr,"date: bad conversion\n");
usage();
/* NOTREACHED */
}
for (i = 0; sd[i] != '\000'; i++)
if (!isdigit(sd[i])) {
goto bad;
}
nt = localtime(&now);
if (i == 10) {
nt->tm_year = (sd[8]-'0')*10 + sd[9]-'0';
if (nt->tm_year < 70) nt->tm_year += 100;
}
Year = 1900 + nt->tm_year;
/* between 1970 and 2069, there are no non-leap century years,
* so Year%4 is a good enough "isleap()"
*/
if (Year%4) monthlen[1] = 28; /* not a leap year */
nt->tm_mon = (sd[0]-'0')*10 + sd[1]-'0';
if (nt->tm_mon < 1 || nt->tm_mon > 12) goto bad;
nt->tm_mon--; sd+=2;
nt->tm_mday = (sd[0]-'0')*10 + sd[1]-'0';
if (nt->tm_mday < 1 || nt->tm_mday > monthlen[nt->tm_mon])
goto bad;
sd += 2;
nt->tm_hour = (sd[0]-'0')*10 + sd[1]-'0';
if (nt->tm_hour > 23) goto bad;
sd += 2;
nt->tm_min = (sd[0]-'0')*10 + sd[1]-'0';
if (nt->tm_min > 59) goto bad;
/* now calculate seconds from ORIGIN */
now = nt->tm_hour * (SECPERHOUR) + nt->tm_min * SECPERMIN;
for (i = 1970; i < Year; i++) {
now += SECPERYEAR;
if (i%4 == 0) now += SECPERDAY;
}
for (i = 0; i < nt->tm_mon; i++) {
now += monthlen[i]*SECPERDAY;
}
now += (nt->tm_mday-1)*SECPERDAY;
/* Now we have a local time, turn it into GMT */
now += timezone;
if (daylight) {
/* see if we need to correct for DST */
nt = localtime(&now);
if (nt->tm_isdst) now -= SECPERHOUR; /* spring ahead */
/* except GMT is behind us */
}
if (stime(&now) < 0) {
perror("date: cannot set date\n");
exit(2);
}
printf("%s", ctime(&now));
}
#endif /* !NOSETDATE */
--
John Woods, Charles River Data Systems, Framingham MA, (508) 626-1101
...!decvax!frog!john, john at frog.UUCP, ...!mit-eddie!jfw, jfw at eddie.mit.edu
Remainder Khomeini!
More information about the Comp.unix.questions
mailing list