(file) Return to time_convert.c CVS log (file) (dir) Up to [Development] / JSOC / proj / util / apps

File: [Development] / JSOC / proj / util / apps / time_convert.c (download)
Revision: 1.5, Mon Nov 16 22:25:03 2009 UTC (13 years, 10 months ago) by kehcheng
Branch: MAIN
CVS Tags: Ver_LATEST, Ver_9-5, Ver_9-41, Ver_9-4, Ver_9-3, Ver_9-2, Ver_9-1, Ver_9-0, Ver_8-8, Ver_8-7, Ver_8-6, Ver_8-5, Ver_8-4, Ver_8-3, Ver_8-2, Ver_8-12, Ver_8-11, Ver_8-10, Ver_8-1, Ver_8-0, Ver_7-1, Ver_7-0, Ver_6-4, Ver_6-3, Ver_6-2, Ver_6-1, Ver_6-0, Ver_5-9, Ver_5-8, Ver_5-7, Ver_5-6, Ver_5-14, Ver_5-13, Ver_5-12, Ver_5-11, Ver_5-10
Changes since 1.4: +1 -1 lines
Fix typo (1997 -> 1977).

/*
 * time_convert - change TAI time since 1977 into ascii with a given timezone
 * and from an ascii time to seconds.  Takes one argument of time or seconds and an optional
 * flag argument of time zone.  Default is UTC for conversion to ascii.
 */

