taylor@hplabsc.UUCP (Dave Taylor) (01/06/87)
So there I was after having used the date(1) command on HP-UX (System V with some neat enhancements, etc etc) and I got onto a Vax running BSD Unix. Well! The date(1) command on BSD doesn't have all the neat functionality that the HP-UX one has, so I rewrote the BSD date command! What follows is a *nonshar* (too lazy) that contains the "C" source to the newdate program and the man entry too. The enhancement is that the user can now specify exactly what the output format is to look like. You can now have 'date' output a format like "Today is Friday, December 12, 1986 at 4:50 pm" rather than the old, boring stuff. Neat, eh? This has been enhanced too - I've added (among others) %z to output the current timezone, so even you system V users should be interested! Bugs, etc, to comp.sources.d please. -- Dave Taylor taylor@hplabs.HP.COM -- attachment: shar files.. # Shell Archive created by hpldat!taylor at Mon Jan 5 21:33:12 1987 # To unpack the enclosed files, please use this file as input to the # Bourne (sh) shell. This can be most easily done by the command; # sh < thisfilename # This archive contains; # newdate.1 newdate.c # ---------- file newdate.1 ---------- filename="newdate.1" if [ -f $filename ] then echo File \"$filename\" already exists\! Skipping... filename=/dev/null # throw it away else echo extracting file newdate.1... fi cat << 'END-OF-FILE' > $filename .TH NEWDATE 1 LOCAL .UC 4 .SH NAME newdate \- enhanced version of date(1) .SH SYNOPSIS .B newdate .RB "[ yymmddhhmm [ " . "ss ] ]" .br .B newdate .RB "+format_statement" .SH DESCRIPTION If no arguments are given, or the first argument doesn't start with a `+' character, the standard .I date(1) program is invoked. .sp If the argument begins with a `+' sign, then it is interpreted as follows: .nf %n carriage return %t tab %% percent sign %A name of the day of the week %D date in MM/DD/YY format %H hour (0-23) %M minute (0-59) %N name of the month %S second (0-59) %T time as HH:MM:SS %a abbreviated name of the day of the week %d day of month (0-31) %h abbreviated name of the month %j Julian date (0-364) %m month number (0-11) %r time as HH:MM am/pm %w day of week (0-6, 0=Sunday) %y year - 1900 (0-99) %z time zone name .fi any other characters encountered in the format instruction (which must start with the `+' character) are copied as is to the output. .SH EXAMPLE A nice date format can be obtained by using .nf \fInewdate "+Today is %A, %N 19%d, %y at %r'"\fR .fi which results in output like .nf \fIToday is Friday, December 12, 1986 at 11:02 pm\fR .sp Another interesting example is to use .nf \fInewdate +Date: %a %h %d, %y %T %z\fR .fi to get the standard mail header line: .nf \fIDate: Fri Dec 12, 86 23:05:40 PST\fR .fi .SH FILES /bin/date for calls to the ``real'' date program. .SH SEE ALSO date(1) .SH AUTHOR Dave Taylor, Hewlett-Packard Labs .SH COMPATABILITY This program implements the System V .I date(1) command with three new (and useful) additions, namely the '%A' (full day name) '%N' (full month name) and '%z' (time zone name). .SH COMMENTS Since this program calls .I /bin/date for all arguments other than those starting with a `+', it is expected that this can be called ``date'' and be placed somewhere in the users path so that this is the default program for calls to .I date(1). .sp The notation is really disgusting, but I'm just implementing what was created on System V. I suppose the correct way to phrase this is ``it's compatible!'', but still.... END-OF-FILE if [ "$filename" != "/dev/null" ] then size=`wc -c < $filename` if [ $size != 2140 ] then echo $filename changed - should be 2140 bytes, not $size bytes fi chmod 666 $filename fi # ---------- file newdate.c ---------- filename="newdate.c" if [ -f $filename ] then echo File \"$filename\" already exists\! Skipping... filename=/dev/null # throw it away else echo extracting file newdate.c... fi cat << 'END-OF-FILE' > $filename /** newdate.c **/ /** This program is implemented based on the manual entry in HP-UX (Hewlett-Packards *reliable* version of Unix) for the 'date(1)' program. The main improvement is that the user now has a set of format commands that they can use to get output in a different format than the normal (ugly) date(1) command. Note to system V and HP-UX users - I've also added %A and %N for full day and month name, respectively. Please see the manual entry for more information. (C) Copyright 1986, Dave Taylor **/ /** If you're on a System V machine, then compile with -DSYSV as a flag. **/ #include <stdio.h> #include <sys/time.h> char *short_dayname[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; char *short_monthname[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; char *long_dayname[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; char *long_monthname[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; struct tm *localtime(); /* forward declare for compiler happiness */ #ifdef SYSV extern char *tzname[2]; #else char *timezone(); /* another forward declaration... */ #endif main(argc, argv) int argc; char *argv[]; { char buffer[200], /* our output buffer... */ tempbuf[100]; /* and a temp one for formatting stuff */ int loc; /* our location in the format string */ long thetime; /* the current time, in seconds! */ struct tm *t; /* the time record structure */ #ifndef SYSV struct timeval tp; /* for storing yet-another-format */ struct timezone tz; /* to figure out our timezone... */ #endif if (argc == 1 || argv[1][0] != '+') /* go to 'real' date prog */ execv("/bin/date", argv); if (argc > 2) { fprintf(stderr,"Usage: %s [new time] [ + format string]\n", argv[0]); exit(1); } /* if we're here we're doing okay... */ thetime = time( (long *) 0); t = localtime(&thetime); #ifndef SYSV /** now let's get the timezone that we're in... **/ gettimeofday(&tp, &tz); #endif /* we have the time...now let's parse and build the output! */ for (loc = 1; loc < strlen(argv[1]);) { tempbuf[0] = '\0'; if (argv[1][loc] == '%') { /* a format string! */ switch (argv[1][loc+1]) { case 'n' : strcat(buffer, "\n"); break; case 't' : strcat(buffer, "\t"); break; case '%' : strcat(buffer, "%"); break; case 'm' : sprintf(tempbuf, "%d", t->tm_mon); break; case 'd' : sprintf(tempbuf, "%d", t->tm_mday); break; case 'y' : sprintf(tempbuf, "%d", t->tm_year); break; case 'D' : sprintf(tempbuf, "%d/%d/%d", t->tm_mon, t->tm_mday, t->tm_year); break; case 'H' : sprintf(tempbuf, "%d", t->tm_hour); break; case 'M' : sprintf(tempbuf, "%d", t->tm_min); break; case 'S' : sprintf(tempbuf, "%d", t->tm_sec); break; case 'T' : sprintf(tempbuf, "%02d:%02d:%02d", t->tm_hour, t->tm_min, t->tm_sec); break; case 'j' : sprintf(tempbuf, "%d", t->tm_yday); break; case 'w' : sprintf(tempbuf, "%d", t->tm_wday); break; case 'a' : sprintf(tempbuf, "%s", short_dayname[t->tm_wday]); break; case 'h' : sprintf(tempbuf, "%s", short_monthname[t->tm_mon]); break; case 'A' : sprintf(tempbuf, "%s", long_dayname[t->tm_wday]); break; case 'N' : sprintf(tempbuf, "%s", long_monthname[t->tm_mon]); break; case 'r' : sprintf(tempbuf, "%d:%02d %s", t->tm_hour > 12? t->tm_hour - 12:t->tm_hour, t->tm_min, t->tm_hour > 12? "pm":"am"); break; case 'z' : sprintf(tempbuf, "%s", #ifdef SYSV t->tm_isdst? tzname[1] : tzame[0]); break; #else timezone(tz.tz_minuteswest, t->tm_isdst)); break; #endif case '\0': fprintf(stderr, "%s: unexpected end of format instructions!\n",argv[0]); exit(1); default : fprintf(stderr, "%s: don't understand %%%c as a format instruction!\n", argv[0], argv[1][loc+1]); exit(1); } loc += 2; /* skip the percent and the char we just dealt with */ if (tempbuf[0] != '\0') strcat(buffer, tempbuf); } else { /* not a percent sign... */ tempbuf[0] = argv[1][loc++]; tempbuf[1] = '\0'; strcat(buffer, tempbuf); } } /* and print the buffer out! */ printf("%s\n", buffer); exit(0); /* bye! */ } END-OF-FILE if [ "$filename" != "/dev/null" ] then size=`wc -c < $filename` if [ $size != 4546 ] then echo $filename changed - should be 4546 bytes, not $size bytes fi chmod 666 $filename fi echo done exit 0