ftp.nice.ch/pub/next/unix/network/news/nn.6.4.16.s.tar.gz#/nn/pack_date.c

This is pack_date.c in view mode; [Download] [Up]

/*
 *	(c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
 *
 *	Calculate an approximate "time_stamp" value for a date
 *	string.  The actual value is not at all critical,
 *	as long as the "ordering" is ok.
 *
 *	The result is NOT a time_t value, i.e. ctime() will
 *	not produce the original Date string.
 *
 *	The date must have format:  [...,] [D]D Mmm YY hh:mm:ss TZONE
 *
 *	Thanks to Wayne Davison for the timezone decoding code.
 */

#include "config.h"

/* #define DATE_TEST /* never define this !! */

#undef W
#undef E
#undef DST
#undef UTC
#define W	* (-60) - 
#define E	* 60 +
#define DST	+ 60
#define UTC	60 *

static struct zonetab {
    char *tz_name;
    int32 tz_offset;
} ztab[] = {
    "a",	UTC 1,		/* UTC+1h */
    "acsst",	9 E 30 DST,	/* Cent. Australia */
    "acst",	9 E 30,		/* Cent. Australia */
    "adt",	4 W 0 DST,	/* Atlantic (Canada) */
    "aesst",	10 E 0 DST,	/* E. Australia */
    "aest",	10 E 0,		/* E. Australia */
    "ast",	4 W 0,		/* Atlantic (Canada) */
    "awsst",	8 E 0 DST,	/* W. Australia */
    "awst",	8 E 0,		/* W. Australia */
    "b",	UTC 2,		/* UTC+2h */
    "bst",	0 E 0 DST,	/* Great Britain summertime */
    "c",	UTC 3,		/* UTC+3h */
    "cdt",	6 W 0 DST,	/* Central */
    "cest",	1 E 0 DST,	/* Central Europe */
    "cet",	1 E 0,		/* Central Europe */
    "cetdst",	1 E 0 DST,	/* Central Europe */
    "cst",	6 W 0,		/* Central */
    "d",	UTC 4,		/* UTC+4h */
    "dnt",	1 E 0,		/* Denmark */
    "dst",	1 E 0 DST,	/* Denmark */
    "e",	UTC 5,		/* UTC+5h */
    "edt",	5 W 0 DST,	/* Eastern US */
    "eest",	2 E 0 DST,	/* Eastern Europe */
    "eet",	2 E 0,		/* Eastern Europe */
    "eetdst",	2 E 0 DST,	/* Eastern Europe */
    "est",	5 W 0,		/* Eastern US */
    "f",	UTC 6,		/* UTC+6h */
    "g",	UTC 7,		/* UTC+7h */
    "gmt",	0,		/*  */
    "h",	UTC 8,		/* UTC+8h */
    "hdt",	10 W 0 DST,	/* Hawaii/Alaska */
    "hst",	10 W 0,		/* Hawaii/Alaska */
    "i",	UTC 9,		/* UTC+9h */
    "ist",	2 E 0,		/* Israel */
    "jst",	9 E 0,		/* Japan */
    "k",	UTC 10,		/* UTC+10h */
    "l",	UTC 11,		/* UTC+11h */
    "m",	UTC 12,		/* UTC+12h */
    "mdt",	7 W 0 DST,	/* Mountain US */
    "mest",	1 E 0 DST,	/* Central Europe */
    "met",	1 E 0,		/* Central Europe */
    "metdst",	1 E 0 DST,	/* Central Europe */
    "mst",	7 W 0,		/* Mountain */
    "n",	UTC -1,		/* UTC-1h */
    "ndt",	3 W 30 DST,	/* Nfld. (Canada) */
    "nst",	3 W 30,		/* Nfld. (Canada) */
    "o",	UTC -2,		/* UTC-2h */
    "p",	UTC -3,		/* UTC-3h */
    "pdt",	8 W 0 DST,	/* Pacific */
    "pst",	8 W 0,		/* Pacific */
    "q",	UTC -4,		/* UTC-4h */
    "r",	UTC -5,		/* UTC-5h */
    "s",	UTC -6,		/* UTC-6h */
    "t",	UTC -7,		/* UTC-7h */
    "u",	UTC -8,		/* UTC-8h */
    "ut",	UTC 0,		/* UTC */
    "utc",	UTC 0,		/* UTC */
    "v",	UTC -9,		/* UTC-9h */
    "w",	UTC -10,	/* UTC-10h */
    "west",	0 E 0 DST,	/* Western Europe */
    "wet",	0 E 0,		/* Western Europe */
    "wetdst",	0 E 0 DST,	/* Western Europe */
    "x",	UTC -11,	/* UTC-11h */
    "y",	UTC -12,	/* UTC-12h */
    "ydt",	9 W 0 DST,	/* Yukon */
    "yst",	9 W 0,		/* Yukon */
    "z",	UTC 0,		/* UTC */
    NULL,	0
};

