[net.sources.mac] Standard time utilities

jww@bonnie.UUCP (Joel West) (05/18/85)

The following shell archive includes all the necessary source to implement
a UNIX-like time functionality for the Mac on the Megamax (and presumably
other) C compilers.  It also includes a bonus -- implementation of a
function (comparable to ctime) that uses the Macintosh International
Utilities to format the date in a country-specific fashion.

I'll be glad to put this in the public domain and let anyone distribute
it with any system that doesn't have it (I'm sending a copy back to
Megamax).  The only condition is that credit (in some form) is given
where credit is due.


#!/bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #!/bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	README
#	ctime.3
#	time.c
#	time.h
#	timedemo.c
# This archive created: Sat May 18 16:15:35 1985
export PATH; PATH=/bin:$PATH
if test -f 'README'
then
	echo shar: over-writing existing file "'README'"
fi
sed 's/^XX//' << \SHAR_EOF > 'README'
XXUNIX time function emulation utilities for the Macintosh
XXJoel West, May 18, 1985
XXihnp4!bonnie!jww, westjw@nosc.ARPA
XX
XXThe following files are defined:
XX	time.h: include file for time utilities
XX	time.c: library source for time utilities
XX	ctime.3: UNIX-like man(1) page for utitilies
XX	timedemo.c: demonstration program
XX	
XXThese implement nearly the full suite of standard UNIX time
XXutilities:
XX	time() - return current time in seconds
XX	ctime() - format time to 26-character string
XX	localtime() - decompose time into components
XX	asctime() - format component time to 26-character string
XXThese functions are standard on System V, BSD 4.2, and the /usr/group
XXcommon UNIX standard (although time() is emulated under BSD 4.2).
XXThe UNIX systems also include gmtime(), but this doesn't make
XXsense on a Mac, which doesn't know anything about time zones or
XXgreenwich mean time.
XX
XXIn addition, the function
XX	iutime() - international-format time
XXis similar to ctime (without the seconds), but uses the Macintosh
XXInternational Utilities to produce a country-specific output.  In
XXthe US, this results in a 26 to 28-character string of the form:
XX	Sun, Sep 16, 1973, 1:03 AM\n\0
SHAR_EOF
if test -f 'ctime.3'
then
	echo shar: over-writing existing file "'ctime.3'"