/**
   @defgroup time_convert time_convert
   @ingroup su_util

   @brief Convert among the internal DRMS time representation and other time representations.

   @par Synopsis:
   @code
   time_convert -h
   time_convert s=<secondsJSOC> | sdo=<secondsSDO> | egse=<secondsEGSE> | time=<calenderTime> |
                ord=<ordinalDate> [o=jsoc | o=sdo | o=egse | o=ord | o=cal] [zone=<zone>] [p=<precision>]

   @endcode

   Converts internal DRMS time (seconds since 15 seconds 
   before January 1, 1977 UTC) to an external ascii string 
   representation. The exact external representation depends on the command-line
   arguments provided to this utility. Possiblities include: <tt>SDO time</tt>, 
   <tt>EGSE time</tt>, <tt>Ordinal date</tt>, and <tt>Calendar time</tt>.  
   <tt>SDO time</tt> is the number of seconds that have elapsed since 
   January 1, 1958 TAI, i.e. SDO onboard time. The full format is the string
   representation of a double data type. <tt>EGSE time</tt> is 
   the number of seconds that have elapsed since @e APPROXIMATELY January 1, 2004 UTC
   (actual epoch is 2003.12.30_23:59:36.000_UTC). The full format is also the string
   representation of a double data type. <tt>Ordinal date</tt> is 
   the day number of the year (starting at day 1 on January 1). The full format
   is YYYY.DDD[_ZZZ], where YYYY is the year, DDD is the day number, and ZZZ is the
   zone (e.g., UTC, TDT, PDT, etc.). <tt>Calendar time</tt> gives the year, month, date, hour, 
   minutes, and seconds for a given system of time (like @e UTC). The full format is
   specified in <tt>JSOC TN 07-001</tt> (http://jsoc.stanford.edu/doc/timerep.html), 
   but in short it looks like:

   @par
   1.  year.month.fracday[_type]
   @par
   2.  year.month.day_hour:minute[:second][_type]
   @par
   3.  {MJD|JD}_julday[_type]

   where @a type refers to the time system or time zone (e.g., @e UTC, or @e PST), @e MJD and
   @e JD refer to Modified Julian Date and Julian Date, and @e julday refers to a Julian 
   day number.

   The precision of the seconds field is specified with the <tt>p</tt> parameter.  The default is 0.  Setting p=3 will produce output identical to the original version of time_convert.

   Alternatively, and with the appropriate command-line parameters, @ref time_convert 
   converts from any supported time representation to any other representation.

   If multiple input format strings are specified as arguments 
   (e.g., time_convert s=234235235.35 ord=1982.035), only one will be used. A descriptive 
   string will be printed describing which input string was used. Given a definitive
   input format, @ref time_convert chooses a default output format. If the input is 
   an internal time, an SDO time, an EGSE time, or an ordinal date, the default output 
   is a calendar time. If the definitive input format is a calendar time, the default
   output is an internal time. The default output format can be overwritten
   by providing the @a o=format argument. 

   When the output format is either an ordinal time or a calendar time, the 
   time can be expressed in any of several supported time systems (e.g., @e UTC,
   @e TDT, @e TAI, or even a time zone, like @e PDT). This is accomplished by
   supplying the appropriate @a zone=system argument. Refer to 
   <tt>JSOC TN 07-001</tt> (http://jsoc.stanford.edu/doc/timerep.html) for a 
   complete list of the supported "zones".

   The default time format is with no fractions of seconds.  If o=jsoc is specified the seconds are provided to the nearest ms.

   @par Flags:
   @c -h: Show usage message.

   @param s An input time formatted as an internal time. 
   <secondsJSOC> is seconds since 15 seconds before January 1, 1977 UTC.
   @param sdo  An input time formatted as an SDO time.
   <secondsSDO> is seconds since January 1, 1958 TAI.
   @param egse  An input time formatted as an EGSE time.
   <secondsEGSE> is seconds since 2003.12.30_23:59:36.000_UTC
   @param time  An input time formatted as a calendar time.
   <calenderTime> is as specified in 
   <tt>JSOC TN 07-001</tt> (http://jsoc.stanford.edu/doc/timerep.html)
   @param ord An input time formatted as an ordinal date.
   <ordinalDate> is yyyy.ddd[_zone], where @a zone is any supported 
   time system as specified in  <tt>JSOC TN 07-001</tt> 
   (http://jsoc.stanford.edu/doc/timerep.html).
   @param o The output format to be used. "jsoc" refers to internal time; 
   "sdo" refers to SDO time; "egse" refers to EGSE time; 
   "ord" refers to ordinal date; and "cal" refers to calendar time.

   @par Example to convert an internal time to the default output format (UTC calendar time):
   @code
   time_convert s=234253535.23
   @endcode

   @par Example to convert an internal time to the default output format (calendar time), but in TAI time:
   @code
   time_convert s=234253535.23 zone=TAI
   @endcode

   @par Example to convert an internal time to an EGSE time:
   @code
   time_convert s=234253535.23 o=egse
   @endcode

   @par Example to convert an EGSE time to a calendar time in the PDT time zone:
   @code
   time_convert egse=232533636.362 o=cal zone=PDT
   @endcode

   @par Example to convert an ordinal time to a calendar time in the TDT system:
   @code
   time_convert ord=2007.352 o=cal zone=TDT
   @endcode

   @par Example to convert a calendar time to an internal time:
   @code
   time_convert time=1998.02.04_06:00:17.230_UTC
   @endcode

   @par Example to convert a calendar time to an internal time (explicitly):
   @code
   time_convert time=1998.02.04_06:00:17.230_UTC o=jsoc
   @endcode

   @par Example to convert a calendar time to an SDO time
   @code
   time_convert time=1998.02.04_06:00:17.230_UTC o=sdo
   @endcode
*/
/* @{ */
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include "timeio.h"
#include "jsoc.h"
#include "cmdparams.h"

ModuleArgs_t module_args[] =
{
  {ARG_STRING, "s", "NOT SPECIFIED", "<DSDS/JSOC time in seconds>"},
  {ARG_STRING, "sdo", "NOT SPECIFIED", "<SDO time in seconds>"},
  {ARG_STRING, "egse", "NOT SPECIFIED", "<EGSE time in seconds>"},
  {ARG_STRING, "time", "NOT SPECIFIED", "<Time as yyyy.mm...>"},
  {ARG_STRING, "ord", "NOT SPECIFIED", "<Time as yyyy.ddd...>"},
  {ARG_STRING, "zone", "UTC", "<Time zone>"},
  {ARG_STRING, "o", "NOT SPECIFIED", "format of time output"},
  {ARG_INT, "p", "0", "precision of seconds for time output"},
  {ARG_FLAG, "h", "0", "help message"},
  {ARG_END}
};

ModuleArgs_t *gModArgs = module_args;
/* @} */

