#include "parsedate.h"

/*
 ****************************************************************************
 *
 * parsedate.(c/h)
 *
 * All function(s) required for parsing netlogger timestamps:
 *
 *   - double calcDate( const char *)
 *   - double convertDate( long sec, long usec )
 *
 * $Author: mstoufer $
 * $Source: /home/g2/src/projects/NetLogger/src/nlv/parsedate.c,v $
 * $RCSfile: parsedate.c,v $
 * $Revision: 1.1.1.1 $
 * $Locker:  $
 * $Date: 2000/12/05 19:52:32 $
 *
 ****************************************************************************
 */
static char rcsid[] = "$Id: parsedate.c,v 1.1.1.1 2000/12/05 19:52:32 mstoufer Exp $";

/*
 *---------------------------------------------------------------------------
 * calcDate -- Calculate date in sec. since 1/1/1970 from string.
 *             Algorithm borrowed from linux kernel source code,
 *             i.e. Linus Torvalds, who in turn credits it to Gauss.
 *
 * PRE: Input is properly formatted, non-null, need _not_ be null-terminated.
 * IN : String in format YYYYMMDDHHmmss.uuuuuu
 *        YYYY  = 4 digit year
 *        MM    = 2 digit month (1..12)
 *        DD    = 2 digit day of month (1..31)
 *        HH    = 2 digit hour of day ( 0..23 )
 *        mm    = 2 digit minute of hour ( 0..59 )
 *        ss    = 2 digit second of minute ( 0..59 )
 *        uuuuuu= 1..6 digit microsecond of second ( 0..999999 )
 * OUT: Number of seconds, and fraction accurate to at most microseconds,
 *      elapsed since 1/1/1970 (GMT).
 *---------------------------------------------------------------------------
 */
double Nlv_pdCalcDate( const char *s )
{
  unsigned int year, mon, day, hour, min, sec;
  unsigned long usec;

  /* printf("<dbg> pdCalcDate(\"%s\")\n", s ); */

  sscanf(s, "%4u%2u%2u%2u%2u%2u.%uld", &year, &mon, &day, &hour, &min, &sec, &usec );

  if (0 >= (int) (mon -= 2)) {    /* 1..12 -> 11,12,1..10 */
    mon += 12;      /* Puts Feb last since it has leap day */
    year -= 1;
  }
  return (double)
    ( ( ( (
	   (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
	   year*365 - 719499
	   )*24 + hour /* now have hours */
	  )*60 + min /* now have minutes */
	)*60 + sec /* seconds */
      ) + (double)( usec / 1E6 ); /* microseconds */
}
/*
 *---------------------------------------------------------------------------
 * calcDate2 -- Exactly the same as calcDate, just a different name to
 *              acoid using a mutex in a thread that needs to parse quickly.
 *---------------------------------------------------------------------------
 */
double Nlv_pdCalcDate2( const char *s )
{
  unsigned int year, mon, day, hour, min, sec;
  unsigned long usec;

  /*  printf("<dbg> pdCalcDate(\"%s\")\n", s ); */

  sscanf(s, "%4u%2u%2u%2u%2u%2u.%uld", &year, &mon, &day, &hour, &min, &sec, &usec );

  if (0 >= (int) (mon -= 2)) {    /* 1..12 -> 11,12,1..10 */
    mon += 12;      /* Puts Feb last since it has leap day */
    year -= 1;
  }
  return (double)
    ( ( ( (
	   (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
	   year*365 - 719499
	   )*24 + hour /* now have hours */
	  )*60 + min /* now have minutes */
	)*60 + sec /* seconds */
      ) + (double)( usec / 1E6 ); /* microseconds */
}


/*
 *---------------------------------------------------------------------------
 * convertDate -- Take a seconds, microseconds argument and convert it
 *                to a date string that calcDate could parse.
 *
 * CALL: gmtime, strftime
 *
 * PRE : seconds, usec >= 0 , usec < 1000000 (checked)
 *       date string has DATE_STRING_LENGTH+1 bytes allocated (not checked)
 * IN  : seconds, useconds
 * OUT : date string 'dstr'.
 * RTRN: 0=OK, other=FAILURE
 * POST: This is the inverse of calcDate, i.e.
 *         calcDate( convertDate( sec, usec ) ) = sec.usec
 *---------------------------------------------------------------------------
 */
int Nlv_pdConvertDate( long sec, long usec, char *dstr )
{
  char *func = "Nlv_pdConvertDate";
  struct tm *tp;
  int        len;

  if ( sec < 0 || usec < 0 || usec > 999999 )
    return 1;

  tp = gmtime( (const time_t *) &sec );
  if ( tp == NULL )
    return 1;

  len = strftime( dstr,
		  DATE_STRING_LENGTH+1-7,
		  "%Y%m%d%H%M%S",
		  tp );
  if ( len != DATE_STRING_LENGTH-7 ) {
    fprintf(stderr,"%s: bad strftime() return value: %d\n",func, len);
    return 1;
  }

  sprintf( dstr + DATE_STRING_LENGTH-7, ".%ld", usec );

  return 0;
}
