Index: /trunk/psLib/src/astro/psTime.c
===================================================================
--- /trunk/psLib/src/astro/psTime.c	(revision 1246)
+++ /trunk/psLib/src/astro/psTime.c	(revision 1247)
@@ -12,6 +12,6 @@
  *  @author Ross Harman, MHPCC
  *
- *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-07-15 19:02:13 $
+ *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-07-21 01:29:33 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -24,7 +24,11 @@
 
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
 #include "psTime.h"
 #include "psError.h"
+#define PS_ALLOW_MALLOC
+#include "psMemory.h"
 
 /******************************************************************************/
@@ -32,6 +36,20 @@
 /******************************************************************************/
 
-// Number of available leapsecond updates
-#define NUM_LEAPSECOND_UPDATES 23
+/** Preprocessor macro to generate error for negative time in struct */
+#define CHECK_NEGATIVE_TIME_STRUCT(NAME,RETURN)                                                              \
+if(NAME.tv_sec < 0) {                                                                                        \
+    psError(__func__,"Negative seconds are not allowed: %ld", NAME.tv_sec);                                  \
+    return RETURN;                                                                                           \
+} else if(NAME.tv_usec<0) {                                                                                  \
+    psError(__func__,"Negative microseconds are not allowed: %ld", NAME.tv_usec);                            \
+    return RETURN;                                                                                           \
+}
+
+/** Preprocessor macro to generate error for negative time */
+#define CHECK_NEGATIVE_TIME(NAME,RETURN)                                                                     \
+if(NAME < 0.0) {                                                                                             \
+    psError(__func__,"Negative time is not allowed: %f", NAME);                                              \
+    return RETURN;                                                                                           \
+}                                                                                                            \
 
 /******************************************************************************/
@@ -55,30 +73,30 @@
 the psTimeGetTime() function to calculate TAI time from  UTC time.
  
- 1972 JAN  1 =JD 2441317.5  TAI-UTC=  10.0
- 1972 JUL  1 =JD 2441499.5  TAI-UTC=  11.0
- 1973 JAN  1 =JD 2441683.5  TAI-UTC=  12.0
- 1974 JAN  1 =JD 2442048.5  TAI-UTC=  13.0
- 1975 JAN  1 =JD 2442413.5  TAI-UTC=  14.0
- 1976 JAN  1 =JD 2442778.5  TAI-UTC=  15.0
- 1977 JAN  1 =JD 2443144.5  TAI-UTC=  16.0
- 1978 JAN  1 =JD 2443509.5  TAI-UTC=  17.0
- 1979 JAN  1 =JD 2443874.5  TAI-UTC=  18.0
- 1980 JAN  1 =JD 2444239.5  TAI-UTC=  19.0
- 1981 JUL  1 =JD 2444786.5  TAI-UTC=  20.0
- 1982 JUL  1 =JD 2445151.5  TAI-UTC=  21.0
- 1983 JUL  1 =JD 2445516.5  TAI-UTC=  22.0
- 1985 JUL  1 =JD 2446247.5  TAI-UTC=  23.0
- 1988 JAN  1 =JD 2447161.5  TAI-UTC=  24.0
- 1990 JAN  1 =JD 2447892.5  TAI-UTC=  25.0
- 1991 JAN  1 =JD 2448257.5  TAI-UTC=  26.0
- 1992 JUL  1 =JD 2448804.5  TAI-UTC=  27.0
- 1993 JUL  1 =JD 2449169.5  TAI-UTC=  28.0
- 1994 JUL  1 =JD 2449534.5  TAI-UTC=  29.0
- 1996 JAN  1 =JD 2450083.5  TAI-UTC=  30.0
- 1997 JUL  1 =JD 2450630.5  TAI-UTC=  31.0
- 1999 JAN  1 =JD 2451179.5  TAI-UTC=  32.0
+ 1972 JAN 1 = JD 2441317.5  TAI-UTC = 10.0
+ 1972 JUL 1 = JD 2441499.5  TAI-UTC = 11.0
+ 1973 JAN 1 = JD 2441683.5  TAI-UTC = 12.0
+ 1974 JAN 1 = JD 2442048.5  TAI-UTC = 13.0
+ 1975 JAN 1 = JD 2442413.5  TAI-UTC = 14.0
+ 1976 JAN 1 = JD 2442778.5  TAI-UTC = 15.0
+ 1977 JAN 1 = JD 2443144.5  TAI-UTC = 16.0
+ 1978 JAN 1 = JD 2443509.5  TAI-UTC = 17.0
+ 1979 JAN 1 = JD 2443874.5  TAI-UTC = 18.0
+ 1980 JAN 1 = JD 2444239.5  TAI-UTC = 19.0
+ 1981 JUL 1 = JD 2444786.5  TAI-UTC = 20.0
+ 1982 JUL 1 = JD 2445151.5  TAI-UTC = 21.0
+ 1983 JUL 1 = JD 2445516.5  TAI-UTC = 22.0
+ 1985 JUL 1 = JD 2446247.5  TAI-UTC = 23.0
+ 1988 JAN 1 = JD 2447161.5  TAI-UTC = 24.0
+ 1990 JAN 1 = JD 2447892.5  TAI-UTC = 25.0
+ 1991 JAN 1 = JD 2448257.5  TAI-UTC = 26.0
+ 1992 JUL 1 = JD 2448804.5  TAI-UTC = 27.0
+ 1993 JUL 1 = JD 2449169.5  TAI-UTC = 28.0
+ 1994 JUL 1 = JD 2449534.5  TAI-UTC = 29.0
+ 1996 JAN 1 = JD 2450083.5  TAI-UTC = 30.0
+ 1997 JUL 1 = JD 2450630.5  TAI-UTC = 31.0
+ 1999 JAN 1 = JD 2451179.5  TAI-UTC = 32.0
 */
 
