Index: /trunk/psLib/src/astro/psTime.c
===================================================================
--- /trunk/psLib/src/astro/psTime.c	(revision 4050)
+++ /trunk/psLib/src/astro/psTime.c	(revision 4051)
@@ -10,6 +10,6 @@
  *  @author Ross Harman, MHPCC
  *
- *  @version $Revision: 1.61 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2005-05-25 20:26:55 $
+ *  @version $Revision: 1.62 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2005-05-31 21:47:46 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -24,4 +24,5 @@
 #include "psTime.h"
 #include "psError.h"
+#include "psLogMsg.h"
 #include "psMemory.h"
 #include "psAbort.h"
@@ -69,9 +70,30 @@
                 static psMetadata *timeMetadata = NULL;
 
+// Offset to convert terrestrial time(TT) to international atomic time(TAI)
+#define  TAI_TT_OFFSET_SECONDS        32
+#define  TAI_TT_OFFSET_NANOSECONDS    184000000
+
+// Offset from converting to MJD
+#define  MJD_EPOCH_OFFSET             40587.0
+
+// Offset for converting to JD
+#define  JD_EPOCH_OFFSET              2440587.5
+
+// Offset of year 0000 from epoch
+#define YEAR_0000_SEC                 -62125920000.0
+
+// Offset of year 9999 from epoch
+#define YEAR_9999_SEC                 253202544000.0
+
 /** Static function prototypes */
 static char *cleanString(char *inString, int sLen);
 static char* getToken(char **inString, char *delimiter, psParseErrorType *status);
-psF64 searchTables(psF64 index, psU64 column, psLookupStatusType *status, char *metadataTableNames[], psU32 nTables);
-
+static psF64 searchTables(psF64 index, psU64 column, char *metadataTableNames[],
+                          psU32 nTables, psLookupStatusType* status);
+static psTime* convertTimeTAIUTC(psTime* time);
+static psTime* convertTimeUTCTAI(psTime* time);
+static psTime* convertTimeTAITT(psTime* time);
+static psTime* convertTimeTTTAI(psTime* time);
+static psTime* convertTimeUTCUT1(psTime* time);
 
 /** Removes leading and trailing whitespace and # characters from a string. The cleaned string is a new null
@@ -83,14 +105,13 @@
     char *cleaned = NULL;
 
-
     ptrB = inString;
 
-    /* Skip over leading # or whitespace */
+    // Skip over leading # or whitespace
     while (isspace(*ptrB) || *ptrB=='#') {
         ptrB++;
     }
 
-    /* Skip over trailing whitespace, null terminators, and # characters */
-    ptrE = inString + sLen;
+    // Skip over trailing whitespace, null terminators, and # characters
+    ptrE = inString + sLen - 1;
     while(isspace(*ptrE) || *ptrE=='\0' || *ptrE=='#') {
         ptrE--;
@@ -113,5 +134,4 @@
     int sLen = 0;
 
-
     // Skip over leading whitespace
     while(isspace(**inString)) {
@@ -121,4 +141,5 @@
     // Length of token, not including delimiter
     sLen = strcspn(*inString, delimiter);
+
     if(sLen) {
 
@@ -127,5 +148,6 @@
 
         // Move to end of token
-        (*inString) += sLen;
+        (*inString) += (sLen+1);
+
     } else if(**inString!='\0' && sLen==0) {
         *status = PS_PARSE_ERROR_GENERAL;
@@ -148,45 +170,58 @@
 
 
-/** Searches time tables in priority order and performs interpolation if input index value is within a table.
- * If the index value is out of range, the status is set accordingly. */
-psF64 searchTables(psF64 index, psU64 column, psLookupStatusType *status, char *metadataTableNames[], psU32 nTables)
-{
-    psU32 i = 0;
-    char *tableName = NULL;
-    psF64 result = 0.0;
-    psLookupTable *table = NULL;
-    psMetadataItem *tableMetadataItem = NULL;
-
-
+// Searches time tables in priority order and performs interpolation if input index value is within a table.
+// If the index value is out of range, the status is set accordingly.
+static psF64 searchTables(psF64 index, psU64 column, char *metadataTableNames[],
+                          psU32 nTables, psLookupStatusType* status)
+{
+    char*            tableName          = NULL;
+    psF64            result             = NAN;
+    psLookupTable*   table              = NULL;
+    psMetadataItem*  tableMetadataItem  = NULL;
 
     // Check time metadata. Function call reports errors.
     if(timeMetadata == NULL) {
         if(!p_psTimeInit(p_psGetConfigFileName()))
-            return 0.0;
-    }
-
-    // Search each table in priority order: ser7, eopc,finals
-    for(i=0; i<nTables; i++) {
-
-        // Get table from metadata
+            *status = PS_LOOKUP_ERROR;
+        return NAN;
+    }
+
+    // Search each table in priority order: daily, eopc,finals
+    for(psS32 i = 0; i < nTables; i++) {
+
+        // Get table name from list of tables to search
         tableName = metadataTableNames[i];
+
+        // Lookup table name in time metadata
         tableMetadataItem = psMetadataLookup(timeMetadata, tableName);
+
+        // Check if table not a metadata item
         if(tableMetadataItem == NULL) {
             psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_LOOKUP_METADATA_FAILED,
                     tableName);
-            return 0.0;
-        }
+            *status = PS_LOOKUP_ERROR;
+            return NAN;
+        }
+
+        // Get table from metadata
         table = (psLookupTable*)tableMetadataItem->data.V;
-        PS_ASSERT_PTR_NON_NULL(table,0.0);
-
-        // Attempt to interpolate table
-        *status = PS_LOOKUP_SUCCESS;
-        result = psLookupTableInterpolate(table, index, 2, status);
-        if(*status == PS_LOOKUP_SUCCESS) {
-            return result;
-        } else if(*status == PS_LOOKUP_ERROR) {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_INTERPOLATION_FAILED_NAME,
-                    tableName);
-            return 0.0;
+
+        // Check that table is not NULL
+        PS_ASSERT_PTR_NON_NULL(table,NAN);
+
+        // Check if index within to/from range
+        if(index >= table->validFrom ) {
+            if(index <= table->validTo) {
+                // Attempt to interpolate table
+                result = psLookupTableInterpolate(table, index, column);
+                *status = PS_LOOKUP_SUCCESS;
+                if(!isnan(result)) {
+                    break;
+                }
+            } else {
+                *status = PS_LOOKUP_PAST_BOTTOM;
+            }
+        } else {
+            *status = PS_LOOKUP_PAST_TOP;
         }
     }
@@ -197,10 +232,14 @@
 bool p_psTimeInit(const char *fileName)
 {
+    psS32 numLines = 0;
     bool foundTable = false;
     char *tableDir = NULL;
     char *tableNames = NULL;
+    char *tableFormats = NULL;
     char *namesPtr = NULL;
+    char *formatPtr = NULL;
     char *metadataNamesPtr = NULL;
     char *tableName = NULL;
+    char *tableFormat = NULL;
     char *fullTableName = NULL;
     psS32 i = 0;
@@ -210,8 +249,9 @@
     psVector *tablesFrom = NULL;
     psVector *tablesTo = NULL;
+    psVector *tablesIndex = NULL;
     psMetadataItem *metadataItem = NULL;
     psLookupTable *table = NULL;
     psParseErrorType status = PS_PARSE_SUCCESS;
-    char metadataTableNames[4][MAX_STRING_LENGTH] = {"ser7", "eopc",  "finals", "tai"};
+    char metadataTableNames[4][MAX_STRING_LENGTH] = {"daily", "eopc",  "finals", "tai"};
 
     // Read time config file
@@ -251,4 +291,5 @@
         psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_LOOKUP_METADATA_FAILED,
                 "psLib.time.tables.to");
+        psFree(tablesFrom);
         return false;
     }
@@ -258,4 +299,22 @@
         psFree(tablesFrom);
         psFree(tablesTo);
+        return false;
+    }
+
+    // Get index columns for the tables
+    metadataItem = psMetadataLookup(timeMetadata, "psLib.time.tables.index");
+    if(metadataItem == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE,true,PS_ERRORTEXT_psTime_LOOKUP_METADATA_FAILED,
+                "psLib.time.tables.index");
+        psFree(tablesFrom);
+        psFree(tablesTo);
+        return false;
+    }
+    tablesIndex = psVectorCopy(tablesIndex, metadataItem->data.V, PS_TYPE_S32);
+    if(tablesIndex->n != numTables) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE,true,PS_ERRORTEXT_psTime_BAD_VECTOR,tablesIndex->n,numTables);
+        psFree(tablesFrom);
+        psFree(tablesTo);
+        psFree(tablesIndex);
         return false;
     }
@@ -268,4 +327,5 @@
         psFree(tablesFrom);
         psFree(tablesTo);
+        psFree(tablesIndex);
         return false;
     }
@@ -280,8 +340,24 @@
         psFree(tablesFrom);
         psFree(tablesTo);
+        psFree(tablesIndex);
         psFree(tableDir);
         return false;
     }
     tableNames = psStringCopy(metadataItem->data.V);
+
+    // Get table format strings
+    metadataItem = psMetadataLookup(timeMetadata, "psLib.time.tables.format");
+    if(metadataItem == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE,true, PS_ERRORTEXT_psTime_LOOKUP_METADATA_FAILED,
+                "psLib.time.tables.format");
+        psFree(tablesFrom);
+        psFree(tablesTo);
+        psFree(tablesIndex);
+        psFree(tableDir);
+        psFree(tableNames);
+        return false;
+    }
+    tableFormats = psStringCopy(metadataItem->data.V);
+    formatPtr = tableFormats;
 
     // Read time tables
@@ -289,5 +365,6 @@
     while((tableName=getToken(&namesPtr, " ", &status)) != NULL) {
 
-        // Form path with table name, adding one to length for last '/' that may not occur in string in cong file
+        // Form path with table name, adding one to length for last '/' that may not occur
+        // in string in cong file
         fullTableName = (char*)psAlloc(strlen(tableDir)+strlen(tableName)+1+1);
 
@@ -298,8 +375,15 @@
         strcat(fullTableName, tableName);
 
+        // Get table format
+        tableFormat = getToken(&formatPtr,",",&status);
+        if(tableFormat == NULL) {
+            psError(PS_ERR_BAD_PARAMETER_VALUE,true,PS_ERRORTEXT_psTime_LOOKUP_METADATA_FAILED,
+                    "psLib.time.tables.format");
+        }
+
         // Create and read table
         if(i < numTables) {
-            table = psLookupTableAlloc(fullTableName, tablesFrom->data.F64[i], tablesTo->data.F64[i]);
-            table = psLookupTableRead(table);
+            table = psLookupTableAlloc(fullTableName, (const char*)tableFormat, tablesIndex->data.S32[i]);
+            numLines = psLookupTableRead(table);
         } else {
             psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_BAD_TABLE_COUNT, i+1, numTables);
@@ -321,4 +405,5 @@
         psFree(fullTableName);
         psFree(tableName);
+        psFree(tableFormat);
         psFree(table);
         i++;
@@ -333,4 +418,6 @@
     psFree(tablesFrom);
     psFree(tablesTo);
+    psFree(tablesIndex);
+    psFree(tableFormats);
 
     return true;
@@ -351,7 +438,7 @@
     psTime *outTime = NULL;
 
-
     // Error checks
-    if(type!=PS_TIME_TAI && type!=PS_TIME_UTC) {
+    if(type!=PS_TIME_TAI && type!=PS_TIME_UTC && type!=PS_TIME_UT1 &&
+            type!=PS_TIME_TT) {
         psError(PS_ERR_BAD_PARAMETER_VALUE, true,
                 PS_ERRORTEXT_psTime_TYPE_UNKNOWN,
@@ -360,6 +447,8 @@
     }
 
+    // Allocate memory for structure
     outTime = (psTime*)psAlloc(sizeof(psTime));
 
+    // Initialize members
     outTime->sec = 0;
     outTime->nsec = 0;
@@ -375,8 +464,13 @@
     psTime *time = NULL;
 
-
     // Allocate psTime struct
     time = psTimeAlloc(type);
 
+    // Verify time structure allocated
+    if(time == NULL) {
+        return NULL;
+    }
+
+    // Get the system time
     if (gettimeofday(&now, (struct timezone *)0) == -1) {
         psError(PS_ERR_OS_CALL_FAILED, true,
@@ -391,5 +485,5 @@
     // Add most leapseconds to UTC time to get TAI time if necessary
     if(type == PS_TIME_TAI) {
-        time->sec += psTimeGetTAIDelta(time);
+        time->sec += p_psTimeGetTAIDelta(time);
     }
 
@@ -397,25 +491,239 @@
 }
 
+static psTime* convertTimeTAIUTC(psTime* time)
+{
+    psF64  deltaTAI     = 0.0;
+    psS64  deltaSec     = 0;
+    psU32  deltaNsec    = 0;
+    psF64  deltaUTC     = 0.0;
+
+    // Determine delta to convert between UTC and TAI
+    deltaTAI = p_psTimeGetTAIDelta(time);
+    deltaSec = (psS64)(deltaTAI);
+    deltaNsec = (psU32)((deltaTAI - (psF64)deltaSec) * 1e9);
+
+    // Determine seconds
+    time->sec -= deltaSec;
+
+    // Check for underflow in nsec
+    if(deltaNsec > time->nsec) {
+        // Borrow second
+        time->nsec += 1e9;
+        time->sec--;
+    }
+
+    // Determine nsec
+    time->nsec -= deltaNsec;
+
+    // Check for overflow in nsec
+    if(time->nsec >= 1e9) {
+        time->nsec -= 1e9;
+        time->sec++;
+    }
+
+    // Set new type
+    time->type = PS_TIME_UTC;
+
+    // Check if leapsecond present in delta
+    deltaUTC = p_psTimeGetTAIDelta(time);
+    if(fabs(deltaTAI-deltaUTC) >= 1.0) {
+        time->sec++;
+    }
+
+    return time;
+}
+
+static psTime* convertTimeUTCTAI(psTime* time)
+{
+    psF64  delta     = 0.0;
+    psS64  deltaSec  = 0;
+    psU32  deltaNsec = 0;
+
+    // Determine delta to convert between UTC and TAI
+    delta = p_psTimeGetTAIDelta(time);
+
+    deltaSec = (psS64)(delta);
+    deltaNsec = (psU32)((delta - (psF64)deltaSec) * 1e9);
+
+    // Determine seconds
+    time->sec += deltaSec;
+
+    // Determine nsec
+    time->nsec += deltaNsec;
+
+    // Check for overflow in nsec
+    if(time->nsec >= 1e9) {
+        time->nsec -= 1e9;
+        time->sec++;
+    }
+
+    // Set new type
+    time->type = PS_TIME_TAI;
+
+    return time;
+}
+
+static psTime* convertTimeTAITT(psTime* time)
+{
+    // Add TT offset
+    time->sec += TAI_TT_OFFSET_SECONDS;
+    time->nsec += TAI_TT_OFFSET_NANOSECONDS;
+
+    // Check for overflow in nsec
+    if(time->nsec >= 1e9) {
+        time->nsec -= 1e9;
+        time->sec++;
+    }
+
+    // Set new type
+    time->type = PS_TIME_TT;
+
+    return time;
+}
+
+static psTime* convertTimeTTTAI(psTime* time)
+{
+    // Subtract TT offset
+    time->sec -= TAI_TT_OFFSET_SECONDS;
+
+    // Check for nsec underflow
+    if(TAI_TT_OFFSET_NANOSECONDS > time->nsec) {
+        // Borrow second
+        time->sec--;
+        time->nsec += 1e9;
+    }
+    time->nsec -= TAI_TT_OFFSET_NANOSECONDS;
+
+    // Check for overflow in nsec
+    if(time->nsec >= 1e9) {
+        time->nsec -= 1e9;
+        time->sec++;
+    }
+
+    // Set new type
+    time->type = PS_TIME_TAI;
+
+    return time;
+}
+
+static psTime* convertTimeUTCUT1(psTime* time)
+{
+    psS64   ut1utc  = 0;
+
+    // Get UT1-UTC value
+    ut1utc = (psS64)(psTimeGetUT1Delta(time,PS_IERS_A) * 1e9);
+
+    // Since UTC is within 0.9 sec of UT1 then nsec member is the member affected
+    if((ut1utc < 0) && (abs(ut1utc) > time->nsec)) {
+        // Borrow from sec
+        time->sec--;
+        if(time->leapsecond) {
+            time->leapsecond = false;
+        } else {
+            time->leapsecond = psTimeIsLeapSecond(time);
+        }
+        // Add to nsec
+        time->nsec += 1e9;
+    }
+    time->nsec += ut1utc;
+
+    // Check for overflow in nsec
+    if(time->nsec >= 1e9) {
+        time->nsec -= 1e9;
+        time->sec++;
+        if(time->leapsecond) {
+            time->leapsecond = false;
+            time->sec--;
+        } else {
+            time->leapsecond = psTimeIsLeapSecond(time);
+        }
+    }
+
+    // Set new type
+    time->type = PS_TIME_UT1;
+
+    return time;
+}
+
 psTime* psTimeConvert(psTime *time, psTimeType type)
 {
-    double delta = 0.0;
-
-
     // Error checks
     PS_ASSERT_PTR_NON_NULL(time,NULL);
-    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,1e9-1,NULL);
-
-    if (time->type == type) { // time already right type.  That was easy!
+    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,(psU32)((1e9)-1),time);
+
+    // If the input type is UT1 then return time and generate error message
+    if(time->type == PS_TIME_UT1) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE,true,"Cannot convert from UT1 time type");
         return time;
     }
 
-    delta = psTimeGetTAIDelta(time);
-
-    if (type == PS_TIME_UTC) {
-        time->sec = time->sec - delta;    // User wants UTC time. Subtract leapseconds.
-    } else if(type == PS_TIME_TAI) {
-        time->sec = time->sec + delta;    // User wants TAI time. Add leapseconds.
+    // If the time to convert to is the same as psTime the return time
+    if (time->type == type) {
+        return time;
+    }
+
+    // Convert from TAI to UTC, TT, UT1
+    if(time->type == PS_TIME_TAI) {
+        // Convert from TAI to UTC
+        if(type == PS_TIME_UTC) {
+            time = convertTimeTAIUTC(time);
+            // Convert from TAI to TT
+        } else if(type == PS_TIME_TT) {
+            time = convertTimeTAITT(time);
+            // Convert from TAI to UT1
+        } else if(type == PS_TIME_UT1) {
+            // Convert to UTC first
+            time = convertTimeTAIUTC(time);
+            // Convert UTC to UT1
+            time = convertTimeUTCUT1(time);
+            // Convert from TAI to unknown time type
+        } else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_TYPE_UNKNOWN, type);
+        }
+        // Convert from TT to TAI, UTC, UT1
+    } else if(time->type == PS_TIME_TT) {
+        // Convert from TT to UTC
+        if(type == PS_TIME_UTC) {
+            // Convert to TAI time first
+            time = convertTimeTTTAI(time);
+            // Convert from TAI to UTC
+            time = convertTimeTAIUTC(time);
+            // Convert from TT to TAI
+        } else if(type == PS_TIME_TAI) {
+            time = convertTimeTTTAI(time);
+            // Convert from TT to UT1
+        } else if(type == PS_TIME_UT1) {
+            // Convert to UTC first
+            // Convert to TAI time first
+            time = convertTimeTTTAI(time);
+            // Convert from TAI to UTC
+            time = convertTimeTAIUTC(time);
+            // Convert from UTC to UT1
+            time = convertTimeUTCUT1(time);
+            // Convert from TT to unknown time type
+        } else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_TYPE_UNKNOWN, type);
+        }
+        // Convert from UTC to TAI, TT, UT1
+    } else if(time->type == PS_TIME_UTC) {
+        // Convert UTC to TAI
+        if(type == PS_TIME_TAI) {
+            time = convertTimeUTCTAI(time);
+            // Convert UTC to TT
+        } else if(type == PS_TIME_TT) {
+            // Convert to TAI time first
+            time = convertTimeUTCTAI(time);
+            // Convert TAI to TT
+            time = convertTimeTAITT(time);
+            // Convert UTC to UT1
+        } else if(type == PS_TIME_UT1) {
+            time = convertTimeUTCUT1(time);
+            // Convert UTC to unknown time type
+        } else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_TYPE_UNKNOWN, type);
+        }
+        // Convert unknown time type
     } else {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_TYPE_UNKNOWN, type);
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_TYPE_UNKNOWN, time->type);
     }
 
