*BSD News Article 63993


Return to BSD News archive

Path: euryale.cc.adfa.oz.au!newshost.anu.edu.au!harbinger.cc.monash.edu.au!bunyip.cc.uq.oz.au!munnari.OZ.AU!news.ecn.uoknor.edu!news.ysu.edu!usenet.ins.cwru.edu!magnus.acs.ohio-state.edu!math.ohio-state.edu!howland.reston.ans.net!vixen.cso.uiuc.edu!newsfeed.internetmci.com!tank.news.pipex.net!pipex!news.mathworks.com!uunet!in1.uu.net!gti.gti.net!dkinney
From: dkinney@gti.net (David Kinney)
Newsgroups: comp.unix.programmer,comp.unix.bsd.freebsd.misc
Subject: Re: string -> time_t routine, anyone?
Followup-To: comp.unix.programmer,comp.unix.bsd.freebsd.misc
Date: 22 Mar 1996 23:38:28 GMT
Organization: GTI GlobalNet - (201) 285-9099
Lines: 265
Message-ID: <4ivdlk$jq@gti.gti.net>
References: <1996Mar21.083253.22259@wavehh.hanse.de>
NNTP-Posting-Host: apollo.gti.net
X-Newsreader: TIN [version 1.2 PL2]
Xref: euryale.cc.adfa.oz.au comp.unix.programmer:35440 comp.unix.bsd.freebsd.misc:15780

Martin Cracauer (cracauer@wavehh.hanse.de) wrote:
: I need a routine to convert a string like "19960302" (or other syntax)
: to a time_t. I thought about using the source of date(1), but maybe
: someone has done this before?

	Hi Martin.

	Below is my program "not_ctime.c" which does basically what
	you want.  You may need to modify it slightly depending on
	the input format you use.

	Hope this helps,

		David Kinney   dkinney@gti.net


/******************************************************************************
*
*
*	Program:	not_ctime
*	========	
*
*		Reverse the effects of my 'ctime.c' program.
*               If you input a string such as the default format output
*		of 'date':
*
*               not_ctime Mon Dec 18 20:38:52 EST 1995
*
*               "not_ctime" will return the absolute number of seconds since
*		since the beginning of the epoch (Jan. 1 1970).  E.g.:
*
*		The time_since_epoch is 819337132 sec.
*
*
*               My "ctime" program takes the absolute number of seconds
*		since the beginning of the epoch, e.g. ctime 819337132
*		and returns a default format 'date' string.  E.g.:
*
*		Mon Dec 18 20:38:52 EST 1995
*
*
*               "not_ctime" will be useful when you're trying to determine
*		the elapsed time between two calendar dates.  E.g. between:
*		Mon May 17 16:20:17 EST 1954  and
*               Mon Dec 18 20:38:52 EST 1995
*
*               See also my programs 'ctime', 'difftime', and
*		'sec_to_time_string'.
*
*
*       Input:	A string such as the default format output of 'date'.
*       ======  E.g.  Mon Dec 18 20:38:52 EST 1995
*
*               Specifically, the format is:
*               day_of_week month_name month_date, time_string time_zone year
*
*               Since "not_ctime" ignores the "day_of_week" and "time_zone"
*		fields, you could put garbage in them, but there has to be
*		something in these two fields so that the argv[] counts are
*		correct.
*
*
*	Output:	Outputs the absolute number of seconds since
*	======= since the beginning of the epoch (Jan. 1 1970).  E.g.
*
*		The time_since_epoch is 819337132 sec.
*
*
*	Error Handling:	There are 3 possible error conditions:
*	===============
*		1. Number of input args. (argc) != 7
*		   There must be the name of this command + 6 other args.
*
*		2. Read in non-month string (e.g. XXX) when expecting a
*		   month string such as "Dec".
*
*		3. (year < 1900) || (year > 2038)
*		   'mktime()' will only handle years between 1900 - 2038.
*		   Anything else is out of range.
*
*		All these errors cause 'print_usage' to be called then
*		exit() the program.  Note that the exit() is called
*		immediately *after* 'print_usage()' returns.  exit() is not
*		called from 'print_usage()'
*
*		'print_usage(argv[0])' prints to stderr:"
*
* Usage: not_ctime day_of_week month_name month_date, time_string time_zone year
*        Ex: Mon Dec 18 20:38:52 EST 1995
*
*
*	Routines:	print_usage()
*	=========       
*
*
*       Calls:		mktime()
*       ======
*
*
*	Programmer:	David Kinney
*	===========
*
*
*	Date:		Mon. Dec. 18, 1995
*	=====
*
*
*       Comments:	There are *13* routines such as 'ctime()' that
*       =========       "convert date and time to string".  However,
*                       the only way to do the reverse is to use a
*                       side-effect of 'mktime()'.  This is what
*                       "not_ctime" does.
*
*
*	REVISION HISTORY
*	================
*
*       Date	|     Who	| Comments
*    =========================================================================
*               |               |
*      12/18/95 |     DK        |  Created
*               |               |
******************************************************************************/


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