-// Julian date of leapsecond update and current total number of leapseconds for that date
+// Table for Julian date of leapsecond update and current total number of leapseconds at that date
 static double leapseconds[NUM_LEAPSECOND_UPDATES][2] =
     {
@@ -135,5 +153,5 @@
     time.tv_usec = now.tv_usec;
 
-    // Add last known leapseconds to UTC time to get TAI time
+    // Add most current leapseconds value to UTC time to get TAI time
     time.tv_sec += leapseconds[NUM_LEAPSECOND_UPDATES][1];
 
@@ -143,7 +161,297 @@
 char* psTimeToISO(psTime time)
 {
-    struct tm *tm;
-    tm = localtime (&time.tv_sec);
-    printf("%d\n", tm->tm_sec);
-    return NULL;
-}
+    int ms = 0;
+    char *timeString = NULL;
+    char *tempString = NULL;
+    struct tm *tmTime = NULL;
+
+    CHECK_NEGATIVE_TIME_STRUCT(time,NULL);
+
+    tempString = psAlloc(MAX_TIME_STRING_LENGTH);
+    timeString = psAlloc(MAX_TIME_STRING_LENGTH);
+
+    // Converts psTime to YYYY/MM/DD,HH:MM:SS.SSS in string form
+    ms = time.tv_usec/1000;
+    tmTime = gmtime(&time.tv_sec);
+    if(!strftime(tempString, MAX_TIME_STRING_LENGTH, "%Y/%m/%d,%H:%M:%S", tmTime)) {
+        psError(__func__, " : Line %d - Failed strftime conversion", __LINE__);
+    }
+
+    if(snprintf(timeString,MAX_TIME_STRING_LENGTH,"%s.%3.3d", tempString, ms) < 0) {
+        psError(__func__, " : Line %d - Failed snprintf conversion", __LINE__);
+    }
+    psFree(tempString);
+    free(tmTime);
+
+    return timeString;
+}
+
+psTime psTimeToUTC(psTime time)
+{
+    int i = 0;
+    double jd = 0.0;
+    double ls = 0.0;
+    double *jdTable = NULL;
+    psTime outTime;
+
+    CHECK_NEGATIVE_TIME_STRUCT(time,outTime);
+
+    // Find leapseconds to subtract from psTime to get UTC time
+    jd = psTimeToJD(time);
+    jdTable = leapseconds[0];
+    for(i=0; i<NUM_LEAPSECOND_UPDATES; i++, jdTable+=2) {
+        if(jd > *jdTable) {
+            ls = *(jdTable + 1);
+        }
+    }
+
+    outTime.tv_sec = time.tv_sec - ls;
+    outTime.tv_usec = time.tv_usec;
+
+    CHECK_NEGATIVE_TIME_STRUCT(outTime,outTime);
+
+    return outTime;
+}
+
+double psTimeToMJD(psTime time)
+{
+    double mjd = 0.0;
+
+    CHECK_NEGATIVE_TIME_STRUCT(time,mjd);
+
+    // Modified Julian date conversion courtesy of Eugene Magnier
+    mjd = time.tv_sec/SEC_PER_DAY + time.tv_usec/USEC_PER_DAY + 40587.0;
+
+    return mjd;
+}
+
+double psTimeToJD(psTime time)
+{
+    double jd = 0.0;
+
+    CHECK_NEGATIVE_TIME_STRUCT(time,jd);
+
+    // Julian date conversion courtesy of Eugene Magnier
+    jd = time.tv_sec/SEC_PER_DAY + time.tv_usec/USEC_PER_DAY + 2440587.5;
+
+    return jd;
+}
+
+struct timeval psTimeToTimeval(psTime time)
+{
+    struct timeval timevalTime;
+
+    CHECK_NEGATIVE_TIME_STRUCT(time,timevalTime);
+    timevalTime.tv_sec = time.tv_sec;
+    timevalTime.tv_usec = time.tv_usec;
+
+    return timevalTime;
+}
+
+struct tm* psTimeToTM(psTime time)
+{
+    struct tm *tmTime = NULL;
+
+    CHECK_NEGATIVE_TIME_STRUCT(time,tmTime);
+    tmTime = gmtime(&time.tv_sec);
+
+    return tmTime;
+}
+
+psTime psISOToTime(char *time)
+{
+    char tempString[MAX_TIME_STRING_LENGTH];
+    int month;
+    int day;
+    int year;
+    int hour;
+    int minute;
+    int second;
+    int millisecond;
+    struct tm tmTime;
+    psTime outTime;
+
+    strncpy(tempString, time, MAX_TIME_STRING_LENGTH);
+
+    // Convert YYYY/MM/DD,HH:MM:SS.SSS in string form to tm time
+    year = atoi(strtok(tempString, "/"));
+    if(year < 0) {
+        psError(__func__,"Years less than 1900 not allowed. Value: %d", year);
+    }
+
+    month = atoi(strtok(tempString, "/"));
+    if(month<1 || month>12) {
+        psError(__func__,"Month must have a value from 0 to 11. Value: %d", month);
+    }
+
+    day = atoi(strtok(tempString, ","));
+    if(day<1 || day>31) {
+        psError(__func__,"Day must have a value from 1 to 31. Value: %d", day);
+    }
+
+    hour = atoi(strtok(tempString, ":"));
+    if(hour<0 || hour>23) {
+        psError(__func__,"Hour must have a value from 0 to 23. Value: %d", hour);
+    }
+
+    second = atoi(strtok(tempString, "."));
+    if(second<0 || second>60) {
+        psError(__func__,"Second must have a value from 0 to 59. Value: %d", second);
+    }
+
+    millisecond = atoi(strtok(tempString, "X"));
+    if(millisecond<0 || millisecond>1000) {
+        psError(__func__,"Second must have a value from 0 to 999. Value: %d", millisecond);
+    }
+
+    tmTime.tm_year = year - 1900;
+    tmTime.tm_mon = month - 1;
+    tmTime.tm_mday = day;
+    tmTime.tm_hour = hour;
+    tmTime.tm_min = minute;
+    tmTime.tm_sec = second;
+
+    // Convert tm time to psTime
+    outTime = psTMToTime(&tmTime);
+    outTime.tv_usec = millisecond*1000;
+
+    return outTime;
+}
+
+psTime psUTCToTime(psTime time)
+{
+    psTime outTime;
+
+    CHECK_NEGATIVE_TIME_STRUCT(time,outTime);
+
+    // Convert UTC time to psTime/TAI
+    outTime.tv_sec = time.tv_sec + leapseconds[NUM_LEAPSECOND_UPDATES][1];
+    ;
+    outTime.tv_usec = time.tv_usec;
+    CHECK_NEGATIVE_TIME_STRUCT(outTime,outTime);
+
+    return time;
+}
+
+psTime psMJDToTime(double time)
+{
+    psTime outTime;
+    double days = 0.0;
+    double seconds = 0.0;
+
+    CHECK_NEGATIVE_TIME(time,outTime);
+
+    // Modified Julian date conversion courtesy of Eugene Magnier
+    days = time - 40587.0;
+
+    // Convert to psTime/TAI
+    seconds = days*SEC_PER_DAY;
+    outTime.tv_usec = (seconds -(long)seconds)*1000000.0;
+    outTime.tv_sec = seconds;
+
+    CHECK_NEGATIVE_TIME_STRUCT(outTime,outTime);
+
+    return outTime;
+}
+
+psTime psJDToTime(double time)
+{
+    double days = 0.0;
+    double seconds = 0.0;
+    psTime outTime;
+
+    CHECK_NEGATIVE_TIME(time,outTime);
+
+    // Julian date conversion courtesy of Eugene Magnier
+    days = time - 2440587.5;
+
+    // Convert to psTime/TAI
+    seconds = days*SEC_PER_DAY;
+    outTime.tv_sec = seconds;
+    outTime.tv_usec = (seconds -(long)seconds)*1000000.0;
+
+    CHECK_NEGATIVE_TIME_STRUCT(outTime,outTime);
+
+    return outTime;
+}
+
+psTime psTimevalToTime(struct timeval *time)
+{
+    psTime outTime;
+    if(time == NULL)
+    {
+        psError(__func__,"Null value for timeval arg not allowed");
+        return outTime;
+    } else if(time->tv_sec < 0)
+    {
+        psError(__func__,"Negative seconds are not allowed: %ld", time->tv_sec);
+        return outTime;
+    } else if(time->tv_usec<0)
+    {
+        psError(__func__,"Negative microseconds are not allowed: %ld", time->tv_usec);
+        return outTime;
+    }
+
+    // Convert to psTime/TAI
+    outTime.tv_sec = time->tv_sec;
+    outTime.tv_usec = time->tv_usec;
+
+    CHECK_NEGATIVE_TIME_STRUCT(outTime,outTime);
+
+    return outTime;
+}
+
+
+psTime psTMToTime(struct tm *time)
+{
+    int i;
+    int m;
+    int n;
+    int y;
+    int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+    long epoch;
+    psTime outTime;
+
+    i= 0;
+    m = 0;
+    n = 0;
+    y = 0;
+    epoch = 0;
+
+    if(time == NULL)
+    {
+        psError(__func__,"Null value for tm arg not allowed");
+        return outTime;
+    } else if(time->tm_year < 70)
+    {
+        psError(__func__,"Input times earlier than 1970 not allowed");
+        return outTime;
+    }
+
+    n = time->tm_year + 1900 - 1;
+    epoch = (time->tm_year - 70) * SEC_PER_YEAR + ((n/4 - n/100 + n/400) -
+            (1969/4 - 1969/100 + 1969/400)) * SEC_PER_DAY;
+
+    y = time->tm_year + 1900;
+
+    for(i = 0; i < time->tm_mon; i++)
+    {
+        epoch += mon [m] * SEC_PER_DAY;
+        if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) {
+            epoch += SEC_PER_DAY;
+        }
+
+        if(++m > 11) {
+            m = 0;
+            y++;
+        }
+    }
+
+    epoch += (time->tm_mday - 1) * SEC_PER_DAY;
+    epoch += time->tm_hour *SEC_PER_HOUR + time->tm_min * SEC_PER_MINUTE + time->tm_sec;
+
+    outTime.tv_usec = 0;
+    outTime.tv_sec = epoch;
+
+    return outTime;
+}
Index: /trunk/psLib/src/astro/psTime.h
===================================================================
--- /trunk/psLib/src/astro/psTime.h	(revision 1246)
+++ /trunk/psLib/src/astro/psTime.h	(revision 1247)
@@ -12,6 +12,6 @@
  *  @author Ross Harman, MHPCC
  *