@@ -423,5 +731,5 @@
 }
 
-double psTimeToLMST(psTime *time, double longitude)
+psF64 psTimeToLMST(psTime *time, psF64 longitude)
 {
     psF64  jdTdtDays    =  0.0;
@@ -433,5 +741,4 @@
     psF64  t            =  0.0;
     psF64  tu           =  0.0;
-    psF64  ut1UtcDbl    =  0.0;
     psF64  const1       =  24110.5493771;
     psF64  const2       =  8639877.3173760;
@@ -440,34 +747,30 @@
     psF64  const5       = -0.0000062;
     psF64  const6       =  0.0000013;
-    psTime *ut1UtcDelta = NULL;
     psTime *tdtTime     = NULL;
-    psTime *taiTime     = NULL;
-    psTime *utcTime     = NULL;
     psTime *ut1Time     = NULL;
-
 
     // Error checks
     PS_ASSERT_PTR_NON_NULL(time,NAN);
-    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,1e9-1,NAN);
-
-    // Calculate TAI or UTC time based on type of time user passes
-    if(time->type == PS_TIME_TAI) {
-        taiTime = psMemIncrRefCounter(time);
-        utcTime = psTimeAlloc(PS_TIME_UTC);
-        utcTime->sec = taiTime->sec - psTimeGetTAIDelta(time);
-        utcTime->nsec = taiTime->nsec;
-    } else if(time->type == PS_TIME_UTC) {
-        utcTime = psMemIncrRefCounter(time);
-        taiTime = psTimeAlloc(PS_TIME_TAI);
-        taiTime->sec = utcTime->sec + psTimeGetTAIDelta(time);
-        taiTime->nsec = utcTime->nsec;
-    }
-
-    // Convert Universal Time (UTC) to  UT1
-    ut1UtcDbl = psTimeGetUT1Delta(taiTime);
-    utcTime->type = PS_TIME_TAI; // Don't allow addition of leapseconds to ut1Time
-    ut1Time = psTimeMath(utcTime, ut1UtcDbl);
-    utcTime->type = PS_TIME_UTC;
-
+    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,(psU32)((1e9)-1),NAN);
+
+    // Verify input time is not in UT1 seconds
+    if(time->type == PS_TIME_UT1) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE,true,PS_ERRORTEXT_psTime_TYPE_INCORRECT,time->type);
+        return NAN;
+    }
+
+    // Determine time reference to TT
+    tdtTime = psTimeAlloc(time->type);
+    tdtTime->sec = time->sec;
+    tdtTime->nsec = time->nsec;
+    tdtTime->leapsecond = time->leapsecond;
+    tdtTime = psTimeConvert(tdtTime,PS_TIME_TT);
+
+    // Determine time reference to UT1
+    ut1Time = psTimeAlloc(time->type);
+    ut1Time->sec = time->sec;
+    ut1Time->nsec = time->nsec;
+    ut1Time->leapsecond = time->leapsecond;
+    ut1Time = psTimeConvert(ut1Time,PS_TIME_UT1);
 
     // Calculate UT1 as Julian Centuries since J2000.0
@@ -476,7 +779,4 @@
     t = (jdUt1Days - 2451545.0)/36525.0;
 
-    // Calculate Terrestial Dynamical Time (TDT)
-    tdtTime = psTimeMath(taiTime, 32.184);
-
     // Calculate TDT as Julian centuries since J2000.0
     jdTdtDays = psTimeToJD(tdtTime);
@@ -486,6 +786,8 @@
     fracDays = fmod(mjdUt1Days, 1.0);
 
-    // Calculate Greenwich Mean Sidereal Time (GMST) in radians. Equation set up to minimize multiplications.
-    gmstRad = fracDays*TWOPI+(const1+const2*tu+t*(const3+t*(const4+t*(const5+const6*t))))*S2R;
+    // Calculate Greenwich Mean Sidereal Time (GMST) in radians.
+    // Equation set up to minimize multiplications.
+    gmstRad = fracDays*TWOPI
+              + (const1+const2*tu+t*(const3+t*(const4+t*(const5+const6*t))))*S2R;
 
     // Place GMST between 0 and 2*pi
@@ -496,38 +798,43 @@
 
     // Free temporary structs
-    psFree(ut1UtcDelta);
     psFree(ut1Time);
     psFree(tdtTime);
-    psFree(utcTime);
-    psFree(taiTime);
 
     return lmstRad;
 }
 
-double psTimeGetUT1Delta(const psTime *time)
-{
-    psU32 nTables = 3;
-    psF64 mjd = 0.0;
-    psF64 result = 0.0;
-    psF64 dut2ut1 = 0.0;
-    psF64 t = 0.0;
-    psVector *dut = NULL;
-    psMetadataItem *tableMetadataItem = NULL;
-    psLookupStatusType status = PS_LOOKUP_SUCCESS;
-    char *metadataTableNames[3] = {"ser7Table", "eopcTable",  "finalsTable"};
-
+psF64 psTimeGetUT1Delta(const psTime *time, psTimeBulletin bulletin)
+{
+    psU32              nTables               = 2;
+    psF64              mjd                   = 0.0;
+    psF64              result                = 0.0;
+    psU64              tableColumn           = 0;
+    psF64              dut2ut1               = 0.0;
+    psF64              t                     = 0.0;
+    psVector*          dut                   = NULL;
+    psMetadataItem*    tableMetadataItem     = NULL;
+    psLookupStatusType status                = PS_LOOKUP_SUCCESS;
+    char*              metadataTableNames[2] = {"dailyTable",  "finalsTable"};
 
     // Error checks
     PS_ASSERT_PTR_NON_NULL(time,NAN);
-    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,1e9-1,NAN);
-
-    if(time->type != PS_TIME_TAI) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_TYPE_INCORRECT, time->type);
-        return 0.0;
+    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,(psU32)((1e9)-1),NAN);
+
+    // Check for invalid bulletin specified
+    if((bulletin != PS_IERS_A) && (bulletin != PS_IERS_B)) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE,true,"Invalid bulletin specified %d",bulletin);
+        return NAN;
+    }
+
+    // Set lookup table column based on Bullentin
+    if(bulletin == PS_IERS_A) {
+        tableColumn = 3;
+    } else {
+        tableColumn = 6;
     }
 
     // Attempt to find value through table lookup and interpolation
     mjd = psTimeToMJD(time);
-    result = searchTables(mjd, 0, &status, metadataTableNames, nTables);
+    result = searchTables(mjd,tableColumn,metadataTableNames,nTables,&status);
 
     // Value could not be found through table lookup and interpolation
@@ -535,10 +842,12 @@
 
         // Date too early for tables. Get default time delta value from metadata, and issue warning.
-        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_TIME_PREDATES_TABLES, mjd, "UT1-UTC");
-
+        psLogMsg(__func__,PS_LOG_WARN,PS_ERRORTEXT_psTime_TIME_PREDATES_TABLES,mjd,"UT1-UTC");
+
+        // Lookup value from time metadata loaded from psTime.config
         tableMetadataItem = psMetadataLookup(timeMetadata, "psLib.time.before.dut");
         if(tableMetadataItem == NULL) {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_LOOKUP_METADATA_FAILED, "psLib.time.before.dut");
-            return 0.0;
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_LOOKUP_METADATA_FAILED,
+                    "psLib.time.before.dut");
+            return NAN;
         }
         result = tableMetadataItem->data.F64;
@@ -552,14 +861,18 @@
              t = 2000.0 + (MJD - 51544.03)/365.2422
         */
-        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_TIME_POSTDATES_TABLES, mjd, "UT1-UTC");
-
+        // Generate warning of postdate information
+        psLogMsg(__func__,PS_LOG_WARN,PS_ERRORTEXT_psTime_TIME_POSTDATES_TABLES, mjd, "UT1-UTC");
+
+        // Lookup values to calculate prediction
         tableMetadataItem = psMetadataLookup(timeMetadata, "psLib.time.predict.dut");
         if(tableMetadataItem == NULL) {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_LOOKUP_METADATA_FAILED, "psLib.time.predict.dut");
-            return 0.0;
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_LOOKUP_METADATA_FAILED,
+                    "psLib.time.predict.dut");
+            return NAN;
         }
         dut = (psVector*)tableMetadataItem->data.V;
-        PS_ASSERT_PTR_NON_NULL(dut,0.0);
-
+        PS_ASSERT_PTR_NON_NULL(dut,NAN);
+
+        // Calculate predication of future UT1-UTC
         t = 2000.0 + (mjd - 51544.03)/365.2422;
         dut2ut1 = 0.022*sin(TWOPI*t) - 0.012*cos(TWOPI*t) - 0.006*sin(4.0*M_PI*t) + 0.007*cos(4.0*M_PI*t);
@@ -568,5 +881,5 @@
     } else if(status != PS_LOOKUP_SUCCESS) {
         psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_INTERPOLATION_FAILED);
-        return 0.0;
+        return NAN;
     }
 
@@ -574,5 +887,5 @@
 }
 
-struct psSphere* psTimeGetPoleCoords(const psTime* time)
+struct psSphere* p_psTimeGetPoleCoords(const psTime* time)
 {
     psU32 nTables = 3;
@@ -587,5 +900,5 @@
     psLookupStatusType yStatus = PS_LOOKUP_SUCCESS;
     psMetadataItem *tableMetadataItem = NULL;
-    char *metadataTableNames[3] = {"ser7Table", "eopcTable",  "finalsTable"};
+    char *metadataTableNames[3] = {"dailyTable", "eopcTable",  "finalsTable"};
     psVector *xp = NULL;
     psVector *yp = NULL;
@@ -593,5 +906,5 @@
     // Error checks
     PS_ASSERT_PTR_NON_NULL(time,NULL);
-    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,1e9-1,NULL);
+    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,(psU32)((1e9)-1),NULL);
 
     if(time->type != PS_TIME_TAI)
@@ -603,6 +916,8 @@
     // Attempt to find value through table lookup and interpolation
     mjd = psTimeToMJD(time);
-    x = searchTables(mjd, 0, &xStatus, metadataTableNames, nTables);
-    y = searchTables(mjd, 0, &yStatus, metadataTableNames, nTables);
+    //    x = searchTables(mjd, 0, &xStatus, metadataTableNames, nTables);
+    x = searchTables(mjd, 0, metadataTableNames, nTables,&xStatus);
+    //    y = searchTables(mjd, 0, &yStatus, metadataTableNames, nTables);
+    y = searchTables(mjd, 0, metadataTableNames, nTables,&yStatus);
 
     // Value could not be found through table lookup and interpolation
@@ -641,5 +956,4 @@
         psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_TIME_POSTDATES_TABLES, mjd, "polar motion");
 
-
         // Get predicted MJD
         tableMetadataItem = psMetadataLookup(timeMetadata, "psLib.time.predict.mjd");
@@ -692,5 +1006,5 @@
     }
 
-    // Create output sphere and convert arcsec to radians (i.e. x/60/60*M_PI/180)
+    // Create output sphere and convert arcsec to radians (i.e. x/60/60*PS_PI/180)
     output = psAlloc(sizeof(psSphere));
     output->r = x * M_PI / 648000.0;
@@ -700,7 +1014,6 @@
 }
 