#undef MAXZ
#define MAXZ	10

static long tzone(date)
register char *date;
{
    register int i, n;
    static char zone[MAXZ], num[MAXZ];
    register struct zonetab *z;
    long adjust, sign;
    static int first = 1;

    i = 0;
    while (*date && isascii(*date) && isspace(*date)) date++;
	
    for ( ; *date && isascii(*date) ; date++) {
	if (*date == '+' || *date == '-' || isdigit(*date))
	    goto numeric_zone;
	if (isspace(*date)) break;
	if (!isalpha(*date)) continue;	/* p.s.t. -> pst */
	if (i == MAXZ) continue;
	zone[i++] = isupper(*date) ? tolower(*date) : *date;
    }

    while (*date && isascii(*date) && isspace(*date)) date++;
    if (*date && i < MAXZ-3) {
	if (date[0] != 'D' && date[0] != 'd') goto no_dst;
	if (date[1] != 'S' && date[1] != 's') goto no_dst;
	if (date[2] != 'T' && date[2] != 't') goto no_dst;
	zone[i++] = 'd';
	zone[i++] = 's';
	zone[i++] = 't';
    }

 no_dst:
    if (i == 0) return 0;
    adjust = 0;
    if (*date != '+' && *date != '-') goto non_numeric;

 numeric_zone:			/* {+-}[H]H[MM] */
    switch (*date) {
     case '-':
	date++;
	sign = -1;
	break;
     case '+':
	date++;
     default:
	sign = 1;
	break;
    }

    adjust = 0;
    for (n = 0; n < MAXZ && *date && isascii(*date) && isdigit(*date); )
	num[n++] = *date++;
    num[n] = NUL;

    switch (n) {
     case 0:
	break;
     case 3:	/* +HMM */
	adjust = atoi(num+1);
     case 1:	/* +H */
	adjust += (num[0] - '0') * 60;
	break;
     case 2:	/* +HH */
	adjust = atoi(num) * 60;
	break;
     default:	/* +HHMM */
	if (num[2] != '0' || num[3] != '0') {
	    num[4] = NUL;
	    adjust = atoi(num + 2);
	}
	num[2] = NUL;
	adjust += atoi(num) * 60;
	break;
    }
    adjust *= sign;
    if (i == 0) return adjust;

 non_numeric:
    zone[i] = NUL;

    for (z = ztab; z->tz_name != NULL; z++) {
	if ((i = strcmp(zone, z->tz_name)) > 0) continue;
	if (i < 0) break;
	return z->tz_offset + adjust;
    }
    return adjust;
}

static next_int(dp)
char **dp;
{
    register char *str = *dp;
    register i;

    while (*str && !isdigit(*str)) str++;

    i = 0;
    while (*str && isdigit(*str))
	i = (i * 10) + *str++ - '0';

    *dp = str;
    return i;
}

time_stamp pack_date(date)
char *date;
{
    register time_stamp res;
    register int min, hour, day, mon, year;

    if (date == NULL || (day = next_int(&date)) == 0) return 0;

    while (*date && isspace(*date)) date++;

    if (date[0] == NUL || date[1] == NUL || date[2] == NUL) return 0;
    switch (date[0]) {
     case 'J': case 'j':
	if (date[1] == 'a' || date[1] == 'A') { mon = 0; break; }
	if (date[2] == 'n' || date[2] == 'N') { mon = 5; break; }
	mon = 6; break;
     case 'F': case 'f':
	mon = 1; break;
     case 'M': case 'm':
	if (date[2] == 'r' || date[2] == 'R') { mon = 2; break; }
	mon = 4; break;
     case 'A': case 'a':
	if (date[1] == 'p' || date[1] == 'P') { mon = 3; break; }
	mon = 7; break;
     case 'S': case 's':
	mon = 8; break;
     case 'O': case 'o':
	mon = 9; break;
     case 'N': case 'n':
	mon = 10; break;
     case 'D': case 'd':
	mon = 11; break;
     default:
	return 0;
    }

    year = next_int(&date);
    hour = next_int(&date);
    min = next_int(&date);
    if (*date == ':') next_int(&date);

    if (year >= 100) year -= 1900;	/* xxYY -> YY */
    year -= 87;	/* base is 1987 */
    if (year < 0) year += 100;

    res = (year * 12 + mon) * 31 + day - 1;
    res *= 24 * 60;
    res += (hour * 60) + min;

    return res + tzone(date);
}


#ifdef DATE_TEST


main()
{
    char buffer[128];
    char *dp;
    unsigned long t;

    while (fgets(buffer, 128, stdin)) {
	if (strncmp(buffer, "Date:", 5)) continue;

	dp = strchr(buffer, ':');
	if (dp == NULL) continue;
	dp++;
	while (isspace(*dp)) dp++;
	t = pack_date(dp);
	printf("%lu\t%s\n", t, dp);
    }

    exit(0);
}

#endif

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.