Inverse for localtime().
Paul Reger
paulr at sequent.UUCP
Sat Aug 26 11:06:54 AEST 1989
A while back someone asked if there was such a thing as an inverse
localtime() function. (localtime() maps a time_t * to a struct *tm).
I guess there isn't one, so I wrote one (The problem interested me
since it seemed natural for one to exist.). Here it is:
#define Seconds_per_minute 60
#define Seconds_per_hour 60*Seconds_per_minute
#define Seconds_per_day 24*Seconds_per_hour
#define Seconds_per_month 30*Seconds_per_day
#define Seconds_per_year 365*Seconds_per_day
#include <sys/types.h>
#include <sys/time.h>
time_t
tm_to_time_t(t)
struct tm t;
{
time_t high_guess = 0,low_guess = 0,middle;
struct tm *temp;
int score_high,score_low,nyears;
static const int fudges[12] = { 0*Seconds_per_day, /* Jan. */
1*Seconds_per_day, /* Feb. */
-1*Seconds_per_day, /* Mar. */
0*Seconds_per_day, /* Apr. */
0*Seconds_per_day, /* May */
1*Seconds_per_day, /* Jun. */
1*Seconds_per_day, /* Jul. */
2*Seconds_per_day, /* Aug. */
3*Seconds_per_day, /* Sep. */
3*Seconds_per_day, /* Oct. */
4*Seconds_per_day, /* Nov. */
4*Seconds_per_day /* Dec. */ };
nyears = t.tm_year - 70;
low_guess = Seconds_per_year*nyears +
(double) ((nyears-1)*Seconds_per_day) * 0.24 + /* add in leap days... */
Seconds_per_month*t.tm_mon +
fudges[t.tm_mon] + /* Add in approximate days for 'non-30' day months. */
Seconds_per_day*(t.tm_mday - 1) + Seconds_per_hour*t.tm_hour + Seconds_per_minute*t.tm_min + t.tm_sec;
high_guess = low_guess + 2*Seconds_per_day; /* The initial guess will
always be about 1 and a maximum of two days off. Proof
left to the reader. */
while (abs((high_guess - low_guess)) > 1) {
middle = (high_guess + low_guess) / 2;
temp = localtime(&middle);
score_high = ((temp->tm_year > t.tm_year) << 5) + ((temp->tm_mon > t.tm_mon) << 4) + ((temp->tm_mday > t.tm_mday) << 3) +
((temp->tm_hour > t.tm_hour) << 2) + ((temp->tm_min > t.tm_min) << 1) + (temp->tm_sec > t.tm_sec);
score_low = ((temp->tm_year < t.tm_year) << 5) + ((temp->tm_mon < t.tm_mon) << 4) + ((temp->tm_mday < t.tm_mday) << 3) +
((temp->tm_hour < t.tm_hour) << 2) + ((temp->tm_min < t.tm_min) << 1) + (temp->tm_sec < t.tm_sec);
if (score_high > score_low)
high_guess = middle;
else
low_guess = middle;
}
return middle;
}
main(argc,argv)
int argc;
char *argv[];
{
struct tm z;
time_t t;
z.tm_hour = atoi(argv[1]);
z.tm_min = atoi(argv[2]);
z.tm_sec = atoi(argv[3]);
z.tm_mday = atoi(argv[4]);
z.tm_mon = atoi(argv[5]);
z.tm_year = atoi(argv[6]);
t = tm_to_time_t(z);
printf("%d is the time representation for: %s",t,ctime(&t));
}
All the standard disclaimers apply. I only tested this a little bit.
Also, my solution is based on a binary search and is very costly.
Anyone know of a better solution ??
Note also that the elements in the struct besides the six above tm are
ignored.
Still also note that for some reason, the seconds are off by one some
times.
More information about the Comp.unix.questions
mailing list