-double psTimeGetTAIDelta(const psTime *time)
-{
-    psU64 i = 0;
+psF64 p_psTimeGetTAIDelta(const psTime *time)
+{
     psF64 jd = 0.0;
     psF64 mjd = 0.0;
@@ -711,10 +1024,9 @@
     psLookupTable* table = NULL;
     psMetadataItem *tableMetadataItem = NULL;
-    psVector *stats = NULL;
     psVector *results = NULL;
 
     // Error checks
     PS_ASSERT_PTR_NON_NULL(time,NAN);
-    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,1e9-1,NAN);
+    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,(psU32)((1e9)-1),NAN);
 
     // Check time metadata
@@ -739,20 +1051,29 @@
     mjd = psTimeToMJD(time);
 
-    stats = psVectorAlloc(table->numCols, PS_TYPE_U32);
-    results = psLookupTableInterpolateAll(table, jd, stats);
+    // Set ceiling of the julian date to the last entry in the lookup table
+    if(table->validTo < jd) {
+        jd = table->validTo;
+    }
+
+    // Interpolation of look up table
+    results = psLookupTableInterpolateAll(table, jd);
 
     // Check for successful interpolation
-    for(i=0; i<stats->n; i++) {
-        if(stats->data.U32[i] == PS_LOOKUP_ERROR) {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_INTERPOLATION_FAILED);
-        }
-    }
-
-    const1 = results->data.F64[0];
-    const2 = results->data.F64[1];
-    const3 = results->data.F64[2];
-    out = const1 + (mjd - const2) * const3;
-
-    psFree(stats);
+    if(results == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_INTERPOLATION_FAILED);
+    }
+
+    // Set constants from table
+    const1 = results->data.F64[1];
+    const2 = results->data.F64[2];
+    const3 = results->data.F64[3];
+
+    // If const3 not equal to zero solve for difference else floor of const1
+    if(fabs(const3-0.0) > FLT_EPSILON) {
+        out = const1 + (mjd - const2) * const3;
+    } else {
+        out = floor(const1);
+    }
+
     psFree(results);
 
@@ -760,33 +1081,64 @@
 }
 
-
 psS64 psTimeLeapSecondDelta(const psTime *time1, const psTime *time2)
 {
     psS64 diff = 0;
-
 
     // Error checks
     PS_ASSERT_PTR_NON_NULL(time1,0);
     PS_ASSERT_PTR_NON_NULL(time2,0);
-    PS_ASSERT_INT_WITHIN_RANGE(time1->nsec,0,1e9-1,0);
-    PS_ASSERT_INT_WITHIN_RANGE(time2->nsec,0,1e9-1,0);
-    diff = abs((psS64)psTimeGetTAIDelta((psTime*)time1)-(psS64)psTimeGetTAIDelta((psTime*)time2));
+    PS_ASSERT_INT_WITHIN_RANGE(time1->nsec,0,(psU32)((1e9)-1),0);
+    PS_ASSERT_INT_WITHIN_RANGE(time2->nsec,0,(psU32)((1e9)-1),0);
+    diff = abs((psS64)p_psTimeGetTAIDelta((psTime*)time1)-(psS64)p_psTimeGetTAIDelta((psTime*)time2));
 
     return diff;
 }
 
-double psTimeToJD(const psTime *time)
-{
-    double jd = 0.0;
+psBool psTimeIsLeapSecond(const psTime* utc)
+{
+    psTime*    prevUtc     = NULL;
+    psBool     returnValue = false;
+
+    // Check for valid time
+    PS_ASSERT_PTR_NON_NULL(utc,false);
+
+    // Verify time is UTC type
+    if(utc->type != PS_TIME_UTC) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE,true,PS_ERRORTEXT_psTime_TYPE_INCORRECT,utc->type);
+        return false;
+    }
+
+    // Allocate time to hold utc - 1 second
+    prevUtc = psTimeAlloc(PS_TIME_UTC);
+    prevUtc->sec = utc->sec - 1;
+
+    // Check the absolute difference between the two times for leapsecond
+    if(psTimeLeapSecondDelta(utc,prevUtc) >= 1.0) {
+        returnValue = true;
+    } else {
+        returnValue = false;
+    }
+
+    // Free prevUtc
+    psFree(prevUtc);
+
+    return returnValue;
+}
+
+psF64 psTimeToJD(const psTime *time)
+{
+    psF64 jd = NAN;
 
     // Error checks
     PS_ASSERT_PTR_NON_NULL(time,NAN);
-    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,1e9-1,NAN);
+    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,(psU32)((1e9)-1),NAN);
 
     // Julian date conversion
     if(time->sec < 0) {
-        jd = time->sec / SEC_PER_DAY - time->nsec / NSEC_PER_DAY + 2440587.5; // psTime earlier than epoch
+        // psTime earlier than epoch
+        jd = time->sec / SEC_PER_DAY - time->nsec / NSEC_PER_DAY + JD_EPOCH_OFFSET;
     } else {
-        jd = time->sec / SEC_PER_DAY + time->nsec / NSEC_PER_DAY + 2440587.5; // psTime greater than epoch
+        // psTime greater than epoch
+        jd = time->sec / SEC_PER_DAY + time->nsec / NSEC_PER_DAY + JD_EPOCH_OFFSET;
     }
 
@@ -794,18 +1146,19 @@
 }
 
-double psTimeToMJD(const psTime *time)
-{
-    double mjd = 0.0;
-
+psF64 psTimeToMJD(const psTime *time)
+{
+    psF64 mjd = NAN;
 
     // Error checks
     PS_ASSERT_PTR_NON_NULL(time,NAN);
-    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,1e9-1,NAN);
+    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,(psU32)((1e9)-1),NAN);
 
     // Modified Julian date conversion
     if(time->sec < 0) {
-        mjd = time->sec / SEC_PER_DAY - time->nsec / NSEC_PER_DAY + 40587.0; // psTime earlier than epoch
+        // psTime earlier than epoch
+        mjd = time->sec / SEC_PER_DAY - time->nsec / NSEC_PER_DAY + MJD_EPOCH_OFFSET;
     } else {
-        mjd = time->sec / SEC_PER_DAY + time->nsec / NSEC_PER_DAY + 40587.0; // psTime greater than epoch
+        // psTime greater than epoch
+        mjd = time->sec / SEC_PER_DAY + time->nsec / NSEC_PER_DAY + MJD_EPOCH_OFFSET;
     }
 
@@ -815,5 +1168,5 @@
 char* psTimeToISO(const psTime *time)
 {
-    psS32 ms = 0;
+    psS32 ds = 0;
     char *timeString = NULL;
     char *tempString = NULL;
@@ -821,14 +1174,23 @@
     time_t sec;
 
-
     // Error checks
     PS_ASSERT_PTR_NON_NULL(time,NULL);
-    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,1e9-1,NULL);
-
+    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,(psU32)((1e9)-1),NULL);
+
+    // Check valid year range
+    PS_ASSERT_LONG_WITHIN_RANGE(time->sec,YEAR_0000_SEC,YEAR_9999_SEC,NULL)
+
+    // Allocate temp strings
     tempString = psAlloc(MAX_TIME_STRING_LENGTH);
     timeString = psAlloc(MAX_TIME_STRING_LENGTH);
 
-    ms = time->nsec / 1000000;
+    // Convert nanoseconds to decaseconds
+    ds = time->nsec / 100000000;
     sec = time->sec;
+
+    // If leapsecond use previous day
+    if(time->leapsecond) {
+        sec--;
+    }
 
     // tmTime variable is statically allocated, no need to free
@@ -840,5 +1202,13 @@
     }
 
-    if (snprintf(timeString, MAX_TIME_STRING_LENGTH, "%s.%3.3dZ", tempString, ms) < 0) {
+    // Check if time is UTC and leapsecond
+    if(((time->type==PS_TIME_UTC)||(time->type==PS_TIME_UT1)) && (time->leapsecond)) {
+        // Modify second to be 60
+        tempString[17] = '6';
+        tempString[18] = '0';
+    }
+
+    // Create string with milliseconds
+    if (snprintf(timeString, MAX_TIME_STRING_LENGTH, "%s,%1dZ", tempString, ds) < 0) {
         psError(PS_ERR_OS_CALL_FAILED, true, PS_ERRORTEXT_psTime_APPEND_MSEC_FAILED);
     }
@@ -848,22 +1218,25 @@
 }
 
-struct timeval psTimeToTimeval(const psTime *time)
-{
-    struct timeval timevalTime;
-
-    timevalTime.tv_sec = 0;
-    timevalTime.tv_usec = 0;
+struct timeval* psTimeToTimeval(const psTime *time)
+{
+    struct timeval  *timevalTime = NULL;
 
     // Error checks
-    PS_ASSERT_PTR_NON_NULL(time,timevalTime);
-    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,1e9-1,timevalTime);
-
-    timevalTime.tv_sec = time->sec;
-    timevalTime.tv_usec = time->nsec / 1000;
+    PS_ASSERT_PTR_NON_NULL(time,NULL);
+    PS_ASSERT_INT_WITHIN_RANGE(time->sec,0,INT32_MAX,NULL);
+    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,(psU32)((1e9)-1),NULL);
+
+    // Allocate structure timeval
+    timevalTime = (struct timeval*)psAlloc(sizeof(struct timeval));
+
+    // Set structure members
+    timevalTime->tv_sec = time->sec;
+    timevalTime->tv_usec = time->nsec / 1000;
 
     return timevalTime;
 }
 
-struct tm* psTimeToTM(const psTime *time)
+/*
+struct tm* p_psTimeToTM(const psTime *time)
 {
     psS64 cent = 0;
@@ -876,15 +1249,15 @@
     psS64 temp = 0;
     struct tm* tmTime = NULL;
-
-
+ 
+ 
     // Error checks
     PS_ASSERT_PTR_NON_NULL(time,NULL);
-    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,1e9-1,NULL);
-
+    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,(psU32)((1e9)-1),NULL);
+ 
     seconds = time->sec%60;
     minute = time->sec/60%60;
     hour = time->sec/3600%24;
     day = (time->sec+62135596800)/86400;
-
+ 
     // Add 306 days to make relative to Mar 1, 0; also adjust day to be within a range (1..2**28-1) where our
     // calculations will work with 32bit ints
@@ -898,5 +1271,5 @@
         day -= temp * 146097;
     }
-
+ 
     cent = (day*4-1)/146097;                        // Calc number of centuries day is after 29 Feb of yr 0
     day -= cent*146097/4;                           // 4 centuries = 146097 days
@@ -906,5 +1279,5 @@
     day -= (month*367-1094)/12;                     // February of following year)
     year += cent*100+temp*400;                      // Get the real year, which is off by
-
+ 
     // One if month is January or February
     if(month > 12)
@@ -913,8 +1286,8 @@
         month -= 12;
     }
-
+ 
     // Allocate output
     tmTime = (struct tm*)psAlloc(sizeof(struct tm));
-
+ 
     tmTime->tm_year = year - 1900;
     tmTime->tm_mon = month - 1;
@@ -924,14 +1297,14 @@
     tmTime->tm_sec = seconds;
     tmTime->tm_isdst = -1;
-
+ 
     return tmTime;
 }
-
-psTime* psTimeFromJD(double time)
-{
-    double days = 0.0;
-    double seconds = 0.0;
+*/
+
+psTime* psTimeFromJD(psF64 time)
+{
+    psF64 days = 0.0;
+    psF64 seconds = 0.0;
     psTime *outTime = NULL;
-
 
     // Allocate psTime struct
@@ -949,15 +1322,14 @@
 
     // Error check
-    PS_ASSERT_INT_WITHIN_RANGE(outTime->nsec,0,1e9-1,outTime);
+    PS_ASSERT_INT_WITHIN_RANGE(outTime->nsec,0,(psU32)((1e9)-1),outTime);
 
     return outTime;
 }
 
-psTime* psTimeFromMJD(double time)
-{
-    double days = 0.0;
-    double seconds = 0.0;
+psTime* psTimeFromMJD(psF64 time)
+{
+    psF64 days = 0.0;
+    psF64 seconds = 0.0;
     psTime *outTime = NULL;
-
 
     // Allocate psTime struct
@@ -967,4 +1339,5 @@
     days = time - 40587.0;
     seconds = days * SEC_PER_DAY;
+
     if(seconds < 0.0) {
         outTime->nsec = (seconds - (psS64)seconds) * -1000000000.0;  // psTime earlier than epoch
@@ -975,5 +1348,5 @@
 
     // Error check
-    PS_ASSERT_INT_WITHIN_RANGE(outTime->nsec,0,1e9-1,outTime);
+    PS_ASSERT_INT_WITHIN_RANGE(outTime->nsec,0,(psU32)((1e9)-1),NULL);
 
     return outTime;
@@ -986,6 +1359,9 @@
     psTime *outTime = NULL;
 
+    // Check for NULL string
+    PS_ASSERT_PTR_NON_NULL(time,NULL);
+
     // Convert YYYY-MM-DDThh:mm:ss.sss in string form to tm time
-    if (sscanf(time, "%d-%d-%dT%d:%d:%d.%d", &tmTime.tm_year, &tmTime.tm_mon, &tmTime.tm_mday,
+    if (sscanf(time, "%d-%d-%dT%d:%d:%d,%d", &tmTime.tm_year, &tmTime.tm_mon, &tmTime.tm_mday,
                &tmTime.tm_hour, &tmTime.tm_min, &tmTime.tm_sec,&millisecond) < 7) {
         psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_ISOTIME_MALFORMED, time);
@@ -1006,6 +1382,44 @@
 
     // Convert tm time to psTime
-    outTime = psTimeFromTM(&tmTime);
+    outTime = p_psTimeFromTM(&tmTime);
     outTime->nsec = millisecond * 1000000;
+
+    return outTime;
+}
+
+psTime* psTimeFromTT(psS64 sec, psU32 nsec)
+{
+    psTime*      outTime  = NULL;
+
+    // Verify nsec within range
+    PS_ASSERT_INT_WITHIN_RANGE(nsec,0,(psU32)((1e9)-1),NULL);
+
+    // Allocate psTime data
+    outTime = psTimeAlloc(PS_TIME_TT);
+
+    // Set data members
+    outTime->sec = sec;
+    outTime->nsec = nsec;
+
+    // Return data structure
+    return outTime;
+}
+
+psTime* psTimeFromUTC(psS64 sec, psU32 nsec, psBool leapsecond)
+{
+    psTime*   outTime   = NULL;
+
+    // Verify nsec within range
+    PS_ASSERT_INT_WITHIN_RANGE(nsec,0,(psU32)((1e9)-1),NULL);
+
+    // Allocate psTime data
+    outTime = psTimeAlloc(PS_TIME_UTC);
+
+    // Set data members
+    outTime->sec = sec;
+    outTime->nsec = nsec;
+
+    // Set leapsecond flag if necessary
+    outTime->leapsecond = psTimeIsLeapSecond(outTime);
 
     return outTime;
@@ -1028,10 +1442,10 @@
 
     // Error check
-    PS_ASSERT_INT_WITHIN_RANGE(outTime->nsec,0,1e9-1,outTime);
+    PS_ASSERT_INT_WITHIN_RANGE(outTime->nsec,0,(psU32)((1e9)-1),outTime);
 
     return outTime;
 }
 
-psTime* psTimeFromTM(const struct tm* time)
+psTime* p_psTimeFromTM(const struct tm* time)
 {
     psS64 year;
@@ -1044,5 +1458,4 @@
     psTime *outTime = NULL;
 
-
     // Error check
     PS_ASSERT_PTR_NON_NULL(time,NULL);
@@ -1062,9 +1475,13 @@
     if( month <= 2 )
     {
-        year -= (temp = (14 - month) / 12);
+        temp = (14 - month) / 12;
+        //        year -= (temp = (14 - month) / 12);
+        year -= temp;
         month += 12 * temp;
     } else if(month > 14)
     {
-        year += (temp = (month - 3) / 12);
+        temp = (month - 3) / 12;
+        //        year += (temp = (month - 3) / 12);
+        year += temp;
         month -= 12 * temp;
     }
@@ -1081,5 +1498,6 @@
     // days to adjust from Mar 1, year 0-relative to Jan 1, year 1-relative. Add hours, minutes, and seconds.
     day += (month * 367 - 1094) / 12 + year % 100 * 1461 / 4 + (year/100 * 36524 + year/400) - 306;
-    outTime->sec = (((day - 1) * SEC_PER_DAY) - 62135596800) + hour*SEC_PER_HOUR + minute*SEC_PER_MINUTE + seconds;
+    outTime->sec = (((day - 1) * SEC_PER_DAY) - 62135596800) + hour*SEC_PER_HOUR
+                   + minute*SEC_PER_MINUTE + seconds;
 
     // C's TM does not define a microsecond field. Microseconds must be manipulated by calling function.
@@ -1087,5 +1505,5 @@
 
     // Error check
-    PS_ASSERT_INT_WITHIN_RANGE(outTime->nsec,0,1e9-1,outTime);
+    PS_ASSERT_INT_WITHIN_RANGE(outTime->nsec,0,(psU32)((1e9)-1),outTime);
 
     return outTime;
@@ -1098,8 +1516,7 @@
     psTime *tempTime = NULL;
 
-
     // Error checks
     PS_ASSERT_PTR_NON_NULL(time,NULL);
-    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,1e9-1,NULL);
+    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,(psU32)((1e9)-1),NULL);
 
     // Convert time to TAI if necessary, but without changing input arguments
@@ -1109,16 +1526,18 @@
         tempTime->nsec = time->nsec;
         tempTime = psTimeConvert(tempTime, PS_TIME_TAI);
+        outTime = psTimeAlloc(PS_TIME_TAI);
     } else {
         tempTime = psMemIncrRefCounter((psTime*)time);
+        outTime = psTimeAlloc(time->type);
     }
 
     // Create output time
-    outTime = psTimeAlloc(PS_TIME_TAI);
     sec = delta + (psF64)tempTime->sec + (psF64)tempTime->nsec/1e9;
-    outTime->sec = sec;
-    outTime->nsec = (sec - outTime->sec)*1e9;
+    PS_ASSERT_LONG_WITHIN_RANGE((psS64)sec,0,PS_MAX_S64,outTime);
+    outTime->sec = (psS64)sec;
+    outTime->nsec = (psU32)((sec - (psF64)outTime->sec)*1e9);
 
     // Error check
-    PS_ASSERT_INT_WITHIN_RANGE(outTime->nsec,0,1e9-1,outTime);
+    PS_ASSERT_INT_WITHIN_RANGE(outTime->nsec,0,(psU32)((1e9)-1),outTime);
 
     // Convert result to same time type as input
@@ -1140,10 +1559,15 @@
     psTime *tempTime2 = NULL;
 
-
     // Error checks
     PS_ASSERT_PTR_NON_NULL(time1,0.0);
-    PS_ASSERT_INT_WITHIN_RANGE(time1->nsec,0,1e9-1,0.0);
+    PS_ASSERT_INT_WITHIN_RANGE(time1->nsec,0,(psU32)((1e9)-1),0.0);
     PS_ASSERT_PTR_NON_NULL(time2,0.0);
-    PS_ASSERT_INT_WITHIN_RANGE(time2->nsec,0,1e9-1,0.0);
+    PS_ASSERT_INT_WITHIN_RANGE(time2->nsec,0,(psU32)((1e9)-1),0.0);
+
+    // Verify both times of the same type
+    if(time1->type != time2->type) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE,true,PS_ERRORTEXT_psTime_TYPE_INCORRECT,time1->type);
+        return out;
+    }
 
     // Convert time to TAI if necessary, but without changing input arguments
