[alt.sources] UNIX-Time the right way ...

jfh@rpp386.cactus.org (John F. Haugh II) (11/30/90)

There is nothing worse than dumb, stupid, slow code.

These is also nothing worse than people whose IQ is so low
that they can't take a hint and do something productive
with it.  Please, people, some of you claim to be programmers,
how about living up to those claims?  I'm really sorry I feel
this need to insult some people, but gee guys, at least take
the effort to try my suggestions before attacking me as
writing buggy or inaccurate code.  Of course, having not been
paid to write this code I will tell you that under certain
conditions it may loop infinitely, but then you get what you
pay for.  Try 2/31/88 for a nice time.

Test results after the source code.  You will notice that this
code correctly handles daylight savings time, as well as
hours, minutes, and seconds.  You will also notice that it
calls localtime 1/15th or so less often.  It even does leap
days.

There is nothing wrong with being "clever", but binary
approximation is as old as Newton, if not older.
--
/*
 * Copyright 1990, John F. Haugh II
 * All rights reserved.
 *
 * Use, duplication, and disclosure prohibited without
 * the express written permission of the author.
 *
 * Non-commercial (profit-making) source distribution permitted
 * provided this notice remains intact.
 */

#include <time.h>

/*
 * days and juldays are used to compute the number of days in the
 * current month, and the cummulative number of days in the preceding
 * months.
 */

static	short	days[12] = {
	31,	28,	31,	30,	31,	30,	/* JAN - JUN */
	31,	31,	30,	31,	30,	31 };	/* JUL - DEC */

static	short	juldays[12] = {
	0,	31,	59,	90,	120,	151,	/* JAN - JUN */
	181,	212,	243,	273,	304,	334 };	/* JUL - DEC */

static long
dtime (tm, time)
struct	tm	*tm;
long	time;	/* no C */
{
	struct	tm	*sm;
	long	diff;
	long	julian1, julian2;

	sm = localtime (&time);

	julian1 = ((tm->tm_year - 70) * 365) +	/* days in whole years */
		(((tm->tm_year + 1) - 70) / 4);	/* days in leap years */
	julian1 += juldays[tm->tm_mon] +	/* days in whole months */
		(tm->tm_mon > 1 && (tm->tm_year % 4) == 0 ? 1:0); /* leap day */
	julian1 += tm->tm_mday - 1;		/* days so far this month */

	julian2 = ((sm->tm_year - 70) * 365) +	/* days in whole years */
		(((sm->tm_year + 1) - 70) / 4);	/* days in leap years */
	julian2 += juldays[sm->tm_mon] +	/* days in whole months */
		(sm->tm_mon > 1 && (sm->tm_year % 4) == 0 ? 1:0); /* leap day */
	julian2 += sm->tm_mday - 1;		/* days so far this month */

	diff = (julian1 - julian2) * (24L*3600);	/* add the days */
	diff += (tm->tm_hour - sm->tm_hour) * (3600L);	/* add the hours */
	diff += (tm->tm_min - sm->tm_min) * (60L);	/* add the minutes */
	diff += (tm->tm_sec - sm->tm_sec);		/* add the seconds */

	return diff;				/* that's how far off */
}

long
mktime (tm)
struct	tm	*tm;
{
	long	old, diff, new;
	struct	tm	*t;

	for (old = 0L;(diff = dtime (tm, old)) != 0;old += diff) {
#ifdef	TEST
		new = old + diff;
		printf ("old = %ld, new = %ld\n", old, new);

		t = localtime (&old);
		printf ("old = %d/%d/%d %d:%d:%d\n",
			t->tm_mon + 1, t->tm_mday, t->tm_year,
			t->tm_hour, t->tm_min, t->tm_sec);

		t = localtime (&new);
		printf ("new = %d/%d/%d %d:%d:%d\n",
			t->tm_mon + 1, t->tm_mday, t->tm_year,
			t->tm_hour, t->tm_min, t->tm_sec);
#else
		;
#endif
	}
	return old;
}
#ifdef	TEST
main ()
{
	long	t;
	struct	tm	tm;
	struct	tm	*ptm;
	char	buf[100];

	while (gets (buf)) {
		memset (&tm, 0, sizeof tm);

		sscanf (buf, "%d/%d/%d %d:%d:%d",
			&tm.tm_mon, &tm.tm_mday, &tm.tm_year,
			&tm.tm_hour, &tm.tm_min, &tm.tm_sec);

		tm.tm_mon--;

		t = mktime (&tm);

		ptm = localtime (&t);
		printf ("guess = %d or %d/%d/%d %d:%d:%d\n",
			t, ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_year,
			ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
	}
}
#endif
--
Script is typescript, started Thu Nov 29 10:00:25 1990
rpp386-> ./mktime
1/1/70 0:0:0
old = 0, new = 21600
old = 12/31/69 18:0:0
new = 1/1/70 0:0:0
guess = 21600 or 1/1/70 0:0:0
12/31/69 18:0:0
guess = 0 or 12/31/69 18:0:0
11/29/90 10:00:25
old = 0, new = 659894425
old = 12/31/69 18:0:0
new = 11/29/90 10:0:25
guess = 659894425 or 11/29/90 10:0:25
6/1/90 12:00:00
old = 0, new = 644263200
old = 12/31/69 18:0:0
new = 6/1/90 13:0:0
old = 644263200, new = 644259600
old = 6/1/90 13:0:0
new = 6/1/90 12:0:0
guess = 644259600 or 6/1/90 12:0:0
10/21/90 01:00:00
old = 0, new = 656492400
old = 12/31/69 18:0:0
new = 10/21/90 2:0:0
old = 656492400, new = 656488800
old = 10/21/90 2:0:0
new = 10/21/90 1:0:0
guess = 656488800 or 10/21/90 1:0:0
10/21/90 02:00:00
old = 0, new = 656496000
old = 12/31/69 18:0:0
new = 10/21/90 3:0:0
old = 656496000, new = 656492400
old = 10/21/90 3:0:0
new = 10/21/90 2:0:0
guess = 656492400 or 10/21/90 2:0:0
10/21/90 3:0:0
old = 0, new = 656499600
old = 12/31/69 18:0:0
new = 10/21/90 4:0:0
old = 656499600, new = 656496000
old = 10/21/90 4:0:0
new = 10/21/90 3:0:0
guess = 656496000 or 10/21/90 3:0:0
10/28/90 1:0:0
old = 0, new = 657097200
old = 12/31/69 18:0:0
new = 10/28/90 1:0:0
guess = 657097200 or 10/28/90 1:0:0
10/28/90 2:0:0
old = 0, new = 657100800
old = 12/31/69 18:0:0
new = 10/28/90 2:0:0
guess = 657100800 or 10/28/90 2:0:0
rpp386-> exit
Script done Thu Nov 29 10:03:31 1990
-- 
John F. Haugh II                             UUCP: ...!cs.utexas.edu!rpp386!jfh
Ma Bell: (512) 832-8832                           Domain: jfh@rpp386.cactus.org
"SCCS, the source motel!  Programs check in and never check out!"
		-- Ken Thompson