CmdParams_t cmdparams;

#define SEC1970TO2004   1072828800
#define SECSPERDAY         86400.0

typedef enum
{
   kTimeFormat_None = 0,
   kTimeFormat_Internal,
   kTimeFormat_SDO,
   kTimeFormat_EGSE,
   kTimeFormat_Ordinal,
   kTimeFormat_Calendar
} TimeFormat_t;

char *TimeFormatStr[] = 
{
   "None",
   "Internal/JSOC",
   "SDO",
   "EGSE",
   "Ordinal",
   "Calendar"
};

static void PrintTime(TIME t, TimeFormat_t f, int precision);
static TIME ZoneAdjustment(TIME t, char *zone, int precision);

int nice_intro ()
  {
  int usage = cmdparams_get_int (&cmdparams, "h", NULL);
  if (usage)
    {
    printf ("Usage:\ntime_convert -h\n"
	"time_convert s=<secondsJSOC>|sdo=<secondsSDO>|egse=<secondsEGSE>|time=<calender time>|ord=<ordinal date> [o=jsoc | o=sdo | o=egse | o=ord | o=cal] [zone=<zone>]\n"
        "<secondsJSOC> = JSOC standard internal time, i.e. secs since 1977.01.01_TAI \n"
        "<secondsSDO> = seconds since January 1, 1958 TAI, i.e. SDO onboard time\n"
	"<secondsEGSE> = seconds since APPROXIMATELY January 1, 2004 \n"
        "<calender time> = yyyy.mm.dd_hh:mm:ss<zone>\n"
	"<ordinal date> = yyyy.ddd<zone>\n"
        "<zone> = time zone as UT, TAI, PST, etc. - default is UTC\n"
	"h - show usage message\n"
        "o - output time in format specified\n"
        "p - precision of seconds printed\n");
    return(1);
    }
  return (0);
  }