Index: /trunk/psLib/src/astro/psTime.h
===================================================================
--- /trunk/psLib/src/astro/psTime.h	(revision 4050)
+++ /trunk/psLib/src/astro/psTime.h	(revision 4051)
@@ -1,19 +1,19 @@
 /** @file  psTime.h
  *
- *  @brief Definitions for time, time utilities, and conversion functions for use with psLib astronomy
- *  functions.
- *
- *  A collection of functions are required by psLib to manipulate time data. These functions primarily consist
- *  of conversions between specific time formats.  They use the UNIX timeval time system as the
- *  base upon which International Atomic Time (TAI) and Universal Time Coordinated (UTC) are calculated.
+ *  @brief Definitions for time, time utilities, and conversion functions for use 
+ *  with psLib astronomy functions.
+ *
+ *  A collection of functions are required by psLib to manipulate time data. These 
+ *  functions primarily consist of conversions between specific time formats.  They 
+ *  use the UNIX timeval time system as the base upon which International Atomic 
+ *  Time (TAI) and Universal Time Coordinated (UTC) are calculated.
  *
  *  @author Ross Harman, MHPCC
  *
- *  @version $Revision: 1.28 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2005-04-19 02:44:12 $
+ *  @version $Revision: 1.29 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2005-05-31 21:47:46 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
  */
-
 
 #ifndef PSTIME_H