- *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-07-15 19:02:13 $
+ *  @version $Revision: 1.4 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-07-21 01:29:22 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -29,4 +29,29 @@
 /// @addtogroup Time
 /// @{
+
+/******************************************************************************/
+/*  DEFINE STATEMENTS                                                         */
+/******************************************************************************/
+
+/** Number of available leapsecond updates */
+#define NUM_LEAPSECOND_UPDATES 23
+
+/** Maximum length of time string */
+#define MAX_TIME_STRING_LENGTH 256
+
+/** Seconds per minute */
+#define  SEC_PER_MINUTE   60
+
+/** Seconds per hour */
+#define  SEC_PER_HOUR     60*SEC_PER_MINUTE
+
+/** Seconds per day */
+#define  SEC_PER_DAY      24*SEC_PER_HOUR
+
+/** Seconds per year */
+#define  SEC_PER_YEAR    365*SEC_PER_DAY
+
+/** Microseconds per day */
+#define USEC_PER_DAY 86400000000.0
 
 /******************************************************************************/
@@ -63,8 +88,8 @@
 /** Convert psTime to ISO time in TAI units.
  *
- * Converts psTime to a null terminated string in the form of: YYYY/MM/DD,HH:MM:SS.SSS. The result from this
- * function is in TAI units.
- *
- *  @return  char*: Pointer null terminated array of chars in ISO/TAI time.
+ * Converts psTime to a null terminated string in the form of: YYYY/MM/DD,HH:MM:SS.SSS. This function assumes
+ * the input time already is in TAI time and does not add or subtract leapseconds.
+ *
+ *  @return  char*: Pointer null terminated array of chars in ISO time.
  */
 char* psTimeToISO(
@@ -74,10 +99,11 @@
 /** Convert psTime to UTC time.
  *
- * Converts psTime to UTC time in double precision floating point notation. The result from this function is
- * not in TAI units, but that of UTC, which does not contain leapseconds.
- *
- *  @return  double: UTC time in floating point notation.
- */
-double psTimeToUTC(
+ * Converts psTime to UTC time in double precision floating point notation. The input to this must already be
+ * int TAI time. The result from this function is not in TAI units, but that of UTC, which does not contain
+ * leapseconds.
+ *
+ *  @return  psTime: UTC time psTime format.
+ */
+psTime psTimeToUTC(
     psTime time    /** Input time to be converted. */
 );
@@ -85,7 +111,8 @@
 /** Convert psTime to modified Julian date time.
  *
- * Converts psTime to modified Julian date (MJD) time. The result from this function is in TAI units.
- *
- *  @return  double: MJD/TAI time in floating point notation.
+ * Converts psTime to modified Julian date (MJD) time. This function assumes the input time already is in TAI
+ * time and does not add or subtract leapseconds.
+ *
+ *  @return  double: Modified Julian Days (MJD) time.
  */
 double psTimeToMJD(
@@ -95,7 +122,8 @@
 /** Convert psTime to Julian date time.
  *
- * Converts psTime to Julian date (JD) time. The result from this function is in TAI units.
- *
- *  @return  double: JD/TAI time in floating point notation.
+ * Converts psTime to Julian date (JD) time. This function assumes the input time already is in TAI time and
+ * does not add or subtract leapseconds.
+ *
+ *  @return  double: Julian Date (JD) time.
  */
 double psTimeToJD(
@@ -105,7 +133,8 @@
 /** Convert psTime to timeval time.
  *
- * Converts psTime to timeval time. The result from this function is in TAI units.
- *
- *  @return  timeval: timeval/TAI time.
+ * Converts psTime to timeval time. This function assumes the input time already is in TAI time and does not
+ * add or subtract leapseconds.
+ *
+ *  @return  timeval: timeval struct time.
  */
 struct timeval psTimeToTimeval(
@@ -115,7 +144,8 @@
 /** Convert psTime to tm time.
  *
- * Converts psTime to tm time. The result from this function is in TAI units.
- *
- *  @return  tm: tm/TAI time.
+ * Converts psTime to tm time. This function assumes the input time already is in TAI time and does not add or
+ * subtract leapseconds.
+ *
+ *  @return  tm: tm struct time.
  */
 struct tm* psTimeToTM(
@@ -125,49 +155,67 @@
 /** Convert ISO to psTime.
  *
- * Converts ISO time to psTime. The result from this function is in TAI units.
+ * Converts ISO time to psTime. This function assumes the input time already is in TAI time and does not add
+ * or subtract leapseconds.
+ *
+ *  @return  psTime: time
+ */
+psTime psISOToTime(
+    char *time  /** Input time to be converted. */
+);
+
+/** Convert UTC to psTime.
+ *
+ * Converts UTC time to psTime. This function assumes the input time already is in TAI time and add or
+ * subtracts the necessary leapseconds.
  *
  *  @return  psTime: time in TAI units.
  */
-psTime psISOToTime(char *time);
-
-/** Convert UTC to psTime.
- *
- * Converts UTC time to psTime. The result from this function is in TAI units.
- *
- *  @return  psTime: time in TAI units.
- */
-psTime psUTCToTime(double time);
+psTime psUTCToTime(
+    psTime time /** Input time to be converted. */
+);
 
 /** Convert MJD to psTime.
  *
- * Converts MJD time to psTime. The result from this function is in TAI units.
- *
- *  @return  psTime: time in TAI units.
- */
-psTime psMJDToTime(double time);
+ * Converts MJD time to psTime. This function assumes the input time already is in TAI time and does not add
+ * or subtract leapseconds.
+ *
+ *  @return  psTime: time.
+ */
+psTime psMJDToTime(
+    double time /** Input time to be converted. */
+);
 
 /** Convert JD to psTime.
  *
- * Converts JD time to psTime. The result from this function is in TAI units.
- *
- *  @return  psTime: time in TAI units.
- */
-psTime psJDToTime(double time);
+ * Converts JD time to psTime. This function assumes the input time already is in TAI time and does not add
+ * or subtract leapseconds.
+ *
+ *  @return  psTime: time.
+ */
+psTime psJDToTime(
+    double time /** Input time to be converted. */
+);
 
 /** Convert timeval to psTime.
  *
- * Converts timeval time to psTime. The result from this function is in TAI units.
- *
- *  @return  psTime: time in TAI units.
- */
-psTime psTimevalToTime(struct timeval *time);
+ * Converts timeval time to psTime. This function assumes the input time already is in TAI time and does not
+ * add or subtract leapseconds.
+ *
+ *  @return  psTime: time.
+ */
+psTime psTimevalToTime(
+    struct timeval *time    /** Input time to be converted. */
+);
 
 /** Convert tm time to psTime.
  *
- * Converts tm time to psTime. The result from this function is in TAI units.
- *
- *  @return  psTime: time in TAI units.
- */
-psTime psTMToTime(struct tm *time);
+ * Converts tm time to psTime. This function assumes the input time already is in TAI time and does not add
+ * or subtract leapseconds.
+ *
+ *  @return  psTime: time.
+ */
+psTime psTMToTime(
+    struct tm *time /** Input time to be converted. */
+);
 /// @}
 
Index: /trunk/psLib/src/astronomy/psTime.c
===================================================================
--- /trunk/psLib/src/astronomy/psTime.c	(revision 1246)
+++ /trunk/psLib/src/astronomy/psTime.c	(revision 1247)
@@ -12,6 +12,6 @@
  *  @author Ross Harman, MHPCC
  *
- *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-07-15 19:02:13 $
+ *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-07-21 01:29:33 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -24,7 +24,11 @@
 
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
 #include "psTime.h"
 #include "psError.h"
+#define PS_ALLOW_MALLOC
+#include "psMemory.h"
 
 /******************************************************************************/
@@ -32,6 +36,20 @@
 /******************************************************************************/
 
-// Number of available leapsecond updates
-#define NUM_LEAPSECOND_UPDATES 23
+/** Preprocessor macro to generate error for negative time in struct */
+#define CHECK_NEGATIVE_TIME_STRUCT(NAME,RETURN)                                                              \
+if(NAME.tv_sec < 0) {                                                                                        \
+    psError(__func__,"Negative seconds are not allowed: %ld", NAME.tv_sec);                                  \
+    return RETURN;                                                                                           \
+} else if(NAME.tv_usec<0) {                                                                                  \
+    psError(__func__,"Negative microseconds are not allowed: %ld", NAME.tv_usec);                            \
+    return RETURN;                                                                                           \
+}
+
+/** Preprocessor macro to generate error for negative time */
+#define CHECK_NEGATIVE_TIME(NAME,RETURN)                                                                     \
+if(NAME < 0.0) {                                                                                             \
+    psError(__func__,"Negative time is not allowed: %f", NAME);                                              \
+    return RETURN;                                                                                           \
+}                                                                                                            \
 
 /******************************************************************************/
@@ -55,30 +73,30 @@
 the psTimeGetTime() function to calculate TAI time from  UTC time.
  
- 1972 JAN  1 =JD 2441317.5  TAI-UTC=  10.0
- 1972 JUL  1 =JD 2441499.5  TAI-UTC=  11.0
- 1973 JAN  1 =JD 2441683.5  TAI-UTC=  12.0
- 1974 JAN  1 =JD 2442048.5  TAI-UTC=  13.0
- 1975 JAN  1 =JD 2442413.5  TAI-UTC=  14.0
- 1976 JAN  1 =JD 2442778.5  TAI-UTC=  15.0
- 1977 JAN  1 =JD 2443144.5  TAI-UTC=  16.0
- 1978 JAN  1 =JD 2443509.5  TAI-UTC=  17.0
- 1979 JAN  1 =JD 2443874.5  TAI-UTC=  18.0
- 1980 JAN  1 =JD 2444239.5  TAI-UTC=  19.0
- 1981 JUL  1 =JD 2444786.5  TAI-UTC=  20.0
- 1982 JUL  1 =JD 2445151.5  TAI-UTC=  21.0
- 1983 JUL  1 =JD 2445516.5  TAI-UTC=  22.0
- 1985 JUL  1 =JD 2446247.5  TAI-UTC=  23.0
- 1988 JAN  1 =JD 2447161.5  TAI-UTC=  24.0
- 1990 JAN  1 =JD 2447892.5  TAI-UTC=  25.0
- 1991 JAN  1 =JD 2448257.5  TAI-UTC=  26.0
- 1992 JUL  1 =JD 2448804.5  TAI-UTC=  27.0
- 1993 JUL  1 =JD 2449169.5  TAI-UTC=  28.0
- 1994 JUL  1 =JD 2449534.5  TAI-UTC=  29.0
- 1996 JAN  1 =JD 2450083.5  TAI-UTC=  30.0
- 1997 JUL  1 =JD 2450630.5  TAI-UTC=  31.0
- 1999 JAN  1 =JD 2451179.5  TAI-UTC=  32.0
+ 1972 JAN 1 = JD 2441317.5  TAI-UTC = 10.0
+ 1972 JUL 1 = JD 2441499.5  TAI-UTC = 11.0
+ 1973 JAN 1 = JD 2441683.5  TAI-UTC = 12.0
+ 1974 JAN 1 = JD 2442048.5  TAI-UTC = 13.0
+ 1975 JAN 1 = JD 2442413.5  TAI-UTC = 14.0
+ 1976 JAN 1 = JD 2442778.5  TAI-UTC = 15.0
+ 1977 JAN 1 = JD 2443144.5  TAI-UTC = 16.0
+ 1978 JAN 1 = JD 2443509.5  TAI-UTC = 17.0
+ 1979 JAN 1 = JD 2443874.5  TAI-UTC = 18.0
+ 1980 JAN 1 = JD 2444239.5  TAI-UTC = 19.0
+ 1981 JUL 1 = JD 2444786.5  TAI-UTC = 20.0
+ 1982 JUL 1 = JD 2445151.5  TAI-UTC = 21.0
+ 1983 JUL 1 = JD 2445516.5  TAI-UTC = 22.0
+ 1985 JUL 1 = JD 2446247.5  TAI-UTC = 23.0
+ 1988 JAN 1 = JD 2447161.5  TAI-UTC = 24.0
+ 1990 JAN 1 = JD 2447892.5  TAI-UTC = 25.0
+ 1991 JAN 1 = JD 2448257.5  TAI-UTC = 26.0
+ 1992 JUL 1 = JD 2448804.5  TAI-UTC = 27.0
+ 1993 JUL 1 = JD 2449169.5  TAI-UTC = 28.0
+ 1994 JUL 1 = JD 2449534.5  TAI-UTC = 29.0
+ 1996 JAN 1 = JD 2450083.5  TAI-UTC = 30.0
+ 1997 JUL 1 = JD 2450630.5  TAI-UTC = 31.0
+ 1999 JAN 1 = JD 2451179.5  TAI-UTC = 32.0
 */
 
-// Julian date of leapsecond update and current total number of leapseconds for that date
+// Table for Julian date of leapsecond update and current total number of leapseconds at that date
 static double leapseconds[NUM_LEAPSECOND_UPDATES][2] =
     {
@@ -135,5 +153,5 @@
     time.tv_usec = now.tv_usec;
 
-    // Add last known leapseconds to UTC time to get TAI time
+    // Add most current leapseconds value to UTC time to get TAI time
     time.tv_sec += leapseconds[NUM_LEAPSECOND_UPDATES][1];
 
@@ -143,7 +161,297 @@
 char* psTimeToISO(psTime time)
 {
-    struct tm *tm;
-    tm = localtime (&time.tv_sec);
-    printf("%d\n", tm->tm_sec);
-    return NULL;
-}
+    int ms = 0;
+    char *timeString = NULL;
+    char *tempString = NULL;
+    struct tm *tmTime = NULL;
+
+    CHECK_NEGATIVE_TIME_STRUCT(time,NULL);
+
+    tempString = psAlloc(MAX_TIME_STRING_LENGTH);
+    timeString = psAlloc(MAX_TIME_STRING_LENGTH);
+
+    // Converts psTime to YYYY/MM/DD,HH:MM:SS.SSS in string form
+    ms = time.tv_usec/1000;
+    tmTime = gmtime(&time.tv_sec);
+    if(!strftime(tempString, MAX_TIME_STRING_LENGTH, "%Y/%m/%d,%H:%M:%S", tmTime)) {
+        psError(__func__, " : Line %d - Failed strftime conversion", __LINE__);
+    }
+
+    if(snprintf(timeString,MAX_TIME_STRING_LENGTH,"%s.%3.3d", tempString, ms) < 0) {
+        psError(__func__, " : Line %d - Failed snprintf conversion", __LINE__);
+    }
+    psFree(tempString);
+    free(tmTime);
+
+    return timeString;
+}
+
+psTime psTimeToUTC(psTime time)
+{
+    int i = 0;
+    double jd = 0.0;
+    double ls = 0.0;
+    double *jdTable = NULL;
+    psTime outTime;
+
+    CHECK_NEGATIVE_TIME_STRUCT(time,outTime);
+
+    // Find leapseconds to subtract from psTime to get UTC time
+    jd = psTimeToJD(time);
+    jdTable = leapseconds[0];
+    for(i=0; i<NUM_LEAPSECOND_UPDATES; i++, jdTable+=2) {
+        if(jd > *jdTable) {
+            ls = *(jdTable + 1);
+        }
+    }
+
+    outTime.tv_sec = time.tv_sec - ls;
+    outTime.tv_usec = time.tv_usec;
+
+    CHECK_NEGATIVE_TIME_STRUCT(outTime,outTime);
+
+    return outTime;
+}
+
+double psTimeToMJD(psTime time)
+{
+    double mjd = 0.0;
+
+    CHECK_NEGATIVE_TIME_STRUCT(time,mjd);
+
+    // Modified Julian date conversion courtesy of Eugene Magnier
+    mjd = time.tv_sec/SEC_PER_DAY + time.tv_usec/USEC_PER_DAY + 40587.0;
+
+    return mjd;
+}
+
+double psTimeToJD(psTime time)
+{
+    double jd = 0.0;
+
+    CHECK_NEGATIVE_TIME_STRUCT(time,jd);
+
+    // Julian date conversion courtesy of Eugene Magnier
+    jd = time.tv_sec/SEC_PER_DAY + time.tv_usec/USEC_PER_DAY + 2440587.5;
+
+    return jd;
+}
+
+struct timeval psTimeToTimeval(psTime time)
+{
+    struct timeval timevalTime;
+
+    CHECK_NEGATIVE_TIME_STRUCT(time,timevalTime);
+    timevalTime.tv_sec = time.tv_sec;
+    timevalTime.tv_usec = time.tv_usec;
+
+    return timevalTime;
+}
+
+struct tm* psTimeToTM(psTime time)
+{
+    struct tm *tmTime = NULL;
+
+    CHECK_NEGATIVE_TIME_STRUCT(time,tmTime);
+    tmTime = gmtime(&time.tv_sec);
+
+    return tmTime;
+}
+
+psTime psISOToTime(char *time)
+{
+    char tempString[MAX_TIME_STRING_LENGTH];
+    int month;
+    int day;
+    int year;
+    int hour;
+    int minute;
+    int second;
+    int millisecond;
+    struct tm tmTime;
+    psTime outTime;
+
+    strncpy(tempString, time, MAX_TIME_STRING_LENGTH);
+
+    // Convert YYYY/MM/DD,HH:MM:SS.SSS in string form to tm time
+    year = atoi(strtok(tempString, "/"));
+    if(year < 0) {
+        psError(__func__,"Years less than 1900 not allowed. Value: %d", year);
+    }
+
+    month = atoi(strtok(tempString, "/"));
+    if(month<1 || month>12) {
+        psError(__func__,"Month must have a value from 0 to 11. Value: %d", month);
+    }
+
+    day = atoi(strtok(tempString, ","));
+    if(day<1 || day>31) {
+        psError(__func__,"Day must have a value from 1 to 31. Value: %d", day);
+    }
+
+    hour = atoi(strtok(tempString, ":"));
+    if(hour<0 || hour>23) {
+        psError(__func__,"Hour must have a value from 0 to 23. Value: %d", hour);
+    }
+
+    second = atoi(strtok(tempString, "."));
+    if(second<0 || second>60) {
+        psError(__func__,"Second must have a value from 0 to 59. Value: %d", second);
+    }
+
+    millisecond = atoi(strtok(tempString, "X"));
+    if(millisecond<0 || millisecond>1000) {
+        psError(__func__,"Second must have a value from 0 to 999. Value: %d", millisecond);
+    }
+
+    tmTime.tm_year = year - 1900;
+    tmTime.tm_mon = month - 1;
+    tmTime.tm_mday = day;
+    tmTime.tm_hour = hour;
+    tmTime.tm_min = minute;
+    tmTime.tm_sec = second;
+
+    // Convert tm time to psTime
+    outTime = psTMToTime(&tmTime);
+    outTime.tv_usec = millisecond*1000;
+
+    return outTime;
+}
+
+psTime psUTCToTime(psTime time)
+{
+    psTime outTime;
+
+    CHECK_NEGATIVE_TIME_STRUCT(time,outTime);
+
+    // Convert UTC time to psTime/TAI
+    outTime.tv_sec = time.tv_sec + leapseconds[NUM_LEAPSECOND_UPDATES][1];
+    ;
+    outTime.tv_usec = time.tv_usec;
+    CHECK_NEGATIVE_TIME_STRUCT(outTime,outTime);
+
+    return time;
+}
+
+psTime psMJDToTime(double time)
+{
+    psTime outTime;
+    double days = 0.0;
+    double seconds = 0.0;
+
+    CHECK_NEGATIVE_TIME(time,outTime);
+
+    // Modified Julian date conversion courtesy of Eugene Magnier
+    days = time - 40587.0;
+
+    // Convert to psTime/TAI
+    seconds = days*SEC_PER_DAY;
+    outTime.tv_usec = (seconds -(long)seconds)*1000000.0;
+    outTime.tv_sec = seconds;
+
+    CHECK_NEGATIVE_TIME_STRUCT(outTime,outTime);
+
+    return outTime;
+}
+
+psTime psJDToTime(double time)
+{
+    double days = 0.0;
+    double seconds = 0.0;
+    psTime outTime;
+
+    CHECK_NEGATIVE_TIME(time,outTime);
+
+    // Julian date conversion courtesy of Eugene Magnier
+    days = time - 2440587.5;
+
+    // Convert to psTime/TAI
+    seconds = days*SEC_PER_DAY;
+    outTime.tv_sec = seconds;
+    outTime.tv_usec = (seconds -(long)seconds)*1000000.0;
+
+    CHECK_NEGATIVE_TIME_STRUCT(outTime,outTime);
+
+    return outTime;
+}
+
+psTime psTimevalToTime(struct timeval *time)
+{
+    psTime outTime;
+    if(time == NULL)
+    {
+        psError(__func__,"Null value for timeval arg not allowed");
+        return outTime;
+    } else if(time->tv_sec < 0)
+    {
+        psError(__func__,"Negative seconds are not allowed: %ld", time->tv_sec);
+        return outTime;
+    } else if(time->tv_usec<0)
+    {
+        psError(__func__,"Negative microseconds are not allowed: %ld", time->tv_usec);
+        return outTime;
+    }
+
+    // Convert to psTime/TAI
+    outTime.tv_sec = time->tv_sec;
+    outTime.tv_usec = time->tv_usec;
+
+    CHECK_NEGATIVE_TIME_STRUCT(outTime,outTime);
+
+    return outTime;
+}
+
+
+psTime psTMToTime(struct tm *time)
+{
+    int i;
+    int m;
+    int n;
+    int y;
+    int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+    long epoch;
+    psTime outTime;
+
+    i= 0;
+    m = 0;
+    n = 0;
+    y = 0;
+    epoch = 0;
+
+    if(time == NULL)
+    {
+        psError(__func__,"Null value for tm arg not allowed");
+        return outTime;
+    } else if(time->tm_year < 70)
+    {
+        psError(__func__,"Input times earlier than 1970 not allowed");
+        return outTime;
+    }
+
+    n = time->tm_year + 1900 - 1;
+    epoch = (time->tm_year - 70) * SEC_PER_YEAR + ((n/4 - n/100 + n/400) -
+            (1969/4 - 1969/100 + 1969/400)) * SEC_PER_DAY;
+
+    y = time->tm_year + 1900;
+
+    for(i = 0; i < time->tm_mon; i++)
+    {
+        epoch += mon [m] * SEC_PER_DAY;
+        if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) {
+            epoch += SEC_PER_DAY;
+        }
+
+        if(++m > 11) {
+            m = 0;
+            y++;
+        }
+    }
+
+    epoch += (time->tm_mday - 1) * SEC_PER_DAY;
+    epoch += time->tm_hour *SEC_PER_HOUR + time->tm_min * SEC_PER_MINUTE + time->tm_sec;
+
+    outTime.tv_usec = 0;
+    outTime.tv_sec = epoch;
+
+    return outTime;
+}
Index: /trunk/psLib/src/astronomy/psTime.h
===================================================================
--- /trunk/psLib/src/astronomy/psTime.h	(revision 1246)
+++ /trunk/psLib/src/astronomy/psTime.h	(revision 1247)
@@ -12,6 +12,6 @@
  *  @author Ross Harman, MHPCC
  *
- *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-07-15 19:02:13 $
+ *  @version $Revision: 1.4 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-07-21 01:29:22 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -29,4 +29,29 @@
 /// @addtogroup Time
 /// @{
+
+/******************************************************************************/
+/*  DEFINE STATEMENTS                                                         */
+/******************************************************************************/
+
+/** Number of available leapsecond updates */
+#define NUM_LEAPSECOND_UPDATES 23
+
+/** Maximum length of time string */
+#define MAX_TIME_STRING_LENGTH 256
+
+/** Seconds per minute */
+#define  SEC_PER_MINUTE   60
+
+/** Seconds per hour */
+#define  SEC_PER_HOUR     60*SEC_PER_MINUTE
+
+/** Seconds per day */
+#define  SEC_PER_DAY      24*SEC_PER_HOUR
+
+/** Seconds per year */
+#define  SEC_PER_YEAR    365*SEC_PER_DAY
+
+/** Microseconds per day */
+#define USEC_PER_DAY 86400000000.0
 
 /******************************************************************************/
@@ -63,8 +88,8 @@
 /** Convert psTime to ISO time in TAI units.
  *
- * Converts psTime to a null terminated string in the form of: YYYY/MM/DD,HH:MM:SS.SSS. The result from this
- * function is in TAI units.
- *
- *  @return  char*: Pointer null terminated array of chars in ISO/TAI time.
+ * Converts psTime to a null terminated string in the form of: YYYY/MM/DD,HH:MM:SS.SSS. This function assumes
+ * the input time already is in TAI time and does not add or subtract leapseconds.
+ *
+ *  @return  char*: Pointer null terminated array of chars in ISO time.
  */
 char* psTimeToISO(
@@ -74,10 +99,11 @@
 /** Convert psTime to UTC time.
  *
- * Converts psTime to UTC time in double precision floating point notation. The result from this function is
- * not in TAI units, but that of UTC, which does not contain leapseconds.
- *
- *  @return  double: UTC time in floating point notation.
- */
-double psTimeToUTC(
+ * Converts psTime to UTC time in double precision floating point notation. The input to this must already be
+ * int TAI time. The result from this function is not in TAI units, but that of UTC, which does not contain
+ * leapseconds.
+ *
+ *  @return  psTime: UTC time psTime format.
+ */
+psTime psTimeToUTC(
     psTime time    /** Input time to be converted. */
 );
@@ -85,7 +111,8 @@
 /** Convert psTime to modified Julian date time.
  *
- * Converts psTime to modified Julian date (MJD) time. The result from this function is in TAI units.
- *
- *  @return  double: MJD/TAI time in floating point notation.
+ * Converts psTime to modified Julian date (MJD) time. This function assumes the input time already is in TAI
+ * time and does not add or subtract leapseconds.
+ *
+ *  @return  double: Modified Julian Days (MJD) time.
  */
 double psTimeToMJD(
@@ -95,7 +122,8 @@
 /** Convert psTime to Julian date time.
  *
- * Converts psTime to Julian date (JD) time. The result from this function is in TAI units.
- *
- *  @return  double: JD/TAI time in floating point notation.
+ * Converts psTime to Julian date (JD) time. This function assumes the input time already is in TAI time and
+ * does not add or subtract leapseconds.
+ *
+ *  @return  double: Julian Date (JD) time.
  */
 double psTimeToJD(
@@ -105,7 +133,8 @@
 /** Convert psTime to timeval time.
  *
- * Converts psTime to timeval time. The result from this function is in TAI units.
- *
- *  @return  timeval: timeval/TAI time.
+ * Converts psTime to timeval time. This function assumes the input time already is in TAI time and does not
+ * add or subtract leapseconds.
+ *
+ *  @return  timeval: timeval struct time.
  */
 struct timeval psTimeToTimeval(
@@ -115,7 +144,8 @@
 /** Convert psTime to tm time.
  *
- * Converts psTime to tm time. The result from this function is in TAI units.
- *
- *  @return  tm: tm/TAI time.
+ * Converts psTime to tm time. This function assumes the input time already is in TAI time and does not add or
+ * subtract leapseconds.
+ *
+ *  @return  tm: tm struct time.
  */
 struct tm* psTimeToTM(
@@ -125,49 +155,67 @@
 /** Convert ISO to psTime.
  *
- * Converts ISO time to psTime. The result from this function is in TAI units.
+ * Converts ISO time to psTime. This function assumes the input time already is in TAI time and does not add
+ * or subtract leapseconds.
+ *
+ *  @return  psTime: time
+ */
+psTime psISOToTime(
+    char *time  /** Input time to be converted. */
+);
+
+/** Convert UTC to psTime.
+ *
+ * Converts UTC time to psTime. This function assumes the input time already is in TAI time and add or
+ * subtracts the necessary leapseconds.
  *
  *  @return  psTime: time in TAI units.
  */
-psTime psISOToTime(char *time);
-
-/** Convert UTC to psTime.
- *
- * Converts UTC time to psTime. The result from this function is in TAI units.
- *
- *  @return  psTime: time in TAI units.
- */
-psTime psUTCToTime(double time);
+psTime psUTCToTime(
+    psTime time /** Input time to be converted. */
+);
 
 /** Convert MJD to psTime.
  *
- * Converts MJD time to psTime. The result from this function is in TAI units.
- *
- *  @return  psTime: time in TAI units.
- */
-psTime psMJDToTime(double time);
+ * Converts MJD time to psTime. This function assumes the input time already is in TAI time and does not add
+ * or subtract leapseconds.
+ *
+ *  @return  psTime: time.
+ */
+psTime psMJDToTime(
+    double time /** Input time to be converted. */
+);
 
 /** Convert JD to psTime.
  *
- * Converts JD time to psTime. The result from this function is in TAI units.
- *
- *  @return  psTime: time in TAI units.
- */
-psTime psJDToTime(double time);
+ * Converts JD time to psTime. This function assumes the input time already is in TAI time and does not add
+ * or subtract leapseconds.
+ *
+ *  @return  psTime: time.
+ */
+psTime psJDToTime(
+    double time /** Input time to be converted. */
+);
 
 /** Convert timeval to psTime.
  *
- * Converts timeval time to psTime. The result from this function is in TAI units.
- *
- *  @return  psTime: time in TAI units.
- */
-psTime psTimevalToTime(struct timeval *time);
+ * Converts timeval time to psTime. This function assumes the input time already is in TAI time and does not
+ * add or subtract leapseconds.
+ *
+ *  @return  psTime: time.
+ */
+psTime psTimevalToTime(
+    struct timeval *time    /** Input time to be converted. */
+);
 
 /** Convert tm time to psTime.
  *
- * Converts tm time to psTime. The result from this function is in TAI units.
- *
- *  @return  psTime: time in TAI units.
- */
-psTime psTMToTime(struct tm *time);
+ * Converts tm time to psTime. This function assumes the input time already is in TAI time and does not add
+ * or subtract leapseconds.
+ *
+ *  @return  psTime: time.
+ */
+psTime psTMToTime(
+    struct tm *time /** Input time to be converted. */
+);
 /// @}
 
