[comp.unix.programmer] need "yy-ddd-hh:mm:ss ==>

tsingle@sunland.gsfc.nasa.gov (Tim Singletary) (01/19/91)

Help!  I need something to convert yy-ddd-hh:mm:ss (i.e. year,
day_of_year, hour, minute, second) to a unix-style
_number_of_seconds_since_00:00:00_GMT,_Jan._1,_1970_.

I tried to use Sun's timelocal() function but couldn't get it to work (it
lets you pass both _day_of_year_ and _month,_day_of_month_ with no way
to specify which is correct!).

Ideally what I'm looking for is source code to a timelocal() function,
but any tips or suggestions will be appreciated.

Thanks in advance, 

tim

--
Tim Singletary, August Automation Inc., (301) 286-7942
--
NRA extremist, etc.

jap@convex.cl.msu.edu (Joe Porkka) (01/19/91)

tsingle@sunland.gsfc.nasa.gov (Tim Singletary) writes:

>Help!  I need something to convert yy-ddd-hh:mm:ss (i.e. year,
>day_of_year, hour, minute, second) to a unix-style
>_number_of_seconds_since_00:00:00_GMT,_Jan._1,_1970_.

>I tried to use Sun's timelocal() function but couldn't get it to work (it

Since your using a Sun you can use strptime(), at least
in SunOS 4.1.

I have no idea if this is a Sun defined function, or an ANSI
function.

mike@bria.UUCP (Michael Stefanik) (01/20/91)

In article <TSINGLE.91Jan18120847@sunland.gsfc.nasa.gov> sunland.gsfc.nasa.gov!tsingle (Tim Singletary) writes:
>Help!  I need something to convert yy-ddd-hh:mm:ss (i.e. year,
>day_of_year, hour, minute, second) to a unix-style
>_number_of_seconds_since_00:00:00_GMT,_Jan._1,_1970_.

I am doing this with the full knowledge that people are going to send me
flaming mail about what an ugly solution this is, but ... here is a little
ditty I wrote that seems to even work ...

/*	@(#)tmparse.c	1.1 	parse a time specification
*/

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <time.h>

#define ONE_DAY		86400L
#define ONE_YEAR	31564800L
#define ONE_THIRD	28800L

int mdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

main()
{
long	now;
char	buf[64];

	for (;;) {
		printf("Enter date: ");
		if ( gets(buf) == NULL )
			break;

		tmparse(buf,&now);
		printf("%s",ctime(&now));
		}
}

long tmparse(buf,when)
char	*buf;
long	*when;
{
long		date, now;
int		year = 1970, month = 0, day = 0;
int		hours = 0, mins = 0, secs = 0, count;
char		*ptr, *next;
struct tm	*lt;

	time(&now);
	lt = localtime(&now);

	if ( strchr(buf,'/') == NULL && strchr(buf,'-') == NULL ) {
		month = lt->tm_mon;
		day = lt->tm_mday - 1;
		year = lt->tm_year + 1900;
		next = buf;
		}
	else {
		month = atoi(strtok(buf,"/-")) - 1;
		day = atoi(strtok(NULL,"/-")) - 1;
		year = atoi(strtok(NULL," "));
		next = NULL;

		if ( year == 0 )
			year = lt->tm_year + 1900;
		else if ( year < 100 )
			year += 1900;
		}

	if ( year < 1970 ) {
		*when = 0L;
		return(0L);
		}

	if ( (ptr = strtok(next,":")) != NULL ) {
		while ( isspace(*ptr) )
			++ptr;
		hours = atoi(ptr);
		mins = atoi(strtok(NULL,":"));
		secs = atoi(strtok(NULL,""));
		}

	date = 0L;
	for ( count = 1970; count < year; count++) {
		date += ONE_YEAR;
		if ( count % 4 == 0 || count % 400 == 0 )
			date += ONE_DAY;
		}
	date -= (year - 1971) * ONE_THIRD;

	for ( count = 0; count < month; count++) {
		date += mdays[count] * ONE_DAY;
		if ( count == 1 && (year % 4 == 0 || year % 400 == 0) )
			date += ONE_DAY;
		}

	date += (day * ONE_DAY) + secs + (mins * 60) + (hours * 3600);

	lt = localtime(&date);
	date += (hours - lt->tm_hour) * 3600;

	*when = date;
	return(date);
}
-- 
Michael Stefanik, Systems Engineer (JOAT), Briareus Corporation
UUCP: ...!uunet!bria!mike
--
technoignorami (tek'no-ig'no-ram`i) a group of individuals that are constantly
found to be saying things like "Well, it works on my DOS machine ..."

guy@auspex.auspex.com (Guy Harris) (01/21/91)

In article <TSINGLE.91Jan18120847@sunland.gsfc.nasa.gov>
  tsingle@sunland.gsfc.nasa.gov (Tim Singletary) writes:
> Help!  I need something to convert yy-ddd-hh:mm:ss (i.e. year,
> day_of_year, hour, minute, second) to a unix-style
> _number_of_seconds_since_00:00:00_GMT,_Jan._1,_1970_.
> 
> I tried to use Sun's timelocal() function but couldn't get it to work (it
> lets you pass both _day_of_year_ and _month,_day_of_month_ with no way
> to specify which is correct!).

It lets you pass day-of-year, but it ignores it.  It looks at month and
day-of-month.  (As one of the Timezone Caballeros, and as the person who
put the "Arthur Olson" timezone stuff, including "timelocal()" - which
was adapted from code by Robert Elz, from an idea by Bob Kridle - into
SunOS 4.x, I know whereof I speak here.)

> Ideally what I'm looking for is source code to a timelocal() function,
> but any tips or suggestions will be appreciated.

Try grabbing the source to the "Arthur Olson" timezone code - the SunOS
code, as indicated, comes from that - from some archive site; it was
posted to "comp.sources.unix" or somesuch at some point.

In article <1991Jan18.200700.11045@msuinfo.cl.msu.edu>
  jap@convex.cl.msu.edu (Joe Porkka) writes:
>Since your using a Sun you can use strptime(), at least
>in SunOS 4.1.

No, not entirely.  "strptime()" converts a character string into a
"struct tm"; "timelocal()" - and "mktime()", in ANSI C and/or
POSIX-compliant systems such as SunOS 4.1 (POSIX, not ANSI C, in the
case of 4.1) - convert a "struct tm" into a UNIX time.

Think of "strptime()" as being the "inverse" of "strftime()", and
"timelocal()"/"mktime()" as being the "inverse" of "localtime()".

>I have no idea if this is a Sun defined function, or an ANSI
>function.

It's a Sun-defined function, and it doesn't really do what such a
function should do (as the person who defined it, I have the right to
say it's the wrong answer :-)).

It shouldn't be responsible for figuring out which fields of a time/date
specification may be elided, because that means it has to interpret the
format specification in more detail than is appropriate.  Instead, it
should blindly match the string against the format, and some
higher-level routine should try matching various format strings, e.g. 
one with the "seconds" field of a time and then one without. 

Unfortunately, AT&T's S5R4 "getdate()" routine, which operates similarly to
the aforementioned higher-level routine, doesn't seem to be quite right,
either; it's not affected, as far as I know, by the LANG or LC_TIME
environment variables except to the extent that it might change the
names it's willing to accept for months - I don't think you can set LANG
and have it change the syntaxes it's willing to accept for dates, times,
or date+time.

guy@auspex.auspex.com (Guy Harris) (01/23/91)

>Question: how does getdate(SVR4) differ from Steve Bellovin's getdate()
>	  as found in the news packages ?  Is it similar or does it do
>	  something entirely different ?

Something fairly different.

Bellovin's uses YACC to parse a number of hard-coded formats.  It takes,
as its arguments, a pointer to the string to parse and an optional
pointer to a "struct timeb" holding the current time, the current offset
from GMT and "daylight savings time is honored" flag.  (If the pointer
is NULL, it will call "ftime()" to get that information itself.  Netnews
comes with an "ftime()" routine for systems with S3/S5-style timezone
handling.)

It returns a "time_t" representing the parsed time in seconds since the
Epoch.

S5R4's parses the date by trying a list of formats specified in the file
whose name appears in the environment variable DATEMSK.  It takes, as
its argument, a pointer to the string to parse.

(Unfortunately, according to the manual, it requires DATEMSK to be set,
and won't pick the file based on the setting of LANG or LC_TIME; the
strings it will accept for some things, such as "%A" or "%B" or "%b" or
"%c", will come from the locale, but there doesn't seem to be a way to
tell it to accept "%m/%d/%y" as one of the formats if LANG is set to an
appropriate value for the US, "%d/%m/%y" for locales that work that way,
"%d.%m.%y" for locales that work that way, etc. - it appears you'd have
to have different DATEMSK files for different locales, and set DATEMSK
as well as LANG.  Not fatal, but annoyingly inconvenient.

Yes, I know it has a "%c" that represents "the locale's appropriate date
and time representation", and "%X" that represents "the locale's
appropriate time representation", and "%x" that represents "the locale's
appropriate date representation"; unfortunately, I'm not sure there is
*one single* "appropriate" representation for a locale - is the
appropriate representation for the date in the US locale something that
handles "1/22/91", or something that handles "January 22, 1991", or...?)

It returns a pointer to a "struct tm" representing the parsed time in
broken-down *local* time format; if you want to make a "time_t" out of
it, you have to run the "struct tm" through "mktime()".