@@ -88,6 +88,7 @@
 /** Allocate time struct.
  *
- * Allocates an empty time struct. User must specify the psTimeType (PS_TIME_TAI or PS_TIME_UTC) in the argument.
- * The seconds and microseconds members of the struct are set to zero.
+ * Allocates an empty time struct. User must specify the psTimeType 
+ * (PS_TIME_TAI or PS_TIME_UTC) in the argument. The seconds and microseconds members 
+ * of the struct are set to zero.
  *
  * @return  psTime*: Struct with empty time.
@@ -99,6 +100,6 @@
 /** Get current time.
  *
- * Gets current time from the system clock. User must specify the psTimeType (PS_TIME_TAI or PS_TIME_UTC) in
- * the argument.
+ * Gets current time from the system clock. User must specify the psTimeType 
+ * (PS_TIME_TAI or PS_TIME_UTC) in the argument.
  *
  *  @return  psTime*: Struct with current time.
@@ -121,12 +122,12 @@
 /** Convert psTime to Local Mean Sidereal Time (LMST).
  *
- *  Converts psTime at the given longitude to LMST time. If the input time is not in UTC format, then it is
- *  converted.
- *
- *  @return  double: LST Time.
- */
-double psTimeToLMST(
+ *  Converts psTime at the given longitude to LMST time. If the input time is not 
+ *  in UTC format, then it is converted.
+ *
+ *  @return  psF64: LST Time.
+ */
+psF64 psTimeToLMST(
     psTime *time,                       ///< psTime to be converted.
-    double longitude                    ///< Longitude.
+    psF64 longitude                    ///< Longitude.
 );
 
@@ -135,20 +136,21 @@
  *  This function is necessary to for various SLALIB functions.
  *
- *  @return  double: Time difference.
- */
-double psTimeGetUT1Delta(
+ *  @return  psF64: Time difference.
+ */
+psF64 psTimeGetUT1Delta(
+    const psTime *time,                 ///< psTime to be looked up.
+    psTimeBulletin bulletin             ///< IERS bulletin to use
+);
+
+/** Determine TAI - UTC from table lookup.
+ *
+ *  This function is necessary to for various psTime functions.
+ *
+ *  @return  psF64: Time difference.
+ */
+psF64 p_psTimeGetTAIDelta(
     const psTime *time                  ///< psTime to be looked up.
 );
 
-/** Determine TAI - UTC from table lookup.
- *
- *  This function is necessary to for various psTime functions.
- *
- *  @return  double: Time difference.
- */
-double psTimeGetTAIDelta(
-    const psTime *time                  ///< psTime to be looked up.
-);
-
 /** Determine polar coordinates at a given time.
  *
@@ -157,6 +159,6 @@
  *  @return  psSphere*: Spherical coordinates of Earth's polar axias.
  */
-struct psSphere* psTimeGetPoleCoords(
-                const psTime *time                  ///< psTime determine polar orientation.
+struct psSphere* p_psTimeGetPoleCoords(
+                const psTime *time      ///< psTime determine polar orientation.
             );
 
@@ -172,20 +174,32 @@
 );
 
+/** Determine if UTC time is a leapsecond.
+ *
+ *  Determines if the specified UTC time is a valid leapsecond.
+ *
+ *  @return  psBool: valid leap second
+ */
+psBool psTimeIsLeapSecond(
+    const psTime* utc                  ///< UTC to verify if leap second
+);
+
 /** Convert psTime to Julian date time.
  *
- *  Converts psTime to Julian date (JD) time. This function does not add or subtract leapseconds.
- *
- *  @return  double: Julian Date (JD) time.
- */
-double psTimeToJD(
+ *  Converts psTime to Julian date (JD) time. This function does not add or 
+ *  subtract leapseconds.
+ *
+ *  @return  psF64: Julian Date (JD) time.
+ */
+psF64 psTimeToJD(
     const psTime* time                  ///< Input time to be converted.
 );
 /** Convert psTime to modified Julian date time.
  *
- *  Converts psTime to modified Julian date (MJD) time. This function does not add or subtract leapseconds.
- *
- *  @return  double: Modified Julian Days (MJD) time.
- */
-double psTimeToMJD(
+ *  Converts psTime to modified Julian date (MJD) time. This function does not 
+ *  add or subtract leapseconds.
+ *
+ *  @return  psF64: Modified Julian Days (MJD) time.
+ */
+psF64 psTimeToMJD(
     const psTime* time                  ///< Input time to be converted.
 );
@@ -193,6 +207,6 @@
 /** Convert psTime to ISO8601 formatted string.
  *
- *  Converts psTime to a null terminated string in the form of YYYY-MM-DDThh:mm:ss.sss. This function does not
- *  add or subtract leapseconds.
+ *  Converts psTime to a null terminated string in the form of YYYY-MM-DDThh:mm:ss.sss. 
+ *  This function does not add or subtract leapseconds.
  *
  *  @return  char*: Pointer null terminated array of chars in ISO time.
@@ -206,21 +220,23 @@
  *  Converts psTime to timeval time. This function does not add or subtract leapseconds.
  *
- *  @return  timeval: timeval struct time.
- */
-struct timeval psTimeToTimeval(
-                const psTime* time                  ///< Input time to be converted.
+ *  @return  timeval*: timeval struct time.
+ */
+struct timeval* psTimeToTimeval(
+                const psTime* time     ///< Input time to be converted.
             );
 
-/** Convert psTime to tm time.
- *
- * Converts psTime to tm time. This function is based on a Perl algorithm availble in the Pan-STARRS Image
- * processing Algorithm Design Description (ADD). This function does not add or subtract leapseconds.
+/*
+ * Convert psTime to tm time.
+ *
+ * Converts psTime to tm time. This function is based on a Perl algorithm availble 
+ * in the Pan-STARRS Image processing Algorithm Design Description (ADD). This function 
+ * does not add or subtract leapseconds.
  *
  *  @return  tm: tm struct time.
- */
-struct tm* psTimeToTM(
-                const psTime *time                  ///< Input time to be converted.
+ *
+struct tm* p_psTimeToTM(
+                const psTime *time     ///< Input time to be converted.
             );
-
+*/
 /** Convert JD to psTime.
  *
@@ -230,5 +246,5 @@
  */
 psTime* psTimeFromJD(
-    double time                         ///< Input time to be converted.
+    psF64 time                       ///< Input time to be converted.
 );
 
@@ -240,5 +256,5 @@
  */
 psTime* psTimeFromMJD(
-    double time                         ///< Input time to be converted.
+    psF64 time                      ///< Input time to be converted.
 );
 
@@ -250,5 +266,5 @@
  */
 psTime* psTimeFromISO(
-    const char* time                    ///< Input time to be converted.
+    const char* time                 ///< Input time to be converted.
 );
 
@@ -260,16 +276,40 @@
  */
 psTime* psTimeFromTimeval(
-    const struct timeval *time          ///< Input time to be converted.
+    const struct timeval *time       ///< Input time to be converted.
+);
+
+/** Convert Terrestrial Time to psTime
+ *
+ *  Converts Terrestial Time to psTime.  This function assumes resultant time is of type TT.
+ *
+ *  @return psTime*: time (TT)
+ */
+psTime* psTimeFromTT(
+    psS64 sec,                      ///< Input terrestrial time in seconds
+    psU32 nsec                      ///< Input terrestrial time fraction of seconds (nanoseconds)
+);
+
+/** Convert UTC time to psTime
+ *
+ *  Converts UTC time to psTime.  It will verify if time specified is a leapsecond.
+ *
+ *  @return psTime*: time (UTC)
+ */
+psTime* psTimeFromUTC(
+    psS64  sec,                    ///< Input time in seconds
+    psU32  nsec,                   ///< Input time fraction of seconds (nanoseconds)
+    psBool leapsecond              ///< Input time is a leapsecond
 );
 
 /** Convert tm time to psTime.
  *
- *  Converts tm time to psTime. This function is based on a Perl algorithm availble in the Pan-STARRS Image
- * processing Algorithm Design Description (ADD). This function does not add or subtract leapseconds.
+ *  Converts tm time to psTime. This function is based on a Perl algorithm availble 
+ *  in the Pan-STARRS Image processing Algorithm Design Description (ADD). This function 
+ *  does not add or subtract leapseconds.
  *
  *  @return  psTime*: time.
  */
-psTime* psTimeFromTM(
-    const struct tm *time               ///< Input time to be converted.
+psTime* p_psTimeFromTM(
+    const struct tm *time            ///< Input time to be converted.
 );
 
@@ -281,6 +321,6 @@
  */
 psTime* psTimeMath(
-    const psTime *time,                 ///< Time.
-    psF64 delta                         ///< Time delta.
+    const psTime *time,              ///< Time.
+    psF64 delta                      ///< Time delta.
 );
 
@@ -292,6 +332,6 @@
  */
 psF64 psTimeDelta(
-    const psTime *time1,                ///< First time.
-    const psTime *time2                 ///< Second time.
+    const psTime *time1,             ///< First time.
+    const psTime *time2              ///< Second time.
 );
 
Index: /trunk/psLib/src/astronomy/psAstrometry.c
===================================================================
--- /trunk/psLib/src/astronomy/psAstrometry.c	(revision 4050)
+++ /trunk/psLib/src/astronomy/psAstrometry.c	(revision 4051)
@@ -8,6 +8,6 @@
  *  @author GLG, MHPCC
  *
- *  @version $Revision: 1.66 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2005-05-25 20:26:55 $
+ *  @version $Revision: 1.67 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2005-05-31 21:47:46 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -409,10 +409,10 @@
 
     double date = psTimeToMJD(exp->time);
-    double dut = psTimeGetUT1Delta(exp->time);
+    double dut = psTimeGetUT1Delta(exp->time,PS_IERS_A);
     double elongm = exp->observatory->longitude;
     double phim = exp->observatory->latitude;
     double hm = exp->observatory->height;
 
-    psSphere* polarMotion = psTimeGetPoleCoords(exp->time);
+    psSphere* polarMotion = p_psTimeGetPoleCoords(exp->time);
     double xp = polarMotion->r;
     double yp = polarMotion->d;
Index: /trunk/psLib/src/astronomy/psTime.c
===================================================================
--- /trunk/psLib/src/astronomy/psTime.c	(revision 4050)
+++ /trunk/psLib/src/astronomy/psTime.c	(revision 4051)
@@ -10,6 +10,6 @@
  *  @author Ross Harman, MHPCC
  *
- *  @version $Revision: 1.61 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2005-05-25 20:26:55 $
+ *  @version $Revision: 1.62 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2005-05-31 21:47:46 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -24,4 +24,5 @@
 #include "psTime.h"
 #include "psError.h"
+#include "psLogMsg.h"
 #include "psMemory.h"
 #include "psAbort.h"
@@ -69,9 +70,30 @@
                 static psMetadata *timeMetadata = NULL;
 
+// Offset to convert terrestrial time(TT) to international atomic time(TAI)
+#define  TAI_TT_OFFSET_SECONDS        32
+#define  TAI_TT_OFFSET_NANOSECONDS    184000000
+
+// Offset from converting to MJD
+#define  MJD_EPOCH_OFFSET             40587.0
+
+// Offset for converting to JD
+#define  JD_EPOCH_OFFSET              2440587.5
+
+// Offset of year 0000 from epoch
+#define YEAR_0000_SEC                 -62125920000.0
+
+// Offset of year 9999 from epoch
+#define YEAR_9999_SEC                 253202544000.0
+
 /** Static function prototypes */
 static char *cleanString(char *inString, int sLen);
 static char* getToken(char **inString, char *delimiter, psParseErrorType *status);
-psF64 searchTables(psF64 index, psU64 column, psLookupStatusType *status, char *metadataTableNames[], psU32 nTables);
-
+static psF64 searchTables(psF64 index, psU64 column, char *metadataTableNames[],
+                          psU32 nTables, psLookupStatusType* status);
+static psTime* convertTimeTAIUTC(psTime* time);
+static psTime* convertTimeUTCTAI(psTime* time);
+static psTime* convertTimeTAITT(psTime* time);
+static psTime* convertTimeTTTAI(psTime* time);
+static psTime* convertTimeUTCUT1(psTime* time);
 
 /** Removes leading and trailing whitespace and # characters from a string. The cleaned string is a new null
@@ -83,14 +105,13 @@
     char *cleaned = NULL;
 
-
     ptrB = inString;
 
-    /* Skip over leading # or whitespace */
+    // Skip over leading # or whitespace
     while (isspace(*ptrB) || *ptrB=='#') {
         ptrB++;
     }
 
-    /* Skip over trailing whitespace, null terminators, and # characters */
-    ptrE = inString + sLen;
+    // Skip over trailing whitespace, null terminators, and # characters
+    ptrE = inString + sLen - 1;
     while(isspace(*ptrE) || *ptrE=='\0' || *ptrE=='#') {
         ptrE--;
@@ -113,5 +134,4 @@
     int sLen = 0;
 
-
     // Skip over leading whitespace
     while(isspace(**inString)) {
@@ -121,4 +141,5 @@
     // Length of token, not including delimiter
     sLen = strcspn(*inString, delimiter);
+
     if(sLen) {
 
@@ -127,5 +148,6 @@
 
         // Move to end of token
-        (*inString) += sLen;
+        (*inString) += (sLen+1);
+
     } else if(**inString!='\0' && sLen==0) {
         *status = PS_PARSE_ERROR_GENERAL;
@@ -148,45 +170,58 @@
 
 
-/** Searches time tables in priority order and performs interpolation if input index value is within a table.
- * If the index value is out of range, the status is set accordingly. */
-psF64 searchTables(psF64 index, psU64 column, psLookupStatusType *status, char *metadataTableNames[], psU32 nTables)
-{
-    psU32 i = 0;
-    char *tableName = NULL;
-    psF64 result = 0.0;
-    psLookupTable *table = NULL;
-    psMetadataItem *tableMetadataItem = NULL;
-
-
+// Searches time tables in priority order and performs interpolation if input index value is within a table.
+// If the index value is out of range, the status is set accordingly.
+static psF64 searchTables(psF64 index, psU64 column, char *metadataTableNames[],
+                          psU32 nTables, psLookupStatusType* status)
+{
+    char*            tableName          = NULL;
+    psF64            result             = NAN;
+    psLookupTable*   table              = NULL;
+    psMetadataItem*  tableMetadataItem  = NULL;
 
     // Check time metadata. Function call reports errors.
     if(timeMetadata == NULL) {
         if(!p_psTimeInit(p_psGetConfigFileName()))
-            return 0.0;
-    }
-
-    // Search each table in priority order: ser7, eopc,finals
-    for(i=0; i<nTables; i++) {
-
-        // Get table from metadata
+            *status = PS_LOOKUP_ERROR;
+        return NAN;
+    }
+
+    // Search each table in priority order: daily, eopc,finals
+    for(psS32 i = 0; i < nTables; i++) {
+
+        // Get table name from list of tables to search
         tableName = metadataTableNames[i];
+
+        // Lookup table name in time metadata
         tableMetadataItem = psMetadataLookup(timeMetadata, tableName);
+
+        // Check if table not a metadata item
         if(tableMetadataItem == NULL) {
             psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_LOOKUP_METADATA_FAILED,
                     tableName);
-            return 0.0;
-        }
+            *status = PS_LOOKUP_ERROR;
+            return NAN;
+        }
+
+        // Get table from metadata
         table = (psLookupTable*)tableMetadataItem->data.V;
-        PS_ASSERT_PTR_NON_NULL(table,0.0);
-
-        // Attempt to interpolate table
-        *status = PS_LOOKUP_SUCCESS;
-        result = psLookupTableInterpolate(table, index, 2, status);
-        if(*status == PS_LOOKUP_SUCCESS) {
-            return result;
-        } else if(*status == PS_LOOKUP_ERROR) {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_INTERPOLATION_FAILED_NAME,
-                    tableName);
-            return 0.0;
+
+        // Check that table is not NULL
+        PS_ASSERT_PTR_NON_NULL(table,NAN);
+
+        // Check if index within to/from range
+        if(index >= table->validFrom ) {
+            if(index <= table->validTo) {
+                // Attempt to interpolate table
+                result = psLookupTableInterpolate(table, index, column);
+                *status = PS_LOOKUP_SUCCESS;
+                if(!isnan(result)) {
+                    break;
+                }
+            } else {
+                *status = PS_LOOKUP_PAST_BOTTOM;
+            }
+        } else {
+            *status = PS_LOOKUP_PAST_TOP;
         }
     }
@@ -197,10 +232,14 @@
 bool p_psTimeInit(const char *fileName)
 {
+    psS32 numLines = 0;
     bool foundTable = false;
     char *tableDir = NULL;
     char *tableNames = NULL;
+    char *tableFormats = NULL;
     char *namesPtr = NULL;
+    char *formatPtr = NULL;
     char *metadataNamesPtr = NULL;
     char *tableName = NULL;
+    char *tableFormat = NULL;
     char *fullTableName = NULL;
     psS32 i = 0;
@@ -210,8 +249,9 @@
     psVector *tablesFrom = NULL;
     psVector *tablesTo = NULL;
+    psVector *tablesIndex = NULL;
     psMetadataItem *metadataItem = NULL;
     psLookupTable *table = NULL;
     psParseErrorType status = PS_PARSE_SUCCESS;
-    char metadataTableNames[4][MAX_STRING_LENGTH] = {"ser7", "eopc",  "finals", "tai"};
+    char metadataTableNames[4][MAX_STRING_LENGTH] = {"daily", "eopc",  "finals", "tai"};
 
     // Read time config file
@@ -251,4 +291,5 @@
         psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_LOOKUP_METADATA_FAILED,
                 "psLib.time.tables.to");
+        psFree(tablesFrom);
         return false;
     }
@@ -258,4 +299,22 @@
         psFree(tablesFrom);
         psFree(tablesTo);
+        return false;
+    }
+
+    // Get index columns for the tables
+    metadataItem = psMetadataLookup(timeMetadata, "psLib.time.tables.index");
+    if(metadataItem == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE,true,PS_ERRORTEXT_psTime_LOOKUP_METADATA_FAILED,
+                "psLib.time.tables.index");
+        psFree(tablesFrom);
+        psFree(tablesTo);
+        return false;
+    }
+    tablesIndex = psVectorCopy(tablesIndex, metadataItem->data.V, PS_TYPE_S32);
+    if(tablesIndex->n != numTables) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE,true,PS_ERRORTEXT_psTime_BAD_VECTOR,tablesIndex->n,numTables);
+        psFree(tablesFrom);
+        psFree(tablesTo);
+        psFree(tablesIndex);
         return false;
     }
@@ -268,4 +327,5 @@
         psFree(tablesFrom);
         psFree(tablesTo);
+        psFree(tablesIndex);
         return false;
     }
@@ -280,8 +340,24 @@
         psFree(tablesFrom);
         psFree(tablesTo);
+        psFree(tablesIndex);
         psFree(tableDir);
         return false;
     }
     tableNames = psStringCopy(metadataItem->data.V);
+
+    // Get table format strings
+    metadataItem = psMetadataLookup(timeMetadata, "psLib.time.tables.format");
+    if(metadataItem == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE,true, PS_ERRORTEXT_psTime_LOOKUP_METADATA_FAILED,
+                "psLib.time.tables.format");
+        psFree(tablesFrom);
+        psFree(tablesTo);
+        psFree(tablesIndex);
+        psFree(tableDir);
+        psFree(tableNames);
+        return false;
+    }
+    tableFormats = psStringCopy(metadataItem->data.V);
+    formatPtr = tableFormats;
 
     // Read time tables
@@ -289,5 +365,6 @@
     while((tableName=getToken(&namesPtr, " ", &status)) != NULL) {
 
-        // Form path with table name, adding one to length for last '/' that may not occur in string in cong file
+        // Form path with table name, adding one to length for last '/' that may not occur
+        // in string in cong file
         fullTableName = (char*)psAlloc(strlen(tableDir)+strlen(tableName)+1+1);
 
@@ -298,8 +375,15 @@
         strcat(fullTableName, tableName);
 
+        // Get table format
+        tableFormat = getToken(&formatPtr,",",&status);
+        if(tableFormat == NULL) {
+            psError(PS_ERR_BAD_PARAMETER_VALUE,true,PS_ERRORTEXT_psTime_LOOKUP_METADATA_FAILED,
+                    "psLib.time.tables.format");
+        }
+
         // Create and read table
         if(i < numTables) {
-            table = psLookupTableAlloc(fullTableName, tablesFrom->data.F64[i], tablesTo->data.F64[i]);
-            table = psLookupTableRead(table);
+            table = psLookupTableAlloc(fullTableName, (const char*)tableFormat, tablesIndex->data.S32[i]);
+            numLines = psLookupTableRead(table);
         } else {
             psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_BAD_TABLE_COUNT, i+1, numTables);
@@ -321,4 +405,5 @@
         psFree(fullTableName);
         psFree(tableName);
+        psFree(tableFormat);
         psFree(table);
         i++;
@@ -333,4 +418,6 @@
     psFree(tablesFrom);
     psFree(tablesTo);
+    psFree(tablesIndex);
+    psFree(tableFormats);
 
     return true;
@@ -351,7 +438,7 @@
     psTime *outTime = NULL;
 
-
     // Error checks
-    if(type!=PS_TIME_TAI && type!=PS_TIME_UTC) {
+    if(type!=PS_TIME_TAI && type!=PS_TIME_UTC && type!=PS_TIME_UT1 &&
+            type!=PS_TIME_TT) {
         psError(PS_ERR_BAD_PARAMETER_VALUE, true,
                 PS_ERRORTEXT_psTime_TYPE_UNKNOWN,
@@ -360,6 +447,8 @@
     }
 
+    // Allocate memory for structure
     outTime = (psTime*)psAlloc(sizeof(psTime));
 
+    // Initialize members
     outTime->sec = 0;
     outTime->nsec = 0;
@@ -375,8 +464,13 @@
     psTime *time = NULL;
 
-
     // Allocate psTime struct
     time = psTimeAlloc(type);
 
+    // Verify time structure allocated
+    if(time == NULL) {
+        return NULL;
+    }
+
+    // Get the system time
     if (gettimeofday(&now, (struct timezone *)0) == -1) {
         psError(PS_ERR_OS_CALL_FAILED, true,
@@ -391,5 +485,5 @@
     // Add most leapseconds to UTC time to get TAI time if necessary
     if(type == PS_TIME_TAI) {
-        time->sec += psTimeGetTAIDelta(time);
+        time->sec += p_psTimeGetTAIDelta(time);
     }
 
@@ -397,25 +491,239 @@
 }
 
+static psTime* convertTimeTAIUTC(psTime* time)
+{
+    psF64  deltaTAI     = 0.0;
+    psS64  deltaSec     = 0;
+    psU32  deltaNsec    = 0;
+    psF64  deltaUTC     = 0.0;
+
+    // Determine delta to convert between UTC and TAI
+    deltaTAI = p_psTimeGetTAIDelta(time);
+    deltaSec = (psS64)(deltaTAI);
+    deltaNsec = (psU32)((deltaTAI - (psF64)deltaSec) * 1e9);
+
+    // Determine seconds
+    time->sec -= deltaSec;
+
+    // Check for underflow in nsec
+    if(deltaNsec > time->nsec) {
+        // Borrow second
+        time->nsec += 1e9;
+        time->sec--;
+    }
+
+    // Determine nsec
+    time->nsec -= deltaNsec;
+
+    // Check for overflow in nsec
+    if(time->nsec >= 1e9) {
+        time->nsec -= 1e9;
+        time->sec++;
+    }
+
+    // Set new type
+    time->type = PS_TIME_UTC;
+
+    // Check if leapsecond present in delta
+    deltaUTC = p_psTimeGetTAIDelta(time);
+    if(fabs(deltaTAI-deltaUTC) >= 1.0) {
+        time->sec++;
+    }
+
+    return time;
+}
+
+static psTime* convertTimeUTCTAI(psTime* time)
+{
+    psF64  delta     = 0.0;
+    psS64  deltaSec  = 0;
+    psU32  deltaNsec = 0;
+
+    // Determine delta to convert between UTC and TAI
+    delta = p_psTimeGetTAIDelta(time);
+
+    deltaSec = (psS64)(delta);
+    deltaNsec = (psU32)((delta - (psF64)deltaSec) * 1e9);
+
+    // Determine seconds
+    time->sec += deltaSec;
+
+    // Determine nsec
+    time->nsec += deltaNsec;
+
+    // Check for overflow in nsec
+    if(time->nsec >= 1e9) {
+        time->nsec -= 1e9;
+        time->sec++;
+    }
+
+    // Set new type
+    time->type = PS_TIME_TAI;
+
+    return time;
+}
+
+static psTime* convertTimeTAITT(psTime* time)
+{
+    // Add TT offset
+    time->sec += TAI_TT_OFFSET_SECONDS;
+    time->nsec += TAI_TT_OFFSET_NANOSECONDS;
+
+    // Check for overflow in nsec
+    if(time->nsec >= 1e9) {
+        time->nsec -= 1e9;
+        time->sec++;
+    }
+
+    // Set new type
+    time->type = PS_TIME_TT;
+
+    return time;
+}
+
+static psTime* convertTimeTTTAI(psTime* time)
+{
+    // Subtract TT offset
+    time->sec -= TAI_TT_OFFSET_SECONDS;
+
+    // Check for nsec underflow
+    if(TAI_TT_OFFSET_NANOSECONDS > time->nsec) {
+        // Borrow second
+        time->sec--;
+        time->nsec += 1e9;
+    }
+    time->nsec -= TAI_TT_OFFSET_NANOSECONDS;
+
+    // Check for overflow in nsec
+    if(time->nsec >= 1e9) {
+        time->nsec -= 1e9;
+        time->sec++;
+    }
+
+    // Set new type
+    time->type = PS_TIME_TAI;
+
+    return time;
+}
+
+static psTime* convertTimeUTCUT1(psTime* time)
+{
+    psS64   ut1utc  = 0;
+
+    // Get UT1-UTC value
+    ut1utc = (psS64)(psTimeGetUT1Delta(time,PS_IERS_A) * 1e9);
+
+    // Since UTC is within 0.9 sec of UT1 then nsec member is the member affected
+    if((ut1utc < 0) && (abs(ut1utc) > time->nsec)) {
+        // Borrow from sec
+        time->sec--;
+        if(time->leapsecond) {
+            time->leapsecond = false;
+        } else {
+            time->leapsecond = psTimeIsLeapSecond(time);
+        }
+        // Add to nsec
+        time->nsec += 1e9;
+    }
+    time->nsec += ut1utc;
+
+    // Check for overflow in nsec
+    if(time->nsec >= 1e9) {
+        time->nsec -= 1e9;
+        time->sec++;
+        if(time->leapsecond) {
+            time->leapsecond = false;
+            time->sec--;
+        } else {
+            time->leapsecond = psTimeIsLeapSecond(time);
+        }
+    }
+
+    // Set new type
+    time->type = PS_TIME_UT1;
+
+    return time;
+}
+
 psTime* psTimeConvert(psTime *time, psTimeType type)
 {
-    double delta = 0.0;
-
-
     // Error checks
     PS_ASSERT_PTR_NON_NULL(time,NULL);
-    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,1e9-1,NULL);
-
-    if (time->type == type) { // time already right type.  That was easy!
+    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,(psU32)((1e9)-1),time);
+
+    // If the input type is UT1 then return time and generate error message
+    if(time->type == PS_TIME_UT1) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE,true,"Cannot convert from UT1 time type");
         return time;
     }
 
-    delta = psTimeGetTAIDelta(time);
-
-    if (type == PS_TIME_UTC) {
-        time->sec = time->sec - delta;    // User wants UTC time. Subtract leapseconds.
-    } else if(type == PS_TIME_TAI) {
-        time->sec = time->sec + delta;    // User wants TAI time. Add leapseconds.
+    // If the time to convert to is the same as psTime the return time
+    if (time->type == type) {
+        return time;
+    }
+
+    // Convert from TAI to UTC, TT, UT1
+    if(time->type == PS_TIME_TAI) {
+        // Convert from TAI to UTC
+        if(type == PS_TIME_UTC) {
+            time = convertTimeTAIUTC(time);
+            // Convert from TAI to TT
+        } else if(type == PS_TIME_TT) {
+            time = convertTimeTAITT(time);
+            // Convert from TAI to UT1
+        } else if(type == PS_TIME_UT1) {
+            // Convert to UTC first
+            time = convertTimeTAIUTC(time);
+            // Convert UTC to UT1
+            time = convertTimeUTCUT1(time);
+            // Convert from TAI to unknown time type
+        } else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_TYPE_UNKNOWN, type);
+        }
+        // Convert from TT to TAI, UTC, UT1
+    } else if(time->type == PS_TIME_TT) {
+        // Convert from TT to UTC
+        if(type == PS_TIME_UTC) {
+            // Convert to TAI time first
+            time = convertTimeTTTAI(time);
+            // Convert from TAI to UTC
+            time = convertTimeTAIUTC(time);
+            // Convert from TT to TAI
+        } else if(type == PS_TIME_TAI) {
+            time = convertTimeTTTAI(time);
+            // Convert from TT to UT1
+        } else if(type == PS_TIME_UT1) {
+            // Convert to UTC first
+            // Convert to TAI time first
+            time = convertTimeTTTAI(time);
+            // Convert from TAI to UTC
+            time = convertTimeTAIUTC(time);
+            // Convert from UTC to UT1
+            time = convertTimeUTCUT1(time);
+            // Convert from TT to unknown time type
+        } else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_TYPE_UNKNOWN, type);
+        }
+        // Convert from UTC to TAI, TT, UT1
+    } else if(time->type == PS_TIME_UTC) {
+        // Convert UTC to TAI
+        if(type == PS_TIME_TAI) {
+            time = convertTimeUTCTAI(time);
+            // Convert UTC to TT
+        } else if(type == PS_TIME_TT) {
+            // Convert to TAI time first
+            time = convertTimeUTCTAI(time);
+            // Convert TAI to TT
+            time = convertTimeTAITT(time);
+            // Convert UTC to UT1
+        } else if(type == PS_TIME_UT1) {
+            time = convertTimeUTCUT1(time);
+            // Convert UTC to unknown time type
+        } else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_TYPE_UNKNOWN, type);
+        }
+        // Convert unknown time type
     } else {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_TYPE_UNKNOWN, type);
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_TYPE_UNKNOWN, time->type);
     }
 