fi
sed 's/^XX//' << \SHAR_EOF > 'ctime.3'
XX
XXCTIME(3)							CTIME(3)
XX
XX
XXNAME
XX	time, ctime, localtime, asctime, iutime -- get date and time
XX
XXSYNOPSIS
XX	#include <time.h>
XX
XX	long time ( (long *) 0)
XX
XX	long time (tloc)
XX	long *tloc;
XX		
XX	char *ctime (clock)
XX	long *clock;
XX
XX	struct tm *localtime (clock)
XX	long *clock;
XX
XX	char *asctime (tm)
XX	struct tm *tm;
XX
XX	char *iutime (clock)
XX	long *clock;
XX
XXDESCRIPTION
XX	Time returns the value of time in seconds since 00:00:00 local
XX	time, January 1, 1904.  This is the standard internal format for
XX	time representation on the Macintosh.  If the pointer tloc is
XX	non-null, the return values is also stored at the location pointed to
XX	by tloc.
XX
XX	Ctime converts a long integer system time (such as returned by
XX	time), and returns a pointer to a 26-character string in the
XX	following form.  All fields have constant width, and leading zeros
XX	are always included:
XX
XX		Wed May 15 21:02:21 1985\n\0
XX
XX	Localtime takes a pointer to a system time as an argument, and
XX	returns a pointer to a tm structure, described below.  Asctime
XX	converts a tm structure to a 26-character string in the same
XX	format as ctime, and returns a pointer to the string.
XX
XX
XXCTIME(3)							CTIME(3)
XX
XX
XX	Declarations of all the functions and the tm structure, are in the
XX	<time.h> header file.  The structure declaration is:
XX
XX		struct tm {
XX			int tm_sec;	/* 0-59  seconds */
XX			int tm_min;	/* 0-59  minutes */
XX			int tm_hour;	/* 0-23 hours */
XX			int tm_mday;	/* 1-31 day */
XX			int tm_mon;	/* 0-11 month */
XX			int tm_year;	/* add 1900 */
XX			int tm_wday;	/* Sunday=0 */
XX			int tm_yday;	/* day of year 0-365 */
XX			int tm_isdst;	/* <>0 on daylight */
XX		 };
XX
XX	Tm_isdst is non-zero if Daylight Savings Time is in effect.
XX
XX	Iutime is similar to ctime in that it takes a system time as an
XX	argument and returns a human-readable character string. 
XX	However, the routine uses Apple's international utilities package
XX	for formatting the date in a country-dependent manner.  For the
XX	U.S., the result would be a string, such as the following:
XX
XX		Wed, May 15, 1985, 9:22 PM\n\0
XX
XX	In the U.S., leading zeros are not included in either the day or the
XX	hour, so that the length can vary from 26 to 28 characters.  The
XX	length of the result will be also differ if the country defined for
XX	your user's system is not the U.S.
XX
XXAUTHOR
XX	Joel West (ihnp4!bonnie!jww, westjw@NOSC.ARPA)
XX
XXSEE ALSO
XX	"Macintosh Packages: A Programmer's Guide"
XX	"The Operating System Utilities: A Programmer's Guide"
XX	(both contained in Inside Macintosh)
XX
XX
XXCTIME(3)							CTIME(3)
XX
XX
XXNOTES
XX	The definition of system time differs by exactly 66 years from
XX	that found in UNIX systems, which base their calculations on the
XX	year 1970.  The symbolic constant TIMEDIFF, defined in the
XX	<time.h> header file, gives the exact number of seconds that must
XX	be subtracted from a Macintosh system time to convert to a UNIX
XX	system time:
XX
XX		#define TIMEDIFF 0x7c25b080
XX
XX	The return values point to static data whose content is
XX	overwritten by each call, and thus are probably not suitable for
XX	use in desk accessories.
XX
XX	Although the Mac knows what country it's in, it has no standard
XX	way of indicating its current time zone, and so cannot make
XX	automatic time zone conversions for travel or the changes in
XX	daylight savings time.
XX
XX	The algorithm for Daylight Savings Time understands changes on
XX	the last Sundays in April and October, but does not allow for
XX	one-time aberrations (1974), peculiar state customs, or the
XX	various observations of the practice outside North America.  The
XX	indicator is also inaccurate for the first two hours of the
XX	changeover date, but this error only occurs in 0.046% of the cases.
XX
XX	The routine time returns the value of the Macintosh system
XX	variable Time, so name confusion is possible.
XX
XX
XX
XX
XX
SHAR_EOF
if test -f 'time.c'
then
	echo shar: over-writing existing file "'time.c'"
