DD_time.c 11 KB
/* ===================================================================
 * Name          : DD_time.c
 * Version:      : 4.1
 * Author        : Andrey Fedorov
 * Institution   : IRAP/UPS/CNRS Toulouse
 * Modifications list:
 *    Oct 5, 2002:    V.3.0, New functions   DD_Time2Double   and  Double2DD_Time were added.
 *    March 26, 2010: V.3.1  YEARS up to 2025
 *    May 17, 2011:    V.4.0 Fedorov, completely revised version.
 *                           There is no more confuse between Time and Time Interval
 *   Sept 05, 2011: V.4.1  SetIntNew =>  arg TimeKind => to work with 1970-1973 : BR
 *==================================================================*/

#include "DD_time.h"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>

#define YEARS 70
#define STARTYEAR 1970

/*---- Static array of days shift from Jan-1-1970 -------*/
/*                    1970    1971    1972    1973    1974    1975    1976
 *                    1977    1978    1979    1980    1981    1982    1983
 *                    1984    1985    1986    1987    1988    1989    1990
 *                    1991    1992    1993    1994    1995    1996    1997
 *                    1998    1999    2000    2001    2002    2003    2004
 *                    2005    2006    2007    2008    2009    2010    2011
 *                    2012    2013    2014    2015    2016    2017    2018
 *                    2019    2020    2021    2022    2023    2024    2025
 *                    2026    2027    2028    2029    2030    2031    2032
 *                    2033    2034    2035    2036    2037    2038    2039
 */
static double
      YearDays[YEARS] = {   0.0,   365.0,   730.0,  1096.0,  1461.0,  1826.0,  2191.0,
                         2557.0,  2922.0,  3287.0,  3652.0,  4018.0,  4383.0,  4748.0,
                         5113.0,  5479.0,  5844.0,  6209.0,  6574.0,  6940.0,  7305.0,
                         7670.0,  8035.0,  8401.0,  8766.0,  9131.0,  9496.0,  9862.0,
                        10227.0, 10592.0, 10957.0, 11323.0, 11688.0, 12053.0, 12418.0,
                        12784.0, 13149.0, 13514.0, 13879.0, 14245.0, 14610.0, 14975.0,
                        15340.0, 15706.0, 16071.0, 16436.0, 16801.0, 17167.0, 17532.0,
                        17897.0, 18262.0, 18628.0, 18993.0, 19358.0, 19723.0, 20089.0,
                        20454.0, 20819.0, 21184.0, 21550.0, 21915.0, 22280.0, 22645.0,
                        23011.0, 23376.0, 23741.0, 24106.0, 24472.0, 24837.0, 25202};

/*-------------------------------------------------------------
 * DAY_OF_YEAR = monthday[*][month-1]+day_of_month -1
 *------------------------------------------------------------*/