@@ -423,5 +731,5 @@
 }
 
-double psTimeToLMST(psTime *time, double longitude)
+psF64 psTimeToLMST(psTime *time, psF64 longitude)
 {
     psF64  jdTdtDays    =  0.0;
@@ -433,5 +741,4 @@
     psF64  t            =  0.0;
     psF64  tu           =  0.0;
-    psF64  ut1UtcDbl    =  0.0;
     psF64  const1       =  24110.5493771;
     psF64  const2       =  8639877.3173760;
@@ -440,34 +747,30 @@
     psF64  const5       = -0.0000062;
     psF64  const6       =  0.0000013;
-    psTime *ut1UtcDelta = NULL;
     psTime *tdtTime     = NULL;
-    psTime *taiTime     = NULL;
-    psTime *utcTime     = NULL;
     psTime *ut1Time     = NULL;
-
 
     // Error checks
     PS_ASSERT_PTR_NON_NULL(time,NAN);
-    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,1e9-1,NAN);
-
-    // Calculate TAI or UTC time based on type of time user passes
-    if(time->type == PS_TIME_TAI) {
-        taiTime = psMemIncrRefCounter(time);
-        utcTime = psTimeAlloc(PS_TIME_UTC);
-        utcTime->sec = taiTime->sec - psTimeGetTAIDelta(time);
-        utcTime->nsec = taiTime->nsec;
-    } else if(time->type == PS_TIME_UTC) {
-        utcTime = psMemIncrRefCounter(time);
-        taiTime = psTimeAlloc(PS_TIME_TAI);
-        taiTime->sec = utcTime->sec + psTimeGetTAIDelta(time);
-        taiTime->nsec = utcTime->nsec;
-    }
-
-    // Convert Universal Time (UTC) to  UT1
-    ut1UtcDbl = psTimeGetUT1Delta(taiTime);
-    utcTime->type = PS_TIME_TAI; // Don't allow addition of leapseconds to ut1Time
-    ut1Time = psTimeMath(utcTime, ut1UtcDbl);
-    utcTime->type = PS_TIME_UTC;
-
+    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,(psU32)((1e9)-1),NAN);
+
+    // Verify input time is not in UT1 seconds
+    if(time->type == PS_TIME_UT1) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE,true,PS_ERRORTEXT_psTime_TYPE_INCORRECT,time->type);
+        return NAN;
+    }
+
+    // Determine time reference to TT
+    tdtTime = psTimeAlloc(time->type);
+    tdtTime->sec = time->sec;
+    tdtTime->nsec = time->nsec;
+    tdtTime->leapsecond = time->leapsecond;
+    tdtTime = psTimeConvert(tdtTime,PS_TIME_TT);
+
+    // Determine time reference to UT1
+    ut1Time = psTimeAlloc(time->type);
+    ut1Time->sec = time->sec;
+    ut1Time->nsec = time->nsec;
+    ut1Time->leapsecond = time->leapsecond;
+    ut1Time = psTimeConvert(ut1Time,PS_TIME_UT1);
 
     // Calculate UT1 as Julian Centuries since J2000.0
@@ -476,7 +779,4 @@
     t = (jdUt1Days - 2451545.0)/36525.0;
 
-    // Calculate Terrestial Dynamical Time (TDT)
-    tdtTime = psTimeMath(taiTime, 32.184);
-
     // Calculate TDT as Julian centuries since J2000.0
     jdTdtDays = psTimeToJD(tdtTime);
@@ -486,6 +786,8 @@
     fracDays = fmod(mjdUt1Days, 1.0);
 
-    // Calculate Greenwich Mean Sidereal Time (GMST) in radians. Equation set up to minimize multiplications.
-    gmstRad = fracDays*TWOPI+(const1+const2*tu+t*(const3+t*(const4+t*(const5+const6*t))))*S2R;
+    // Calculate Greenwich Mean Sidereal Time (GMST) in radians.
+    // Equation set up to minimize multiplications.
+    gmstRad = fracDays*TWOPI
+              + (const1+const2*tu+t*(const3+t*(const4+t*(const5+const6*t))))*S2R;
 
     // Place GMST between 0 and 2*pi
@@ -496,38 +798,43 @@
 
     // Free temporary structs
-    psFree(ut1UtcDelta);
     psFree(ut1Time);
     psFree(tdtTime);
-    psFree(utcTime);
-    psFree(taiTime);
 
     return lmstRad;
 }
 
-double psTimeGetUT1Delta(const psTime *time)
-{
-    psU32 nTables = 3;
-    psF64 mjd = 0.0;
-    psF64 result = 0.0;
-    psF64 dut2ut1 = 0.0;
-    psF64 t = 0.0;
-    psVector *dut = NULL;
-    psMetadataItem *tableMetadataItem = NULL;
-    psLookupStatusType status = PS_LOOKUP_SUCCESS;
-    char *metadataTableNames[3] = {"ser7Table", "eopcTable",  "finalsTable"};
-
+psF64 psTimeGetUT1Delta(const psTime *time, psTimeBulletin bulletin)
+{
+    psU32              nTables               = 2;
+    psF64              mjd                   = 0.0;
+    psF64              result                = 0.0;
+    psU64              tableColumn           = 0;
+    psF64              dut2ut1               = 0.0;
+    psF64              t                     = 0.0;
+    psVector*          dut                   = NULL;
+    psMetadataItem*    tableMetadataItem     = NULL;
+    psLookupStatusType status                = PS_LOOKUP_SUCCESS;
+    char*              metadataTableNames[2] = {"dailyTable",  "finalsTable"};
 
     // Error checks
     PS_ASSERT_PTR_NON_NULL(time,NAN);
-    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,1e9-1,NAN);
-
-    if(time->type != PS_TIME_TAI) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_TYPE_INCORRECT, time->type);
-        return 0.0;
+    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,(psU32)((1e9)-1),NAN);
+
+    // Check for invalid bulletin specified
+    if((bulletin != PS_IERS_A) && (bulletin != PS_IERS_B)) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE,true,"Invalid bulletin specified %d",bulletin);
+        return NAN;
+    }
+
+    // Set lookup table column based on Bullentin
+    if(bulletin == PS_IERS_A) {
+        tableColumn = 3;
+    } else {
+        tableColumn = 6;
     }
 
     // Attempt to find value through table lookup and interpolation
     mjd = psTimeToMJD(time);
-    result = searchTables(mjd, 0, &status, metadataTableNames, nTables);
+    result = searchTables(mjd,tableColumn,metadataTableNames,nTables,&status);
 
     // Value could not be found through table lookup and interpolation
@@ -535,10 +842,12 @@
 
         // Date too early for tables. Get default time delta value from metadata, and issue warning.
-        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_TIME_PREDATES_TABLES, mjd, "UT1-UTC");
-
+        psLogMsg(__func__,PS_LOG_WARN,PS_ERRORTEXT_psTime_TIME_PREDATES_TABLES,mjd,"UT1-UTC");
+
+        // Lookup value from time metadata loaded from psTime.config
         tableMetadataItem = psMetadataLookup(timeMetadata, "psLib.time.before.dut");
         if(tableMetadataItem == NULL) {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_LOOKUP_METADATA_FAILED, "psLib.time.before.dut");
-            return 0.0;
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_LOOKUP_METADATA_FAILED,
+                    "psLib.time.before.dut");
+            return NAN;
         }
         result = tableMetadataItem->data.F64;
@@ -552,14 +861,18 @@
              t = 2000.0 + (MJD - 51544.03)/365.2422
         */
-        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_TIME_POSTDATES_TABLES, mjd, "UT1-UTC");
-
+        // Generate warning of postdate information
+        psLogMsg(__func__,PS_LOG_WARN,PS_ERRORTEXT_psTime_TIME_POSTDATES_TABLES, mjd, "UT1-UTC");
+
+        // Lookup values to calculate prediction
         tableMetadataItem = psMetadataLookup(timeMetadata, "psLib.time.predict.dut");
         if(tableMetadataItem == NULL) {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_LOOKUP_METADATA_FAILED, "psLib.time.predict.dut");
-            return 0.0;
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_LOOKUP_METADATA_FAILED,
+                    "psLib.time.predict.dut");
+            return NAN;
         }
         dut = (psVector*)tableMetadataItem->data.V;
-        PS_ASSERT_PTR_NON_NULL(dut,0.0);
-
+        PS_ASSERT_PTR_NON_NULL(dut,NAN);
+
+        // Calculate predication of future UT1-UTC
         t = 2000.0 + (mjd - 51544.03)/365.2422;
         dut2ut1 = 0.022*sin(TWOPI*t) - 0.012*cos(TWOPI*t) - 0.006*sin(4.0*M_PI*t) + 0.007*cos(4.0*M_PI*t);
@@ -568,5 +881,5 @@
     } else if(status != PS_LOOKUP_SUCCESS) {
         psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_INTERPOLATION_FAILED);
-        return 0.0;
+        return NAN;
     }
 
@@ -574,5 +887,5 @@
 }
 
-struct psSphere* psTimeGetPoleCoords(const psTime* time)
+struct psSphere* p_psTimeGetPoleCoords(const psTime* time)
 {
     psU32 nTables = 3;
@@ -587,5 +900,5 @@
     psLookupStatusType yStatus = PS_LOOKUP_SUCCESS;
     psMetadataItem *tableMetadataItem = NULL;
-    char *metadataTableNames[3] = {"ser7Table", "eopcTable",  "finalsTable"};
+    char *metadataTableNames[3] = {"dailyTable", "eopcTable",  "finalsTable"};
     psVector *xp = NULL;
     psVector *yp = NULL;
@@ -593,5 +906,5 @@
     // Error checks
     PS_ASSERT_PTR_NON_NULL(time,NULL);
-    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,1e9-1,NULL);
+    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,(psU32)((1e9)-1),NULL);
 
     if(time->type != PS_TIME_TAI)
@@ -603,6 +916,8 @@
     // Attempt to find value through table lookup and interpolation
     mjd = psTimeToMJD(time);
-    x = searchTables(mjd, 0, &xStatus, metadataTableNames, nTables);
-    y = searchTables(mjd, 0, &yStatus, metadataTableNames, nTables);
+    //    x = searchTables(mjd, 0, &xStatus, metadataTableNames, nTables);
+    x = searchTables(mjd, 0, metadataTableNames, nTables,&xStatus);
+    //    y = searchTables(mjd, 0, &yStatus, metadataTableNames, nTables);
+    y = searchTables(mjd, 0, metadataTableNames, nTables,&yStatus);
 
     // Value could not be found through table lookup and interpolation
@@ -641,5 +956,4 @@
         psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_TIME_POSTDATES_TABLES, mjd, "polar motion");
 
-
         // Get predicted MJD
         tableMetadataItem = psMetadataLookup(timeMetadata, "psLib.time.predict.mjd");
@@ -692,5 +1006,5 @@
     }
 
-    // Create output sphere and convert arcsec to radians (i.e. x/60/60*M_PI/180)
+    // Create output sphere and convert arcsec to radians (i.e. x/60/60*PS_PI/180)
     output = psAlloc(sizeof(psSphere));
     output->r = x * M_PI / 648000.0;
@@ -700,7 +1014,6 @@
 }
 
-double psTimeGetTAIDelta(const psTime *time)
-{
-    psU64 i = 0;
+psF64 p_psTimeGetTAIDelta(const psTime *time)
+{
     psF64 jd = 0.0;
     psF64 mjd = 0.0;
@@ -711,10 +1024,9 @@
     psLookupTable* table = NULL;
     psMetadataItem *tableMetadataItem = NULL;
-    psVector *stats = NULL;
     psVector *results = NULL;
 
     // Error checks
     PS_ASSERT_PTR_NON_NULL(time,NAN);
-    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,1e9-1,NAN);
+    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,(psU32)((1e9)-1),NAN);
 
     // Check time metadata