#define ILLEGAL_MONTH_NR -1
#define MATCH	0

/* From 'man mktime()':

     "The tm structure contains the following members:

          int     tm_sec;       seconds after the minute [0, 61]
          int     tm_min;       minutes after the hour [0, 59]
          int     tm_hour;      hour since midnight [0, 23]
          int     tm_mday;      day of the month [1, 31]
          int     tm_mon;       months since January [0, 11]
          int     tm_year;      years since 1900
          int     tm_wday;      days since Sunday [0, 6]
          int     tm_yday;      days since January 1 [0, 365]
          int     tm_isdst;	flag for daylight savings time

	....

     tm_year of the tm structure must be for year 1970 or  later.
     Calendar times before 00:00:00 UTC, January 1, 1970 or after
     03:14:07 UTC, January 19, 2038 cannot be represented."

	I don't need the fields "tm_wday" and "tm_yday" so I don't set them.
	However, 'mktime()' will automatically fill them in.

	This program accepts input for "tm_mon" as a month name (e.g.
	"Dec"), converts it to a number (e.g. 11) which falls in the [0-11]
	range needed for "tm_mon".

*/
 
struct tm time_str;
time_t time_since_epoch;

char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
                   "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
int month_nr;
int hours, minutes, seconds, year;




main(argc, argv)
        int argc;
        char *argv[];
{
int i;


if (argc != 7)
    {
    print_usage(argv[0]);
    exit();
    }


/* We don't use argv[1], the day_name.  E.g. "Mon" */


/* Convert the month str, e.g. "Dec" to a month number, e.g. 11.
   Note: the month number will be one less than usual (e.g. "Dec"
   is 11) 'cause "time_str.tm_mon" expects not the month number,
   but rather the number of months *since* Jan. [0-11] */

month_nr = ILLEGAL_MONTH_NR;
for (i = 0; i <= 11; i++)
     if (strcmp(months[i], argv[2]) == MATCH)
	{
	month_nr = i;
	break;
	}

if (month_nr == ILLEGAL_MONTH_NR)
    {
    printf("\n\nERROR: Read in non-month string \"%s\", when\n");
    printf("       expected to get a month string such as \"Dec\".\n\n", argv[2]);
    print_usage(argv[0]);
    exit();
    }


time_str.tm_mon  = month_nr;
time_str.tm_mday = atoi(argv[3]);


/* argv[4] is a string with the format  hh:mm:ss  E.g.  21:05:32 */

sscanf(argv[4], "%d:%d:%d",
		&time_str.tm_hour, &time_str.tm_min, &time_str.tm_sec);



/* We don't use argv[5], the time zone.  E.g. "EDT" */


year = atoi(argv[6]);

if ( (year < 1900) || (year > 2038) )
    {
    print_usage(argv[0]);
    exit();
    }
else
    year -= 1900;

/* "year" should now contain the nr. of years since 1900 !  E.g. 95 */
    
time_str.tm_year = year;


/* Don't know if daylight savings time is in effect or not.  By setting
   this variable to -1, 'mktime()' will figure it out and adjust for it. */

time_str.tm_isdst = -1;


time_since_epoch = mktime(&time_str);

if ( time_since_epoch == -1)
   {
   printf("\nThe calendar time cannot be represented\n\n");
   print_usage(argv[0]);
   exit();
   }

printf("\nThe time_since_epoch is %d sec.\n\n", time_since_epoch);
}


print_usage(program_name)
    char *program_name;
{
fprintf(stderr, "\nUsage:	%s day_of_week month_name month_date, time_string time_zone year\n", program_name);
fprintf(stderr, "	Ex: Mon Dec 18 20:38:52 EST 1995\n\n");
}