fi
sed 's/^XX//' << \SHAR_EOF > 'time.c'
XX/* time.c:
XX	time, ctime, localtime, asctime, iutime
XX	UNIX-like time functions
XX   see also <time.h>
XX
XX   These procedures provide functionality similar to that on
XX   UNIX systems.  On UNIX systems, include the line
XX   	#define iutime(longptr) ctime(longptr)
XX   for a roughly comparable result
XX
XX   (c) 1985 Joel West -- May 16, 1985
XX   ihnp4!bonnie!jww, westjw@NOSC.ARPA 
XX   Unlimited license granted if this notice retained in all source copies
XX*/
XX
XX#include <os.h>
XX#include <pack.h>
XX#include <time.h>
XX
XX/* long time(&long)
XX   returns Macintosh system time as seconds since 1/1/1904
XX   returns value as a function and, optionally, to the specified loc
XX   
XX   UNIX uses exactly a 66-year-later starting point.  However, since
XX   this time is most likely going to be passed to ctime() or localtime(),
XX   or used to calculate a period (difference in times), this distinction
XX   isn't likely to matter much.  It does mean code that uses these
XX   functions will move transparently unless it uses absolute
XX   calculations (if so, use TIMEDIFF to convert)
XX*/
XX
XXlong time(ptr)
XXlong *ptr;
XX{	long secs;
XX
XX	if (ptr==0)
XX		ptr = &secs;
XX		
XX	GetDateTime(ptr);
XX	return (*ptr);
XX}
XX
XX/* char *asctime(&tm)
XX   Takes a pointer to a user <tm> structure and returns a 26-character
XX   string of the form:
XX   		"Sun Sep 16 01:03:52 1973\n\0"
XX*/
XX#define DIG(num) ('0' + (char)(num))
XX#define cvt2(buff, int) \
XX	(ptr = &buff, num=int, *ptr++ = DIG(num/10), *ptr = DIG(num%10))
XX
XXchar *asctime(utm)
XXstruct tm *utm;
XX{	static char *monstr = "JanFebMarAprMayJunJulAugSepOctNovDec";
XX	static char *daystr = "SunMonTueWedThuFriSat";
XX	static char *patstr = "Tue Jan 24 03:55:50 1984\n\0";
XX	static char timstr[26];
XX	register int num;
XX	register char *ptr;
XX	
XX	strcpy(timstr, patstr);		/* set delimiters */
XX	strncpy(&timstr[0], &daystr[3*(utm->tm_wday)], 3);
XX	strncpy(&timstr[4], &monstr[3*(utm->tm_mon)], 3);
XX	cvt2(timstr[8], utm->tm_mday);	
XX	cvt2(timstr[11], utm->tm_hour);
XX	cvt2(timstr[14], utm->tm_min);
XX	cvt2(timstr[17], utm->tm_sec);
XX
XX	num = utm->tm_year+1900;	
XX	for (ptr=&timstr[23]; num; num=num/10)
XX		*ptr-- = DIG(num%10);
XX
XX	return (timstr);
XX}
XX
XX/* char *ctime(&long)
XX   Takes a time in seconds (such as returned by time()) and formats
XX   it into a 26-character static string.  See time(), asctime()
XX*/
XXchar *ctime(longptr)
XXlong *longptr;
XX{	
XX	return (asctime(localtime(longptr)));
XX}
XX
XX
XX/* struct tm *localtime(&long)
XX   Takes a Macintosh system time as an argument
XX   
XX   Builds a structure with everything you need to know
XX   (But handles only normal daylight time in most of the US)
XX*/
XXstruct tm *localtime(longptr)
XXlong *longptr;
XX{	static struct tm stm;	/* UNIX struct in memory */
XX	DateTimeRec mactm;	/* Mac struct on stack */
XX	static int mlen[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
XX	register int i,yday;
XX	int leap;
XX
XX	Secs2Date(*longptr, &mactm);
XX	
XX	stm.tm_sec  = mactm.second;
XX	stm.tm_min  = mactm.minute;
XX	stm.tm_hour = mactm.hour;
XX	stm.tm_mday = mactm.day;
XX	stm.tm_mon  = mactm.month-1;
XX	stm.tm_year = mactm.year-1900;
XX	stm.tm_wday = mactm.dayOfWeek-1;
XX
XX	leap = 0;
XX	yday = stm.tm_mday-1;	/* remember, 1/1 is day #0 */
XX
XX	for (i=stm.tm_mon; (--i)>=0; yday += mlen[i])
XX	  {	if (i==1 && (stm.tm_year%4 == 0))
XX		   leap++;	/* leap year rule 1901-2099 */
XX	  };
XX	stm.tm_yday = yday+leap;	/* no effect on DST */
XX
XX/* Daylight Savings Time: works in most of US under 1985 rules
XX   Ignores period of 12am-2am on changeover date
XX*/
XX	stm.tm_isdst = 0;
XX	yday -= stm.tm_wy < 297 )
XX/*	    April 24        Oct 25 */
XX	    stm.tm_isdst++;
XX
XX	return (&stm);
XX}
XX
XX
XX/* char *iutime(&long)
XX   Choose date and time (without seconds)
XX
XX   Somewhat like ctime(), but will produce a result compatible
XX   with the user's native date format.
XX   In the US, produces a 26 to 28-character string of the form:
XX   	"Tue, Jan 24, 1985 3:55 AM\n\0"
XX   Will have different lengths (and orders) in different countries
XX*/
XXchar *iutime(secsptr)
XXlong *secsptr;
XX{	register char *p;
XX	static char time_buff[64];	/* very verbose languages */
XX
XX	p = &time_buff[0];
XX	IUDateString(*secsptr, abbrevDate, p);	/* add date */
XX	p += strlen(p);
XX	*p++ = ' ';			/* leave a blank */
XX	IUTimeString(*secsptr, 0, p);	/* no seconds */
XX	p += strlen(p);
XX	*p++ = '\n';			/* add a newline */
XX	*p = '\0';
XX	return (time_buff);
XX}
XX
SHAR_EOF
if test -f 'time.h'
then
	echo shar: over-writing existing file "'time.h'"