@@ -739,20 +1051,29 @@
     mjd = psTimeToMJD(time);
 
-    stats = psVectorAlloc(table->numCols, PS_TYPE_U32);
-    results = psLookupTableInterpolateAll(table, jd, stats);
+    // Set ceiling of the julian date to the last entry in the lookup table
+    if(table->validTo < jd) {
+        jd = table->validTo;
+    }
+
+    // Interpolation of look up table
+    results = psLookupTableInterpolateAll(table, jd);
 
     // Check for successful interpolation
-    for(i=0; i<stats->n; i++) {
-        if(stats->data.U32[i] == PS_LOOKUP_ERROR) {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_INTERPOLATION_FAILED);
-        }
-    }
-
-    const1 = results->data.F64[0];
-    const2 = results->data.F64[1];
-    const3 = results->data.F64[2];
-    out = const1 + (mjd - const2) * const3;
-
-    psFree(stats);
+    if(results == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_INTERPOLATION_FAILED);
+    }
+
+    // Set constants from table
+    const1 = results->data.F64[1];
+    const2 = results->data.F64[2];
+    const3 = results->data.F64[3];
+
+    // If const3 not equal to zero solve for difference else floor of const1
+    if(fabs(const3-0.0) > FLT_EPSILON) {
+        out = const1 + (mjd - const2) * const3;
+    } else {
+        out = floor(const1);
+    }
+
     psFree(results);
 
@@ -760,33 +1081,64 @@
 }
 
-
 psS64 psTimeLeapSecondDelta(const psTime *time1, const psTime *time2)
 {
     psS64 diff = 0;
-
 
     // Error checks
     PS_ASSERT_PTR_NON_NULL(time1,0);
     PS_ASSERT_PTR_NON_NULL(time2,0);
-    PS_ASSERT_INT_WITHIN_RANGE(time1->nsec,0,1e9-1,0);
-    PS_ASSERT_INT_WITHIN_RANGE(time2->nsec,0,1e9-1,0);
-    diff = abs((psS64)psTimeGetTAIDelta((psTime*)time1)-(psS64)psTimeGetTAIDelta((psTime*)time2));
+    PS_ASSERT_INT_WITHIN_RANGE(time1->nsec,0,(psU32)((1e9)-1),0);
+    PS_ASSERT_INT_WITHIN_RANGE(time2->nsec,0,(psU32)((1e9)-1),0);
+    diff = abs((psS64)p_psTimeGetTAIDelta((psTime*)time1)-(psS64)p_psTimeGetTAIDelta((psTime*)time2));
 
     return diff;
 }
 
-double psTimeToJD(const psTime *time)
-{
-    double jd = 0.0;
+psBool psTimeIsLeapSecond(const psTime* utc)
+{
+    psTime*    prevUtc     = NULL;
+    psBool     returnValue = false;
+
+    // Check for valid time
+    PS_ASSERT_PTR_NON_NULL(utc,false);
+
+    // Verify time is UTC type
+    if(utc->type != PS_TIME_UTC) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE,true,PS_ERRORTEXT_psTime_TYPE_INCORRECT,utc->type);
+        return false;
+    }
+
+    // Allocate time to hold utc - 1 second
+    prevUtc = psTimeAlloc(PS_TIME_UTC);
+    prevUtc->sec = utc->sec - 1;
+
+    // Check the absolute difference between the two times for leapsecond
+    if(psTimeLeapSecondDelta(utc,prevUtc) >= 1.0) {
+        returnValue = true;
+    } else {
+        returnValue = false;
+    }
+
+    // Free prevUtc
+    psFree(prevUtc);
+
+    return returnValue;
+}
+
+psF64 psTimeToJD(const psTime *time)
+{
+    psF64 jd = NAN;
 
     // Error checks
     PS_ASSERT_PTR_NON_NULL(time,NAN);
-    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,1e9-1,NAN);
+    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,(psU32)((1e9)-1),NAN);
 
     // Julian date conversion
     if(time->sec < 0) {
-        jd = time->sec / SEC_PER_DAY - time->nsec / NSEC_PER_DAY + 2440587.5; // psTime earlier than epoch
+        // psTime earlier than epoch
+        jd = time->sec / SEC_PER_DAY - time->nsec / NSEC_PER_DAY + JD_EPOCH_OFFSET;
     } else {
-        jd = time->sec / SEC_PER_DAY + time->nsec / NSEC_PER_DAY + 2440587.5; // psTime greater than epoch
+        // psTime greater than epoch
+        jd = time->sec / SEC_PER_DAY + time->nsec / NSEC_PER_DAY + JD_EPOCH_OFFSET;
     }
 
@@ -794,18 +1146,19 @@
 }
 
-double psTimeToMJD(const psTime *time)
-{
-    double mjd = 0.0;
-
+psF64 psTimeToMJD(const psTime *time)
+{
+    psF64 mjd = NAN;
 
     // Error checks
     PS_ASSERT_PTR_NON_NULL(time,NAN);
-    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,1e9-1,NAN);
+    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,(psU32)((1e9)-1),NAN);
 
     // Modified Julian date conversion
     if(time->sec < 0) {
-        mjd = time->sec / SEC_PER_DAY - time->nsec / NSEC_PER_DAY + 40587.0; // psTime earlier than epoch
+        // psTime earlier than epoch
+        mjd = time->sec / SEC_PER_DAY - time->nsec / NSEC_PER_DAY + MJD_EPOCH_OFFSET;
     } else {
-        mjd = time->sec / SEC_PER_DAY + time->nsec / NSEC_PER_DAY + 40587.0; // psTime greater than epoch
+        // psTime greater than epoch
+        mjd = time->sec / SEC_PER_DAY + time->nsec / NSEC_PER_DAY + MJD_EPOCH_OFFSET;
     }
 
@@ -815,5 +1168,5 @@
 char* psTimeToISO(const psTime *time)
 {
-    psS32 ms = 0;
+    psS32 ds = 0;
     char *timeString = NULL;
     char *tempString = NULL;
@@ -821,14 +1174,23 @@
     time_t sec;
 
-
     // Error checks
     PS_ASSERT_PTR_NON_NULL(time,NULL);
-    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,1e9-1,NULL);
-
+    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,(psU32)((1e9)-1),NULL);
+
+    // Check valid year range
+    PS_ASSERT_LONG_WITHIN_RANGE(time->sec,YEAR_0000_SEC,YEAR_9999_SEC,NULL)
+
+    // Allocate temp strings
     tempString = psAlloc(MAX_TIME_STRING_LENGTH);
     timeString = psAlloc(MAX_TIME_STRING_LENGTH);
 
-    ms = time->nsec / 1000000;
+    // Convert nanoseconds to decaseconds
+    ds = time->nsec / 100000000;
     sec = time->sec;
+
+    // If leapsecond use previous day
+    if(time->leapsecond) {
+        sec--;
+    }
 
     // tmTime variable is statically allocated, no need to free
@@ -840,5 +1202,13 @@
     }
 
-    if (snprintf(timeString, MAX_TIME_STRING_LENGTH, "%s.%3.3dZ", tempString, ms) < 0) {
+    // Check if time is UTC and leapsecond
+    if(((time->type==PS_TIME_UTC)||(time->type==PS_TIME_UT1)) && (time->leapsecond)) {
+        // Modify second to be 60
+        tempString[17] = '6';
+        tempString[18] = '0';
+    }
+
+    // Create string with milliseconds
+    if (snprintf(timeString, MAX_TIME_STRING_LENGTH, "%s,%1dZ", tempString, ds) < 0) {
         psError(PS_ERR_OS_CALL_FAILED, true, PS_ERRORTEXT_psTime_APPEND_MSEC_FAILED);
     }
@@ -848,22 +1218,25 @@
 }
 
-struct timeval psTimeToTimeval(const psTime *time)
-{
-    struct timeval timevalTime;
-
-    timevalTime.tv_sec = 0;
-    timevalTime.tv_usec = 0;
+struct timeval* psTimeToTimeval(const psTime *time)
+{
+    struct timeval  *timevalTime = NULL;
 
     // Error checks
-    PS_ASSERT_PTR_NON_NULL(time,timevalTime);
-    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,1e9-1,timevalTime);
-
-    timevalTime.tv_sec = time->sec;
-    timevalTime.tv_usec = time->nsec / 1000;
+    PS_ASSERT_PTR_NON_NULL(time,NULL);
+    PS_ASSERT_INT_WITHIN_RANGE(time->sec,0,INT32_MAX,NULL);
+    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,(psU32)((1e9)-1),NULL);
+
+    // Allocate structure timeval
+    timevalTime = (struct timeval*)psAlloc(sizeof(struct timeval));
+
+    // Set structure members
+    timevalTime->tv_sec = time->sec;
+    timevalTime->tv_usec = time->nsec / 1000;
 
     return timevalTime;
 }
 
-struct tm* psTimeToTM(const psTime *time)
+/*
+struct tm* p_psTimeToTM(const psTime *time)
 {
     psS64 cent = 0;
@@ -876,15 +1249,15 @@
     psS64 temp = 0;
     struct tm* tmTime = NULL;
-
-
+ 
+ 
     // Error checks
     PS_ASSERT_PTR_NON_NULL(time,NULL);
-    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,1e9-1,NULL);
-
+    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,(psU32)((1e9)-1),NULL);
+ 
     seconds = time->sec%60;
     minute = time->sec/60%60;
     hour = time->sec/3600%24;
     day = (time->sec+62135596800)/86400;
-
+ 
     // Add 306 days to make relative to Mar 1, 0; also adjust day to be within a range (1..2**28-1) where our
     // calculations will work with 32bit ints
@@ -898,5 +1271,5 @@
         day -= temp * 146097;
     }
-
+ 
     cent = (day*4-1)/146097;                        // Calc number of centuries day is after 29 Feb of yr 0
     day -= cent*146097/4;                           // 4 centuries = 146097 days
@@ -906,5 +1279,5 @@
     day -= (month*367-1094)/12;                     // February of following year)
     year += cent*100+temp*400;                      // Get the real year, which is off by
-
+ 
     // One if month is January or February
     if(month > 12)
@@ -913,8 +1286,8 @@
         month -= 12;
     }
-
+ 
     // Allocate output
     tmTime = (struct tm*)psAlloc(sizeof(struct tm));
-
+ 
     tmTime->tm_year = year - 1900;
     tmTime->tm_mon = month - 1;
@@ -924,14 +1297,14 @@
     tmTime->tm_sec = seconds;
     tmTime->tm_isdst = -1;
-
+ 
     return tmTime;
 }
-
-psTime* psTimeFromJD(double time)
-{
-    double days = 0.0;
-    double seconds = 0.0;
+*/
+
+psTime* psTimeFromJD(psF64 time)
+{
+    psF64 days = 0.0;
+    psF64 seconds = 0.0;
     psTime *outTime = NULL;
-
 
     // Allocate psTime struct
@@ -949,15 +1322,14 @@
 
     // Error check
-    PS_ASSERT_INT_WITHIN_RANGE(outTime->nsec,0,1e9-1,outTime);
+    PS_ASSERT_INT_WITHIN_RANGE(outTime->nsec,0,(psU32)((1e9)-1),outTime);
 
     return outTime;
 }
 
