[comp.unix.questions] slicing the date

carroll@s.cs.uiuc.edu (03/28/89)

Allright, I can't figure this out. I'm trying to put the current system
time in my prompt. Under SysV, I can use 'cut' to pick out the seperate
hours, minutes, and seconds from 'date'. For non-SysV types, 'cut' lets
you pick out fields using either delimiter characters or absolute column
counts. I found a way to do this using Ksh (with the pattern matchers),
but it is very ugly. The question is, how can I cut up the output of
date to put the hours, minutes, and seconds into seperate variables? Thanks!

Alan M. Carroll          "And then you say,
carroll@s.cs.uiuc.edu     We have the Moon, so now the Stars..."  - YES
CS Grad / U of Ill @ Urbana    ...{ucbvax,pur-ee,convex}!s.cs.uiuc.edu!carroll

karish@forel.stanford.edu (Chuck Karish) (03/29/89)

In article <216000010@s.cs.uiuc.edu> carroll@s.cs.uiuc.edu wrote:

>Allright, I can't figure this out. I'm trying to put the current system
>time in my prompt. Under SysV, I can use 'cut' to pick out the seperate
>hours, minutes, and seconds from 'date'.

	Why bother using cut?  The SysV date command lets you format
	its output directly.

>The question is, how can I cut up the output of
>date to put the hours, minutes, and seconds into seperate variables? Thanks!

	set `date | tr ':' ' '`
	hr=$4
	min=$5
	sec=$6

	If that's not ugly enough for you, use this instead:

	expr "`date`" \: ".*\([ 	0-9][0-9]:..\):.*"


	Chuck Karish	hplabs!hpda!mindcrf!karish	(415) 493-7277
			karish@forel.stanford.edu

mackey@ihlpb.ATT.COM (R. E. Mackey) (03/29/89)

In article <216000010@s.cs.uiuc.edu>, carroll@s.cs.uiuc.edu writes:
> [......] The question is, how can I cut up the output of
> date to put the hours, minutes, and seconds into seperate variables? Thanks!

The line

	eval `date '+hr=%H;min=%M;sec=%S'`

will set 
	hr to the current hour,
	min to the current minute, and
	sec to the current second.

You're welcome.

-- 
 Ron Mackey - AT&T Bell Laboratories 	UUCP:   att!ihlpb!mackey
 2000 N. Naperville Road		WORK:   (312) 979-2140
 Naperville, Illinois  60566		OFFICE: IH 2C-423

dgp@ncsc1.AT&T.NCSC (Dennis Pelton CSM Contractor x8876) (03/29/89)

In article <216000010@s.cs.uiuc.edu>, carroll@s.cs.uiuc.edu writes:
> 
> Allright, I can't figure this out. I'm trying to put the current system
> time in my prompt. Under SysV, I can use 'cut' to pick out the seperate
> hours, minutes, and seconds from 'date'. For non-SysV types, 'cut' lets
> you pick out fields using either delimiter characters or absolute column
> counts. I found a way to do this using Ksh (with the pattern matchers),
> but it is very ugly. The question is, how can I cut up the output of
> date to put the hours, minutes, and seconds into seperate variables? Thanks!
> 
> Alan M. Carroll          "And then you say,
> carroll@s.cs.uiuc.edu     We have the Moon, so now the Stars..."  - YES
> CS Grad / U of Ill @ Urbana    ...{ucbvax,pur-ee,convex}!s.cs.uiuc.edu!carroll

OK, here's one way:

     hrs=`date +'%H'`
     min=`date +'%M'`
     sec=`date +'%S'`

Andhere's another:

     date +'%H %M %S' >now
     read hrs min sec <now

And a follow-up question for those who know more than I:  Why is it that
the following does NOT work?  The variables are empty.

     date +'%H %M %S' | read hrs min sec

Dennis Pelton
att.COM.UUCP!ncsc5!dgp

carroll@s.cs.uiuc.edu (03/30/89)

RE: Slicing the date

	I've gotten several replies, and I need to clarify something -
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. Any
argument is assumed to be an attempt to *set* the date, not format it,
according to the man pages and actual use. I was moved (against my will)
from SysV to BSD, and this is something that I lost - I used to use the
date '+%H:%M:%S' format, and it doesn't work anymore. That's why I have to
slice the normal output.