fi
sed 's/^XX//' << \SHAR_EOF > 'time.h'
XX/* time.h
XX   Joel West, ihnp4!bonnie!jww, May 18, 1985
XX*/
XX
XX/* Time of UNIX base time (1/1/1970) in Macintosh units */
XX#define TIMEDIFF 0x7c25b080
XX
XX
XXlong time();			/* binary time (Mac-style) */
XXchar *asctime();		/* string from structure */
XXchar *ctime();			/* string from time */
XXchar *iutime();			/* like ctime, int'l, no seconds */
XX
XXstruct tm {
XX	int tm_sec;	/* 0-59 */
XX	int tm_min;	/* 0-59 */
XX	int tm_hour;	/* 0-23 */
XX	int tm_mday;	/* 1-31 */
XX	int tm_mon;	/* 0-11 */
XX	int tm_year;	/* add 1900 */
XX	int tm_wday;	/* Sunday=0 */
XX	int tm_yday;	/* 0-365 */
XX	int tm_isdst;	/* <>0 on daylight */
XX  };
XX
XXstruct tm *localtime();		/* structure from time */
SHAR_EOF
if test -f 'timedemo.c'
then
	echo shar: over-writing existing file "'timedemo.c'"
fi
sed 's/^XX//' << \SHAR_EOF > 'timedemo.c'
XX/* timedemo.c = demonstrate
XX	time() - binary time value
XX	localtime() - return decoded time structure
XX	ctime() - formatted string from binary value
XX	iutime() -  almost like ctime(), but in Mac "international" format
XX*/
XX
XX
XX/* change the following for your location */
XX#define STDTIME "PST"
XX#define DSTTIME "PDT"
XX
XX#include <stdio.h>
XX#include <time.h>
XXchar *tzname[2];	/* declare here for all to use */
XX
XXmain()
XX{	long tim;
XX	int dstflag;
XX
XX	tzname[0] = STDTIME;
XX	tzname[1] = DSTTIME;
XX	
XX	tim = time(0);
XX	dstflag = ((localtime(&tim))->tm_isdst) ? 1 : 0;
XX	printf ("In the %3s time zone,\n\0", tzname[dstflag]);
XX	printf (" UNIX thinks it's %s", ctime(&tim));
XX	printf (" ...while a US Mac calls it %s", iutime(&tim));
XX
XX	while (getchar() != '\n')
XX		; /* just wait */
XX}
XX
SHAR_EOF
#	End of shell archive
exit 0
-- 
	Joel West				     (619) 457-9681
	CACI, Inc. - Federal 3344 N. Torrey Pines Ct La Jolla 92037
	jww@bonnie.UUCP (ihnp4!bonnie!jww)
	westjw@nosc.ARPA

   "The best is the enemy of the good" - A. Mullarney

jww@bonnie.UUCP (Joel West) (05/28/85)

A while back, I posted source for a mac-supported time(2), ctime(3),
asctime(3), etc.  There was one small bug.  In a few days, asctime
(and ctime) will say 
	Sat Jun 01 01:23 1985
where the standard UNIX ctime says
	Sat Jun  1 01:23 1985

The patch below (note the "YY" instead of "XX") is a bit kludgey but
does the job.  

Incidentally, this should answer the question of the obnoxious AT&T
type who threatened to send the corporate lawyers after me for publishing
UNIX source.  I mean, geez, if I were going to steal code, at least I'd 
be able to type it in right!  In case I wasn't clear enough before, I have 
never seen any UNIX source for these, the only thing they have in common 
with the UNIX version is the documentation, and I do not warrantee their
use on a 3B20. :-)

XXchar *asctime(utm)
XXstruct tm *utm;
XX{	static char *monstr = "JanFebMarAprMayJunJulAugSepOctNovDec";
XX	static char *daystr = "SunMonTueWedThuFriSat";
XX	static char *patstr = "Tue Jan 24 03:55:50 1984\n\0";
XX	static char timstr[26];
XX	register int num;
XX	register char *ptr;
XX	
XX	strcpy(timstr, patstr);		/* set delimiters */
XX	strncpy(&timstr[0], &daystr[3*(utm->tm_wday)], 3);
XX	strncpy(&timstr[4], &monstr[3*(utm->tm_mon)], 3);
XX	cvt2(timstr[8], utm->tm_mday);	
YY	if (timstr[8] == '0')
YY	    timstr[8] = ' ';
XX	cvt2(timstr[11], utm->tm_hour);
XX	cvt2(timstr[14], utm->tm_min);
XX	cvt2(timstr[17], utm->tm_sec);
-- 
	Joel West				     (619) 457-9681
	CACI, Inc. - Federal 3344 N. Torrey Pines Ct La Jolla 92037
	jww@bonnie.UUCP (ihnp4!bonnie!jww)
	westjw@nosc.ARPA

  And ye can tell the sheep from the men from their frequent use of (tm)....