-psTime* psTimeFromMJD(double time)
-{
-    double days = 0.0;
-    double seconds = 0.0;
+psTime* psTimeFromMJD(psF64 time)
+{
+    psF64 days = 0.0;
+    psF64 seconds = 0.0;
     psTime *outTime = NULL;
-
 
     // Allocate psTime struct
@@ -967,4 +1339,5 @@
     days = time - 40587.0;
     seconds = days * SEC_PER_DAY;
+
     if(seconds < 0.0) {
         outTime->nsec = (seconds - (psS64)seconds) * -1000000000.0;  // psTime earlier than epoch
@@ -975,5 +1348,5 @@
 
     // Error check
-    PS_ASSERT_INT_WITHIN_RANGE(outTime->nsec,0,1e9-1,outTime);
+    PS_ASSERT_INT_WITHIN_RANGE(outTime->nsec,0,(psU32)((1e9)-1),NULL);
 
     return outTime;
@@ -986,6 +1359,9 @@
     psTime *outTime = NULL;
 
+    // Check for NULL string
+    PS_ASSERT_PTR_NON_NULL(time,NULL);
+
     // Convert YYYY-MM-DDThh:mm:ss.sss in string form to tm time
-    if (sscanf(time, "%d-%d-%dT%d:%d:%d.%d", &tmTime.tm_year, &tmTime.tm_mon, &tmTime.tm_mday,
+    if (sscanf(time, "%d-%d-%dT%d:%d:%d,%d", &tmTime.tm_year, &tmTime.tm_mon, &tmTime.tm_mday,
                &tmTime.tm_hour, &tmTime.tm_min, &tmTime.tm_sec,&millisecond) < 7) {
         psError(PS_ERR_BAD_PARAMETER_VALUE, true, PS_ERRORTEXT_psTime_ISOTIME_MALFORMED, time);
@@ -1006,6 +1382,44 @@
 
     // Convert tm time to psTime
-    outTime = psTimeFromTM(&tmTime);
+    outTime = p_psTimeFromTM(&tmTime);
     outTime->nsec = millisecond * 1000000;
+
+    return outTime;
+}
+
+psTime* psTimeFromTT(psS64 sec, psU32 nsec)
+{
+    psTime*      outTime  = NULL;
+
+    // Verify nsec within range
+    PS_ASSERT_INT_WITHIN_RANGE(nsec,0,(psU32)((1e9)-1),NULL);
+
+    // Allocate psTime data
+    outTime = psTimeAlloc(PS_TIME_TT);
+
+    // Set data members
+    outTime->sec = sec;
+    outTime->nsec = nsec;
+
+    // Return data structure
+    return outTime;
+}
+
+psTime* psTimeFromUTC(psS64 sec, psU32 nsec, psBool leapsecond)
+{
+    psTime*   outTime   = NULL;
+
+    // Verify nsec within range
+    PS_ASSERT_INT_WITHIN_RANGE(nsec,0,(psU32)((1e9)-1),NULL);
+
+    // Allocate psTime data
+    outTime = psTimeAlloc(PS_TIME_UTC);
+
+    // Set data members
+    outTime->sec = sec;
+    outTime->nsec = nsec;
+
+    // Set leapsecond flag if necessary
+    outTime->leapsecond = psTimeIsLeapSecond(outTime);
 
     return outTime;
@@ -1028,10 +1442,10 @@
 
     // Error check
-    PS_ASSERT_INT_WITHIN_RANGE(outTime->nsec,0,1e9-1,outTime);
+    PS_ASSERT_INT_WITHIN_RANGE(outTime->nsec,0,(psU32)((1e9)-1),outTime);
 
     return outTime;
 }
 
-psTime* psTimeFromTM(const struct tm* time)
+psTime* p_psTimeFromTM(const struct tm* time)
 {
     psS64 year;
@@ -1044,5 +1458,4 @@
     psTime *outTime = NULL;
 
-
     // Error check
     PS_ASSERT_PTR_NON_NULL(time,NULL);
@@ -1062,9 +1475,13 @@
     if( month <= 2 )
     {
-        year -= (temp = (14 - month) / 12);
+        temp = (14 - month) / 12;
+        //        year -= (temp = (14 - month) / 12);
+        year -= temp;
         month += 12 * temp;
     } else if(month > 14)
     {
-        year += (temp = (month - 3) / 12);
+        temp = (month - 3) / 12;
+        //        year += (temp = (month - 3) / 12);
+        year += temp;
         month -= 12 * temp;
     }
@@ -1081,5 +1498,6 @@
     // days to adjust from Mar 1, year 0-relative to Jan 1, year 1-relative. Add hours, minutes, and seconds.
     day += (month * 367 - 1094) / 12 + year % 100 * 1461 / 4 + (year/100 * 36524 + year/400) - 306;
-    outTime->sec = (((day - 1) * SEC_PER_DAY) - 62135596800) + hour*SEC_PER_HOUR + minute*SEC_PER_MINUTE + seconds;
+    outTime->sec = (((day - 1) * SEC_PER_DAY) - 62135596800) + hour*SEC_PER_HOUR
+                   + minute*SEC_PER_MINUTE + seconds;
 
     // C's TM does not define a microsecond field. Microseconds must be manipulated by calling function.
@@ -1087,5 +1505,5 @@
 
     // Error check
-    PS_ASSERT_INT_WITHIN_RANGE(outTime->nsec,0,1e9-1,outTime);
+    PS_ASSERT_INT_WITHIN_RANGE(outTime->nsec,0,(psU32)((1e9)-1),outTime);
 
     return outTime;
@@ -1098,8 +1516,7 @@
     psTime *tempTime = NULL;
 
-
     // Error checks
     PS_ASSERT_PTR_NON_NULL(time,NULL);
-    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,1e9-1,NULL);
+    PS_ASSERT_INT_WITHIN_RANGE(time->nsec,0,(psU32)((1e9)-1),NULL);
 
     // Convert time to TAI if necessary, but without changing input arguments
@@ -1109,16 +1526,18 @@
         tempTime->nsec = time->nsec;
         tempTime = psTimeConvert(tempTime, PS_TIME_TAI);
+        outTime = psTimeAlloc(PS_TIME_TAI);
     } else {
         tempTime = psMemIncrRefCounter((psTime*)time);
+        outTime = psTimeAlloc(time->type);
     }
 
     // Create output time
-    outTime = psTimeAlloc(PS_TIME_TAI);
     sec = delta + (psF64)tempTime->sec + (psF64)tempTime->nsec/1e9;
-    outTime->sec = sec;
-    outTime->nsec = (sec - outTime->sec)*1e9;
+    PS_ASSERT_LONG_WITHIN_RANGE((psS64)sec,0,PS_MAX_S64,outTime);
+    outTime->sec = (psS64)sec;
+    outTime->nsec = (psU32)((sec - (psF64)outTime->sec)*1e9);
 
     // Error check
-    PS_ASSERT_INT_WITHIN_RANGE(outTime->nsec,0,1e9-1,outTime);
+    PS_ASSERT_INT_WITHIN_RANGE(outTime->nsec,0,(psU32)((1e9)-1),outTime);
 
     // Convert result to same time type as input
@@ -1140,10 +1559,15 @@
     psTime *tempTime2 = NULL;
 
-
     // Error checks
     PS_ASSERT_PTR_NON_NULL(time1,0.0);
-    PS_ASSERT_INT_WITHIN_RANGE(time1->nsec,0,1e9-1,0.0);
+    PS_ASSERT_INT_WITHIN_RANGE(time1->nsec,0,(psU32)((1e9)-1),0.0);
     PS_ASSERT_PTR_NON_NULL(time2,0.0);
-    PS_ASSERT_INT_WITHIN_RANGE(time2->nsec,0,1e9-1,0.0);
+    PS_ASSERT_INT_WITHIN_RANGE(time2->nsec,0,(psU32)((1e9)-1),0.0);
+
+    // Verify both times of the same type
+    if(time1->type != time2->type) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE,true,PS_ERRORTEXT_psTime_TYPE_INCORRECT,time1->type);
+        return out;
+    }
 
     // Convert time to TAI if necessary, but without changing input arguments
Index: /trunk/psLib/src/astronomy/psTime.h
===================================================================
--- /trunk/psLib/src/astronomy/psTime.h	(revision 4050)
+++ /trunk/psLib/src/astronomy/psTime.h	(revision 4051)
@@ -1,19 +1,19 @@
 /** @file  psTime.h
  *
- *  @brief Definitions for time, time utilities, and conversion functions for use with psLib astronomy
- *  functions.
- *
- *  A collection of functions are required by psLib to manipulate time data. These functions primarily consist
- *  of conversions between specific time formats.  They use the UNIX timeval time system as the
- *  base upon which International Atomic Time (TAI) and Universal Time Coordinated (UTC) are calculated.
+ *  @brief Definitions for time, time utilities, and conversion functions for use 
+ *  with psLib astronomy functions.
+ *
+ *  A collection of functions are required by psLib to manipulate time data. These 
+ *  functions primarily consist of conversions between specific time formats.  They 
+ *  use the UNIX timeval time system as the base upon which International Atomic 
+ *  Time (TAI) and Universal Time Coordinated (UTC) are calculated.
  *
  *  @author Ross Harman, MHPCC
  *
- *  @version $Revision: 1.28 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2005-04-19 02:44:12 $
+ *  @version $Revision: 1.29 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2005-05-31 21:47:46 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
  */
-
 
 #ifndef PSTIME_H
@@ -88,6 +88,7 @@
 /** Allocate time struct.
  *
- * Allocates an empty time struct. User must specify the psTimeType (PS_TIME_TAI or PS_TIME_UTC) in the argument.
- * The seconds and microseconds members of the struct are set to zero.
+ * Allocates an empty time struct. User must specify the psTimeType 
+ * (PS_TIME_TAI or PS_TIME_UTC) in the argument. The seconds and microseconds members 
+ * of the struct are set to zero.
  *
  * @return  psTime*: Struct with empty time.
@@ -99,6 +100,6 @@
 /** Get current time.
  *
- * Gets current time from the system clock. User must specify the psTimeType (PS_TIME_TAI or PS_TIME_UTC) in
- * the argument.
+ * Gets current time from the system clock. User must specify the psTimeType 
+ * (PS_TIME_TAI or PS_TIME_UTC) in the argument.
  *
  *  @return  psTime*: Struct with current time.
@@ -121,12 +122,12 @@
 /** Convert psTime to Local Mean Sidereal Time (LMST).
  *
- *  Converts psTime at the given longitude to LMST time. If the input time is not in UTC format, then it is
- *  converted.
- *
- *  @return  double: LST Time.
- */
-double psTimeToLMST(
+ *  Converts psTime at the given longitude to LMST time. If the input time is not 
+ *  in UTC format, then it is converted.
+ *
+ *  @return  psF64: LST Time.
+ */
+psF64 psTimeToLMST(
     psTime *time,                       ///< psTime to be converted.
-    double longitude                    ///< Longitude.
+    psF64 longitude                    ///< Longitude.
 );
 
@@ -135,20 +136,21 @@
  *  This function is necessary to for various SLALIB functions.
  *
- *  @return  double: Time difference.
- */
-double psTimeGetUT1Delta(
+ *  @return  psF64: Time difference.
+ */
+psF64 psTimeGetUT1Delta(
+    const psTime *time,                 ///< psTime to be looked up.
+    psTimeBulletin bulletin             ///< IERS bulletin to use
+);
+
+/** Determine TAI - UTC from table lookup.
+ *
+ *  This function is necessary to for various psTime functions.
+ *
+ *  @return  psF64: Time difference.
+ */
+psF64 p_psTimeGetTAIDelta(
     const psTime *time                  ///< psTime to be looked up.
 );
 
-/** Determine TAI - UTC from table lookup.
- *
- *  This function is necessary to for various psTime functions.
- *
- *  @return  double: Time difference.
- */
-double psTimeGetTAIDelta(
-    const psTime *time                  ///< psTime to be looked up.
-);
-
 /** Determine polar coordinates at a given time.
  *
@@ -157,6 +159,6 @@
  *  @return  psSphere*: Spherical coordinates of Earth's polar axias.
  */
-struct psSphere* psTimeGetPoleCoords(
-                const psTime *time                  ///< psTime determine polar orientation.
+struct psSphere* p_psTimeGetPoleCoords(
+                const psTime *time      ///< psTime determine polar orientation.
             );
 
@@ -172,20 +174,32 @@
 );
 
+/** Determine if UTC time is a leapsecond.
+ *
+ *  Determines if the specified UTC time is a valid leapsecond.
+ *
+ *  @return  psBool: valid leap second
+ */
+psBool psTimeIsLeapSecond(
+    const psTime* utc                  ///< UTC to verify if leap second
+);
+
 /** Convert psTime to Julian date time.
  *
- *  Converts psTime to Julian date (JD) time. This function does not add or subtract leapseconds.
- *
- *  @return  double: Julian Date (JD) time.
- */
-double psTimeToJD(
+ *  Converts psTime to Julian date (JD) time. This function does not add or 
+ *  subtract leapseconds.
+ *
+ *  @return  psF64: Julian Date (JD) time.
+ */
+psF64 psTimeToJD(
     const psTime* time                  ///< Input time to be converted.
 );
 /** Convert psTime to modified Julian date time.
  *
- *  Converts psTime to modified Julian date (MJD) time. This function does not add or subtract leapseconds.
- *
- *  @return  double: Modified Julian Days (MJD) time.
- */
-double psTimeToMJD(
+ *  Converts psTime to modified Julian date (MJD) time. This function does not 
+ *  add or subtract leapseconds.
+ *
+ *  @return  psF64: Modified Julian Days (MJD) time.
+ */
+psF64 psTimeToMJD(
     const psTime* time                  ///< Input time to be converted.
 );
@@ -193,6 +207,6 @@
 /** Convert psTime to ISO8601 formatted string.
  *
- *  Converts psTime to a null terminated string in the form of YYYY-MM-DDThh:mm:ss.sss. This function does not
- *  add or subtract leapseconds.
+ *  Converts psTime to a null terminated string in the form of YYYY-MM-DDThh:mm:ss.sss. 
+ *  This function does not add or subtract leapseconds.
  *
  *  @return  char*: Pointer null terminated array of chars in ISO time.
@@ -206,21 +220,23 @@
  *  Converts psTime to timeval time. This function does not add or subtract leapseconds.
  *
- *  @return  timeval: timeval struct time.
- */
-struct timeval psTimeToTimeval(
-                const psTime* time                  ///< Input time to be converted.
+ *  @return  timeval*: timeval struct time.
+ */
+struct timeval* psTimeToTimeval(
+                const psTime* time     ///< Input time to be converted.
             );
 
-/** Convert psTime to tm time.
- *
- * Converts psTime to tm time. This function is based on a Perl algorithm availble in the Pan-STARRS Image
- * processing Algorithm Design Description (ADD). This function does not add or subtract leapseconds.
+/*
+ * Convert psTime to tm time.
+ *
+ * Converts psTime to tm time. This function is based on a Perl algorithm availble 
+ * in the Pan-STARRS Image processing Algorithm Design Description (ADD). This function 
+ * does not add or subtract leapseconds.
  *
  *  @return  tm: tm struct time.
- */
-struct tm* psTimeToTM(
-                const psTime *time                  ///< Input time to be converted.
+ *
+struct tm* p_psTimeToTM(
+                const psTime *time     ///< Input time to be converted.
             );
-
+*/
 /** Convert JD to psTime.
  *
@@ -230,5 +246,5 @@
  */
 psTime* psTimeFromJD(
-    double time                         ///< Input time to be converted.
+    psF64 time                       ///< Input time to be converted.
 );
 
@@ -240,5 +256,5 @@
  */
 psTime* psTimeFromMJD(
-    double time                         ///< Input time to be converted.
+    psF64 time                      ///< Input time to be converted.
 );
 
@@ -250,5 +266,5 @@
  */
 psTime* psTimeFromISO(
-    const char* time                    ///< Input time to be converted.
+    const char* time                 ///< Input time to be converted.
 );
 
@@ -260,16 +276,40 @@
  */
 psTime* psTimeFromTimeval(
-    const struct timeval *time          ///< Input time to be converted.
+    const struct timeval *time       ///< Input time to be converted.
+);
+
+/** Convert Terrestrial Time to psTime
+ *
+ *  Converts Terrestial Time to psTime.  This function assumes resultant time is of type TT.
+ *
+ *  @return psTime*: time (TT)
+ */
+psTime* psTimeFromTT(
+    psS64 sec,                      ///< Input terrestrial time in seconds
+    psU32 nsec                      ///< Input terrestrial time fraction of seconds (nanoseconds)
+);
+
+/** Convert UTC time to psTime
+ *
+ *  Converts UTC time to psTime.  It will verify if time specified is a leapsecond.
+ *
+ *  @return psTime*: time (UTC)
+ */
+psTime* psTimeFromUTC(
+    psS64  sec,                    ///< Input time in seconds
+    psU32  nsec,                   ///< Input time fraction of seconds (nanoseconds)
+    psBool leapsecond              ///< Input time is a leapsecond
 );
 
 /** Convert tm time to psTime.
  *
- *  Converts tm time to psTime. This function is based on a Perl algorithm availble in the Pan-STARRS Image
- * processing Algorithm Design Description (ADD). This function does not add or subtract leapseconds.
+ *  Converts tm time to psTime. This function is based on a Perl algorithm availble 
+ *  in the Pan-STARRS Image processing Algorithm Design Description (ADD). This function 
+ *  does not add or subtract leapseconds.
  *
  *  @return  psTime*: time.
  */
-psTime* psTimeFromTM(
-    const struct tm *time               ///< Input time to be converted.
+psTime* p_psTimeFromTM(
+    const struct tm *time            ///< Input time to be converted.
 );
 
@@ -281,6 +321,6 @@
  */
 psTime* psTimeMath(
-    const psTime *time,                 ///< Time.
-    psF64 delta                         ///< Time delta.
+    const psTime *time,              ///< Time.
+    psF64 delta                      ///< Time delta.
 );
 
@@ -292,6 +332,6 @@
  */
 psF64 psTimeDelta(
-    const psTime *time1,                ///< First time.
-    const psTime *time2                 ///< Second time.
+    const psTime *time1,             ///< First time.
+    const psTime *time2              ///< Second time.
 );
 
Index: /trunk/psLib/src/dataManip/psConstants.h
===================================================================
--- /trunk/psLib/src/dataManip/psConstants.h	(revision 4050)
+++ /trunk/psLib/src/dataManip/psConstants.h	(revision 4051)
@@ -6,6 +6,6 @@
  *  @author GLG, MHPCC
  *
- *  @version $Revision: 1.70 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2005-05-31 21:25:27 $
+ *  @version $Revision: 1.71 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2005-05-31 21:48:13 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -150,4 +150,13 @@
 }
 
+// Return an error if the arg lies outside the supplied range
+#define PS_ASSERT_LONG_WITHIN_RANGE(NAME, LOWER, UPPER, RVAL) \
+if ((NAME) < (LOWER) || (NAME) > (UPPER)) { \
+    psError(PS_ERR_BAD_PARAMETER_VALUE, true, \
+            "Error: %s, %lld, is out of range.", \
+            #NAME, NAME, LOWER, UPPER); \
+    return RVAL; \
+}
+
 /*****************************************************************************
 Macros which take a generic psLib type and determine if it is NULL, or has
Index: /trunk/psLib/src/math/psConstants.h
===================================================================
--- /trunk/psLib/src/math/psConstants.h	(revision 4050)
+++ /trunk/psLib/src/math/psConstants.h	(revision 4051)
@@ -6,6 +6,6 @@
  *  @author GLG, MHPCC
  *
- *  @version $Revision: 1.70 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2005-05-31 21:25:27 $
+ *  @version $Revision: 1.71 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2005-05-31 21:48:13 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -150,4 +150,13 @@
 }
 
+// Return an error if the arg lies outside the supplied range
+#define PS_ASSERT_LONG_WITHIN_RANGE(NAME, LOWER, UPPER, RVAL) \
+if ((NAME) < (LOWER) || (NAME) > (UPPER)) { \
+    psError(PS_ERR_BAD_PARAMETER_VALUE, true, \
+            "Error: %s, %lld, is out of range.", \
+            #NAME, NAME, LOWER, UPPER); \
+    return RVAL; \
+}
+
 /*****************************************************************************
 Macros which take a generic psLib type and determine if it is NULL, or has