int main(int argc, char **argv)
{
int status;
TIME sscan_time(char *s);

char *s, *sdo, *time;
char *ord; /* Users can now supply the time argument as an ordinal date ('day-of-year' format - ISO 8601): YYYY.DDD */
char *egse = NULL;
char *oArg = NULL;
int precision = 0;

TIME t;

/* Parse command line parameters */
status = cmdparams_parse (&cmdparams, argc, argv);
if (status == CMDPARAMS_QUERYMODE)
  {
  cmdparams_usage (argv[0]);
  return 0;
  }

if (nice_intro ())
  return (0);

/* The are the different types of input. */
s = cmdparams_get_str(&cmdparams, "s", NULL);
sdo = cmdparams_get_str(&cmdparams, "sdo", NULL);
time = cmdparams_get_str(&cmdparams, "time", NULL);
ord = cmdparams_get_str(&cmdparams, "ord", NULL);
egse = cmdparams_get_str(&cmdparams, "egse", NULL);

/* Determine seconds precision */
precision = cmdparams_get_int(&cmdparams, "p", NULL);

int err = 0;

TIME timeToPrint;
TimeFormat_t inputFormat = kTimeFormat_None;
TimeFormat_t outputFormat = kTimeFormat_None;
TimeFormat_t outputOverride = kTimeFormat_None;
int mFormats = 0;

/* These are the different types of output. */
oArg = cmdparams_get_str(&cmdparams, "o", NULL);
if (strcmp(oArg, "NOT SPECIFIED") != 0)
{
   if (strcmp(oArg, "jsoc") == 0)
   {
      outputOverride = kTimeFormat_Internal;
   }
   else if (strcmp(oArg, "sdo") == 0)
   {
      outputOverride = kTimeFormat_SDO;
   }
   else if (strcmp(oArg, "egse") == 0)
   {
      outputOverride = kTimeFormat_EGSE;
   }
   else if (strcmp(oArg, "ord") == 0)
   {
      outputOverride = kTimeFormat_Ordinal;
   }
   else if (strcmp(oArg, "cal") == 0)
   {
      outputOverride = kTimeFormat_Calendar;
   }
   else
   {
      fprintf(stderr, "Output format %s is not recognized.  Using default.\n", oArg);
   }
}

if (strcmp(s, "NOT SPECIFIED")!= 0)
{ 
   /* internal seconds was specified */
   if (inputFormat == kTimeFormat_None)
   {
      sscanf(s, "%lf", &t);
      timeToPrint = t;
      outputFormat = kTimeFormat_Calendar;
      inputFormat =  kTimeFormat_Internal;
   }
   else
   {
      mFormats = 1;
   }
}
if (strcmp(sdo, "NOT SPECIFIED")!= 0)
{ 
   /* SDO seconds was specified */
   if (inputFormat == kTimeFormat_None)
   {
      sscanf(sdo, "%lf", &t);
      timeToPrint = t + sscan_time("1958.01.01_00:00:00_TAI");
      outputFormat = kTimeFormat_Calendar;
      inputFormat = kTimeFormat_SDO;
   }
   else
   {
      mFormats = 1;
   }
}
if (strcmp(egse, "NOT SPECIFIED") != 0)
{
   /* Time since ~ 1/1/2004 was provided as input */
   if (inputFormat == kTimeFormat_None)
   {
      sscanf(egse, "%lf", &t);
      timeToPrint = t + SEC1970TO2004 + sscan_time("1970.01.01_00:00_UTC");
      outputFormat = kTimeFormat_Calendar;
      inputFormat = kTimeFormat_EGSE;
   }
   else
   {
      mFormats = 1;
   }
}
if (strcmp(time, "NOT SPECIFIED")!= 0)
{ 
   /* calendar time string was specified */
   if (inputFormat == kTimeFormat_None)
   {
      t = sscan_time(time);
      timeToPrint = t;
      outputFormat = kTimeFormat_Internal;
      inputFormat = kTimeFormat_Calendar;
   }
   else
   {
      mFormats = 1;
   }
}
if (ord != NULL && *ord != NULL && strcmp(ord, "NOT SPECIFIED") != 0)
{
   /* day-of-year was specified - convert to internal representation */
   if (inputFormat == kTimeFormat_None)
   {
      err = 1;
      
      long year = 0;
      int day = 0;
      char *tFormat = NULL;
      
      char *ordDate = strdup(ord);
      int timeStrLen = strlen(ordDate);
      
      if (ordDate != NULL)
      {
	 char *loc = strchr(ordDate, '.');
	 char *loc2 = strchr(ordDate, '_');
	 
	 if (loc != NULL)
	 {
	    *loc = '\0';
	    
	    if (sscanf(ordDate, "%ld", &year) != 0)
	    {
	       if (loc2 != NULL && loc2 > loc)
	       {
		  *loc2 = '\0';
		  sscanf(loc + 1, "%d", &day);
		  
		  if (loc2 + 1 <= &ordDate[timeStrLen - 1])
		  {
		     tFormat = (char *)malloc(sizeof(char) * strlen(loc2 + 1) + 1);
		     if (tFormat)
		     {
			sscanf(loc2 + 1, "%s", tFormat);
		     }
		  }
	       }
	       else if (loc + 1 <= &ordDate[timeStrLen - 1])
	       {
		  sscanf((loc + 1), "%d", &day);
	       }
	       
	       err = (day < 1 || day > 366);
	       
	       if (!err)
	       {
		  /* first convert to calendar date */
		  char timeBuf[64];
		  snprintf(timeBuf, sizeof(timeBuf), "%ld.01.%d_00:00_%s", year, day, tFormat ? tFormat : "UT");
		  /* then use sscan_time to convert to internal time */
		  // t = sscan_time(timeBuf) - sscan_time("1977.01.01_00:00_TAI");
		  // sscan_time("1977.01.01_00:00_TAI") == 0
		  t = sscan_time(timeBuf);
		  timeToPrint = t;
		  outputFormat = kTimeFormat_Internal;
		  inputFormat = kTimeFormat_Ordinal;
	       }
	       else
	       {
		  fprintf(stderr, "invalid day of year\n");
	       }
	    }
	    else
	    {
	       fprintf(stderr, "invalid year\n");
	    }
	 }
	 else
	 {
	    fprintf(stderr, "missing day of year\n");
	 }
	 
	 free(ordDate);
      }
      
      if (tFormat)
      {
	 free(tFormat);
      }
   }
   else
   {
      mFormats = 1;
   }
}

if (inputFormat == kTimeFormat_None)
{
   fprintf(stderr, "No input format specified.\n");
   err = 1;
}
else if (mFormats)
{
   fprintf(stderr, 
	   "Multiple input formats specified, using %s time\n", 
	   TimeFormatStr[inputFormat]);
}

if (outputOverride != kTimeFormat_None)
{
   outputFormat = outputOverride;
}

if (!err)
{
   PrintTime(timeToPrint, outputFormat, precision);
}

if (err)
{
   fprintf(stderr,"time_convert call error\n");
   return(1);
}
else
{
   return(0);
}
}