Alan M. Carroll          "And then you say,
carroll@s.cs.uiuc.edu     We have the Moon, so now the Stars..."  - YES
CS Grad / U of Ill @ Urbana    ...{ucbvax,pur-ee,convex}!s.cs.uiuc.edu!carroll

dmt@PacBell.COM (Dave Turner) (03/30/89)

In article <216000010@s.cs.uiuc.edu> carroll@s.cs.uiuc.edu writes:
>Allright, I can't figure this out. I'm trying to put the current system
>time in my prompt. Under SysV, I can use 'cut' to pick out the seperate
>hours, minutes, and seconds from 'date'. For non-SysV types, 'cut' lets
>you pick out fields using either delimiter characters or absolute column

You might try:

	date "+%H %M %S" | read HH MM SS

	echo $HH
	echo $MM
	echo $SS


-- 
Dave Turner	415/542-1299	{att,bellcore,sun,ames,pyramid}!pacbell!dmt

noe@s.cs.uiuc.edu (03/30/89)

Maybe expr will work?  Again, it's going to look sort of hideous, but it should
work.  For example, if date produces "Wed Mar 29 16:57:30 1989" then
	NOW=`date`
	PS1=`expr "$NOW" : '... ... \(..\)'`
would set PS1=29, the day of the month.  This is Bourne shell, by the way, and
would also work in Kourne shell (-: but not C-shell.  I assume anyone forcibly
removed from a System V environment at least has the good sense to avoid csh
like the plague.

gwyn@smoke.BRL.MIL (Doug Gwyn ) (03/30/89)

In article <431@ncsc1.AT&T.NCSC> dgp@ncsc1.AT&T.NCSC (Dennis Pelton CSM Contractor x8876) writes:
>Why is it that the following does NOT work?
>     date +'%H %M %S' | read hrs min sec

Because the shell built-in "read" runs in a subshell due to the pipeline.
You're setting the variables in a subshell, all right, but that isn't
what you wanted.

rgreen@druhi.ATT.COM (Rodney R. Green) (03/31/89)

in article <216000010@s.cs.uiuc.edu>, carroll@s.cs.uiuc.edu says:
> Nf-ID: #N:s.cs.uiuc.edu:216000010:000:703
> Nf-From: s.cs.uiuc.edu!carroll    Mar 27 15:34:00 1989
> 
>                 .... The question is, how can I cut up the output of
> date to put the hours, minutes, and seconds into seperate variables? Thanks!
> 
> Alan M. Carroll          "And then you say,
> carroll@s.cs.uiuc.edu     We have the Moon, so now the Stars..."  - YES
> CS Grad / U of Ill @ Urbana    ...{ucbvax,pur-ee,convex}!s.cs.uiuc.edu!carroll

The date command has a parameter with which you can specify the format of the
output.  The following three commands will output the hours, minutes, and
seconds respectively:
date +%H
date +%M
date +%S

Of course, setting them separately can result in skew (suppose the hour
changes between the time you set hours and minutes).  You can get output
of the form HH MM SS with the following command.
date +"%H %M %S"
and then cut it up to get the pieces you want.  

See the manual page for date(1) for the complete description of
formatting from date.

Rodney Green
rgreen@druhi.att.com           ...!att!druhi!rgreen
AT&T Bell Laboratories     Denver, CO

jpr@dasys1.UUCP (Jean-Pierre Radley) (04/01/89)

In article <216000010@s.cs.uiuc.edu> carroll@s.cs.uiuc.edu writes:
>Allright, I can't figure this out. I'm trying to put the current system
>time in my prompt. Under SysV, I can use 'cut' to pick out the seperate
>hours, minutes, and seconds from 'date'. For non-SysV types, 'cut' lets
>you pick out fields using either delimiter characters or absolute column
>counts. I found a way to do this using Ksh (with the pattern matchers),
>but it is very ugly. The question is, how can I cut up the output of
>date to put the hours, minutes, and seconds into seperate variables? Thanks!

Using 'cut'? Why? Why not just pick a format from the repertoire of the
'date' command, then use the /bin/sh built-in "set" to extract variables?


set `date "+%H %M %S"` ; echo $1 $2 $3

Or maybe you want 

TIME = `date "+%H:%M:%S"`

-- 
Jean-Pierre Radley		Honi soit		jpr@dasys1.UUCP
New York, New York		qui mal			...!hombre!jpradley!jpr
CIS: 76120,1341			y pense			...!hombre!trigere!jpr

john@frog.UUCP (John Woods) (04/04/89)

> 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@frog.UUCP, ...!mit-eddie!jfw, jfw@eddie.mit.edu

			Remainder Khomeini!

mchinni@pica.army.mil (Michael J. Chinni, SMCAR-CCS-E) (04/04/89)

Alan,

	I can think of two possible choices. One, you may still have access to
a SysV environment, but it may be in /usr/usg or /usr/5bin or some such. This
will allow you to use the SysV date command with its output formatting. Two, if
the above is not true, try the following (H-hours M-minutes S-seconds):
H=`date | cut -c12-19 | cut -f1 -d':'`
M=`date | cut -c12-19 | cut -f2 -d':'`
S=`date | cut -c12-19 | cut -f3 -d':'`

these depend upon date output having the HH:MM:SS in columns 12-19

/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
			    Michael J. Chinni
	US Army Armament Research, Development, and Engineering Center
 User to skeleton sitting at cobweb    () Picatinny Arsenal, New Jersey  
   and dust covered terminal/desk      () ARPA: mchinni@pica.army.mil
    "System been down long?"           () UUCP: ...!uunet!pica.army.mil!mchinni
/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/

mchinni@pica.army.mil (Michael J. Chinni, SMCAR-CCS-E) (04/04/89)

Alan,

	Since you do not have cut at all, I don't know how you could do this
w/o using some type of cut-like utility. What you might want to do it to get
the public-domain versions of cut and paste from the unix-sources archives.
Such versions are available in Volume 8 of the archives. The address is
unix-sources@smoke.brl.mil, newsgroup is comp.sources.unix, moderator is Rich
Salz (rsalz@uunet.uu.net).

        I would suggest contacting unix-sources-request@smoke.brl.mil or
rsalz@uunet.uu.net to find out the procedure for getting said programs.

/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
			    Michael J. Chinni
	US Army Armament Research, Development, and Engineering Center
 User to skeleton sitting at cobweb    () Picatinny Arsenal, New Jersey  
   and dust covered terminal and desk  () ARPA: mchinni@pica.army.mil
    "System been down long?"           () UUCP: ...!uunet!pica.army.mil!mchinni
/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/

bernsten@phoenix.Princeton.EDU (Dan Bernstein) (04/05/89)

In article <18941@adm.BRL.MIL> mchinni@pica.army.mil (Michael J. Chinni, SMCAR-CCS-E) writes:
> Alan,
> 
> 	Since you do not have cut at all, I don't know how you could do this
> w/o using some type of cut-like utility. What you might want to do it to get
> the public-domain versions of cut and paste from the unix-sources archives.

I believe the cut command in question was something like ``cut -c12-19''
for extracting columns 12 through 19 of a file. If you don't have easy
access to uunet, can't reach smoke.brl.mil, don't feel like getting cut
and paste to work, prefer speed and simplicity, or are just lazy, you
might try the primitive ``type of cut-like utility'' known as colrm.

  colrm 20 | colrm 1 11

is quite a bit faster than cut -c12-19, can handle long lines, and
doesn't require cut in the first place. Note that it reacts differently
to tabs, though expand and unexpand negate the difference.

(I once moved a shell script to a machine without cut. I felt even more
stupid than usual when I realized I could have used colrm in the first
place.)

---Dan Bernstein, bernsten@phoenix.princeton.edu

carroll@s.cs.uiuc.edu (04/05/89)

RE : Slicing the Date

The end of the saga - I wrote the original note because I thought that
BSD must have some simple 'cut' equivalent that I missed somehow. Apparently
that is not the case. I didn't want to use a C program because of quota
problems, and I am *not* the SysAdmin, so installing a different version
is not an option. I did receive several interesting solutions, but none
that much better than using ksh pattern operators to simulate 'cut'. Because
of the way ksh works, I only have to slice the date once, on login, not
every time the prompt is displayed, so overhead is not that much of a
concern. Many thanks to those who responded.

Alan M. Carroll          "And then you say,
carroll@s.cs.uiuc.edu     We have the Moon, so now the Stars..."  - YES
CS Grad / U of Ill @ Urbana    ...{ucbvax,pur-ee,convex}!s.cs.uiuc.edu!carroll