static int monthday[2][12] =
{
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
{0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
};

/*------------------------------------------------------------
 * Global static Flag to show the current state of the time
 * processor. Is it Time interval (0), or DD Time (1)
 *----------------------------------------------------------*/
static int TimeFlag = 1;
/*================== INTERNAL FUNCTION ====================*/
/*-------------------- SetInt ----------------------------*/
void SetInt(dd_tmstr_t *UT)
{
  SetIntNew(UT,DD_TM_UNKNOWN);
}

void SetIntNew(dd_tmstr_t *UT,t_DDTimeKind timeKind) /* Fill int values of dd_tmstr_t */
/* If the double times field of UT structure is defined,
 * this function fills remains fields of Year, day .... separately
 */
{
   static double msofday = 24.0*60.0*60.0;
   static double msofhour = 60.0*60.0;
   static double msofmin = 60.0;
   long daynumber;
   double msrest;
   int i;

   daynumber = (long)(UT->times / msofday);
   for(i=0;i<YEARS;i++) if(daynumber < (long)YearDays[i]) break;
   i--;

   switch(timeKind)
   {
     case DD_TM_DATE :
     {
       //it's a date
       UT->year = i+1970;
       UT->day = (int)(daynumber - (long)YearDays[i]);
       break;
     }
     case DD_TM_TIME_INTERVAL :
     {
       //it's a time interval
       UT->year = 0;
       UT->day =  (int)(daynumber);
       break;
     }
     default :
       //compatibility mode
       if(i > 3)
       {
         UT->year = i+1970;
         UT->day = (int)(daynumber - (long)YearDays[i]);
       }
       else
       {
         UT->year = 0;
         UT->day =  (int)(daynumber);
       }
       break;
   }

   msrest = UT->times - (double)daynumber * msofday;
   UT->hour = (int)(msrest / msofhour);
   msrest -= (double)(UT->hour)*msofhour;
   UT->min = (int)(msrest / msofmin);
   msrest -= (double)(UT->min)*msofmin;
   UT->sec = (int)(msrest);
   UT->msec = (int)((msrest - (double)(UT->sec))*1000.0);
   return;
}

/*---------------- end of SetInt -----------------------*/
 
/*-------------------------------------------------------
 *                 SetDouble()
 * Returns the double value of seconds since  1 Jan 1970
 * The calculations are made from already filled dd_tmstr_t.
 * If UT->year
 *------------------------------------------------------*/
void SetDouble(dd_tmstr_t *UT)
{
 static double SecInMls = 1.0/1000.0;
 static double SecImMin = 60.0;
 static double SecInHour = 60.0*60.0;
 static double SecInDay = 60.0*60.0*24.0;
 if(UT->year >= STARTYEAR)     // This is DD Time !
 UT->times =          (double)UT->msec*SecInMls  +
                      (double)UT->sec +
                      (double)UT->min*SecImMin +
                      (double)UT->hour*SecInHour +
                      (double)UT->day*SecInDay +
                      YearDays[(UT->year - 1970)]*SecInDay;
 else if(UT->year < STARTYEAR) // This is Time Interval
 UT->times =            (double)UT->msec*SecInMls  +
                        (double)UT->sec +
                        (double)UT->min*SecImMin +
                        (double)UT->hour*SecInHour +
                        (double)UT->day*SecInDay +
                        YearDays[UT->year]*SecInDay;
 else
 UT->times =            0.0;
 return;
}
/*----------------- end of SetDouble ---------------------*/

/*=================== PUBLIC FUNCTIONS ==================*/
/*-------------------   DD_Time2Double  --------------------*/
double DD_Time2Double(dd_time_t  UTstring)
{
   static dd_tmstr_t UT;
   static char year[5] = "0000\0";
   static char  day[4] = "000\0";
   static char   hour[3]= "00\0";
   static char min[3] = "00\0";
   static char  sec[3]= "00\0";
   static char  msec[4] = "000\0";

   strncpy(year,UTstring,4);
   strncpy(day,UTstring+4,3);
   strncpy(hour,UTstring+7,2);
   strncpy(min,UTstring+9,2);
   strncpy(sec,UTstring+11,2);
   strncpy(msec,UTstring+13,3);

   sscanf(year,"%d",&(UT.year));
   sscanf(day,"%d",&(UT.day));
   sscanf(min,"%d",&(UT.min));
   sscanf(hour,"%d",&(UT.hour));
   sscanf(sec,"%d",&(UT.sec));
   sscanf(msec,"%d",&(UT.msec));
   if(UT.year < STARTYEAR) TimeFlag = 0; // Time Inetrval

   SetDouble(&UT);
   return UT.times;
}
/*------------------------------------------------------*/

/*-------------------   Double2DD_Time  ---------------------*/
 char *Double2DD_Time(double Time)
 {
    static dd_time_t UTstring;
    dd_tmstr_t  UT;

    UT.times =   Time;
    SetInt(&UT);
    sprintf(UTstring,"%04d%03d%02d%02d%02d%03d",(UT.year),(UT.day),(UT.hour), (UT.min), (UT.sec),(UT.msec));
    return &(UTstring[0]);
 }
/*------------------------------------------------------------*/

/*================== BACKUP COMPABILITY FUNCTIONS =================*/
/*-----------------------------------------------------------------
 *                  ReadTime()
 * Reads a standard DD time string as an argument
 * and converts it into dd_tmstr_t structure.
 * Function returns the pointer to the internal startic structure dd_tmstr_t.
 * Function redefines TimeFlag.
 *----------------------------------------------------------------*/
dd_tmstr_t *ReadTime(char *UTstring)
{
   static dd_tmstr_t UT;
   static char year[5] = "0000\0";
   static char  day[4] = "000\0";
   static char   hour[3]= "00\0";
   static char min[3] = "00\0";
   static char  sec[3]= "00\0";
   static char  msec[4] = "000\0";

   strncpy(year,UTstring,4);
   strncpy(day,UTstring+4,3);
   strncpy(hour,UTstring+7,2);
   strncpy(min,UTstring+9,2);
   strncpy(sec,UTstring+11,2);
   strncpy(msec,UTstring+13,3);

   sscanf(year,"%d",&(UT.year));
   sscanf(day,"%d",&(UT.day));
   sscanf(min,"%d",&(UT.min));
   sscanf(hour,"%d",&(UT.hour));
   sscanf(sec,"%d",&(UT.sec));
   sscanf(msec,"%d",&(UT.msec));

   if(UT.year < STARTYEAR) TimeFlag = 0; // Time Inetrval

   SetDouble(&UT);
   return(&UT);
}
/*-------------------- end of ReadTime ------------------------*/

/*---------------------- Write Time ---------------------------*/
/* Function Write time convert use only double times field
 * of dd_tmstr_t structure to print time in DD style
 * in internal static string. The integer fields redefined.
 * Function return string pointer.
 */

char *WriteTime(dd_tmstr_t *UT)
{
   static dd_time_t UTstring;

   SetInt(UT);
   sprintf(UTstring,"%04d%03d%02d%02d%02d%03d",(UT->year),(UT->day),(UT->hour),
                                         (UT->min), (UT->sec),(UT->msec));
   return(UTstring);
}
/*------------------- end of WriteTime -------------------*/

void WriteFmtTime(dd_tmstr_t *UT,char *UTstring)
{
   SetInt(UT);
   sprintf(UTstring,"%04d:%03d:%02d:%02d:%02d",(UT->year),(UT->day),(UT->hour),
                                               (UT->min), (UT->sec));
}
/*------------------- end of WriteFmtTime -------------------*/

/*=========================================================
 *    Functions for DECODERs
 * These functions make conversion from/to DD double/DD_time_structure and
 * a integer array as follows:
 * {Year, Month, Day_Of_Month, Hour, Min, Sec, Mls}
 *========================================================*/
/*--------------------------------------------------------
 *              UT2double()
 * Fille the DD_time_structure with double fild from the
 * integer array (see the section header)
 *-------------------------------------------------------*/
dd_tmstr_t *UT2double(unsigned *ut)
/* Fill the standard structure with double too using as
 * argument 7 int length array in Gavrilova Passport Standard
 */
{
static dd_tmstr_t UT;
int visocos;

if(ut[0]%4 == 0) visocos = 1; else visocos = 0;
UT.year = ut[0];
UT.day = monthday[visocos][ut[1] - 1]+ut[2] - 1;
UT.hour = ut[3];
UT.min = ut[4];
UT.sec = ut[5];
UT.msec = ut[6];

SetDouble(&UT);
return(&UT);
}
/*-------------------------------------------------------*/
/*-------------------------------------------------------
 *           Double2UT()
 * Converts Standard DD double time to interger array (see
 * the section header)
 *--------------------------------------------------------*/
unsigned *Double2UT(double t)
{
   static unsigned UT[7];
   dd_tmstr_t tm;
   int i,visocos;

   tm.times = t;
   SetInt(&tm);
   if(tm.year % 4 == 0) visocos = 1; else visocos = 0;
   i = 0;
   while((i < 12) && (tm.day >= monthday[visocos][i])) i++;
   UT[0] = tm.year;
   UT[1] = i;
   UT[2] = tm.day +1 - monthday[visocos][i-1];
   UT[3] = tm.hour;
   UT[4] = tm.min;
   UT[5] = tm.sec;
   UT[6] = tm.msec;

   return( (unsigned *)UT);
}
/*=======================================================================*/