/* t is time in TAI seconds since 1/1/1977, f is the format in which to print the time string */
void PrintTime(TIME t, TimeFormat_t f, int precision)
{
   if (f == kTimeFormat_Calendar)
   {
      char at[128];
      sprint_time(at, t, cmdparams_get_str(&cmdparams, "zone", NULL), precision);
      // broken for precision == 3, causes seg fault, fixed maybe
      // sprint_time(at, t, cmdparams_get_str(&cmdparams, "zone", NULL), 0);
      printf("%s\n", at);
   }
   else if (f == kTimeFormat_SDO)
   {
      /* no zone associated with sdo time, so zone parameter is ignored */
      printf("%12.*f\n", precision, t - sscan_time("1958.01.01_00:00:00_TAI"));
   }
   else if (f == kTimeFormat_EGSE)
   {
      /* no zone associated with egse time, so zone parameter is ignored */
      printf("%12.*f\n", precision, t - SEC1970TO2004 - sscan_time("1970.01.01_00:00_UTC"));
   }
   else if (f == kTimeFormat_Ordinal)
   {
      /* This does NOT provide a fractional day - any fractional part is discarded. */
      int ordTimeDays = 0;
      char zoneStr[32];
      char at[128];
      TIME jan1 = 0;
      TIME secsSinceJan1 = 0;

      char *zone =  cmdparams_get_str(&cmdparams, "zone", NULL);
      
      /* First, get internal time for January 1 of the year we are going to output. */
      sprint_time(at, t, zone, precision);
      char *tz = strrchr(at, '_');

      if (tz)
      {
	 snprintf(zoneStr, sizeof(zoneStr), "_%s", tz + 1);
      }

      char *dot = strchr(at, '.');
      if (dot != NULL)
      {
	 *dot = '\0';
	 char timeStr[64];
	 snprintf(timeStr, sizeof(timeStr), "%s.01.01_00:00:00%s", at, zoneStr);
	 jan1 = sscan_time(timeStr);
      }
      
      secsSinceJan1 = t - jan1;

      /* Now, get zone adjustment for jan1 and t.  Subtract Adj(t) - Adj(jan1) from 
       * secsSinceJan1. */
      TIME adjJan1 = ZoneAdjustment(jan1, zone, precision);
      TIME adjT = ZoneAdjustment(t, zone, precision);
      TIME ordTimeSecs = secsSinceJan1 - (adjT - adjJan1);

      /* Divide by TAI secs per day (86400). */
      ordTimeDays = 1 + ordTimeSecs / SECSPERDAY;      

      /* Output */
      printf("%s.%03d%s\n", at, ordTimeDays, zoneStr);
   }
   else
   {
      if (f != kTimeFormat_Internal)
      {
         // format error
         fprintf(stderr, "Invalid output format, defaulting to JSOC time.\n");
      }
         printf("%0.*f\n", precision, t);
   }
}

/* <t> is the TAI-seconds equivalent of a time in the <zone> time zone. */
TIME ZoneAdjustment(TIME t, char *zone, int precision)
{
   char timestr[128];
   sprint_time(timestr, t, zone, precision);

   char *tz = strrchr(timestr, '_');
   tz[1] = 'T';
   tz[2] = 'A';
   tz[3] = 'I';
   tz[4] = '\0';
   
   TIME taiDateSecs = sscan_time(timestr);
   return t - taiDateSecs;
}

Karen Tian
Powered by
ViewCVS 0.9.4