/* @(#)ast_trtime.c	19.1 (ES0-DMD) 02/25/03 13:53:55 */
/*===========================================================================
  Copyright (C) 1995 European Southern Observatory (ESO)
 
  This program is free software; you can redistribute it and/or 
  modify it under the terms of the GNU General Public License as 
  published by the Free Software Foundation; either version 2 of 
  the License, or (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public 
  License along with this program; if not, write to the Free 
  Software Foundation, Inc., 675 Massachusetss Ave, Cambridge, 
  MA 02139, USA.
 
  Corresponding concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/

/*++++++++++++++
.TYPE		Module
.IDENTIFICATION	trtime.c
.LANGUAGE	C
.AUTHOR		Francois Ochsenbein [ESO-IPG]
.CATEGORY	Time expression
.COMMENTS	Times may be expressed in three forms:
\begin{TeX}
\begin{itemize}
\item	integer (mnemonic {\tt i}): the number of seconds elapsed
		since Jan 1, 1970, at 00:00:00.
		The available period is roughly 1902-2037.
\item	double (mnemonic {\tt jd}): the Julian Date
\item	structure (mnemonic {\tt tm}): a structure containing, as integers:
	\begin{itemize}
	\item	{\tt year} number
	\item 	{\tt mon} the month number in range [0-11]
	\item 	{\tt mday} the day number within month, in range [1-31]
	\item 	{\tt yday} the day number within year, in range [0-355]
	\item 	{\tt wday} the day number within week, in range [0-6]
				(0 is Sunday)
	\item 	{\tt hour} in range [0-23]
	\item 	{\tt min} in range [0-59]
	\item 	{\tt sec} in range [0-59]
	\end{itemize}
\end{itemize}
This routine does only include transformations between structure tm and
integer.
\end{TeX}

.VERSION 1.0	04-Mar-1987: Creation
.VERSION 1.1	21-Oct-1988: Cosmetic modifications
.VERSION 1.2	14-Mar-1989: Removed bug in tr_tmi
.VERSION 1.3	13-Jul-1989: Corrected bug in tr_tmi (returned status)
			Also checked if day is correct.
--------------------------*/

#include <trtime.h>
#include <tra.h>

#define DEBUG 		0
#define FINISH		goto FIN
#define RETURN		FIN: return (trerror->errno ? -1 : 0)

REXTERN struct trerr_s	*trerror;

STATIC unsigned char month[12]={31,28,31,30,31,30,31,31,30,31,30,31};

/*========================================================================*/
int tr_itm(t, T)
/*+++
.PURPOSE	Transform integer time to structure
.RETURNS	0
.REMARKS	
---*/
	long int   t;	/* IN:	Time in seconds since Jan 1, 1970	*/
	struct tm *T;	/* OUT: Time in the structure			*/
{
	long int days, year;

#if DEBUG
  printf("Input time is %ld sec\n", t);
#endif
  days	  = t/86400L;
  if (t < 0)	days--;
  t -= (days*86400L);
#if DEBUG
  printf("Time of day is %ld sec\n", t);
#endif
  T->tm_hour = t/3600;
  T->tm_min  = 0;
  T->tm_sec  = (t%3600);
#if DEBUG
  printf("Days since 1970: %ld\n", days);
  printf("Time %dh %dmn %ds\n", T->tm_hour, T->tm_min, T->tm_sec);
#endif

  days   += (70L*365L + 18L);		/* Offset 1900	*/
  year    = (4L*days)/1461L;
  T->tm_year = year;
  T->tm_mon  = 0;
  T->tm_mday = 0;
  T->tm_yday = days - 365L*year - (year+3)/4;
  T->tm_year+= 1900;

  tr_tm(T);  

  return(0);
}

/*========================================================================*/
int tr_tmi(T, t)
/*+++
.PURPOSE Transform structure time to time in seconds from Jan 1, 1970
.RETURNS 0 / -1 (time not in limits 1902-2037). Error message logged,
.REMARKS	
---*/
	struct tm *T;	/* IN:	Time as a structure		*/
	long int *t;	/* OUT:	Time in seconds			*/
{
	register long int n, y;

  trerror->errno = 0;
  trerror->len = 0;
  *t = 0x80000000;	/* Default returned time...		*/
  
  if (tr_tm(T))		/* Compute missing information...	*/
	FINISH;

  if ((T->tm_year < 1902) || (T->tm_year >=2038))
  {  	trerror->errno = -1; 
  	trerror->msg = "Year outside limits [1902, 2038]";
  	tr_error();
	FINISH;
  }

  n = T->tm_year - 1970;
  y = (n >= 0 ? n+1 : n-2);		/* Leap year counter */
  n = 365*n + y/4;

  *t = (n + T->tm_yday) * 86400L + T->tm_hour * 3600L
	+ T->tm_min * 60L + T->tm_sec;

  RETURN;
}

/*========================================================================*/
int tr_tm(T)
/*+++
.PURPOSE	Compute missing info in T structure
.RETURNS	0 (good date) / -1 (bad data: invalid month or day number ...)
.REMARKS	
---*/
	struct tm *T;	/* MOD:	Time as a structure		*/
{
	long int y, j, t;

  trerror->errno = 0;
  trerror->len = 0;
  trerror->msg = (char *)0;
  month[1] = 29;
  
  if (T->tm_mday)			/* Compute Day of 400 yr cycle 	*/
  {	if ( (T->tm_mon > 11) || (T->tm_mon < 0) )
  	 	trerror->msg = "bad month";
  	if ( (T->tm_mday <= 0) || (T->tm_mday > month[T->tm_mon]))
  		trerror->msg = "bad day_in_month";
	if (trerror->msg)
	{	trerror->errno = -1;
	  	tr_error();
  		FINISH;
  	}
  }
	/* Convert time	*/

  j = 0;
  t = ((long)(T->tm_hour*60) + (long)(T->tm_min))*60 + T->tm_sec;
  while (t < 0)		{ j--; t += 86400L; }
  while (t >= 86400L)	{ j++; t -= 86400L; }
#if DEBUG
  printf("tr_tm: Time of day is %ld sec\n", t);
#endif
  T->tm_sec = t%60;
  t /= 60;
  T->tm_min = t%60;
  T->tm_hour= t/60;
  t = j;		/* Days	*/

  y = T->tm_year % 400;
  T->tm_year /= 400;
  if (y < 0)	{ y += 400; T->tm_year -= 1;}
  T->tm_year *= 400;
  if (T->tm_mday)			/* Compute Day of 400 yr cycle 	*/
  {	y += 400;			/* Positive interval	*/
  	j = y - (11 - T->tm_mon)/10;
	t += ((1461L*j)/4 + (306L * ((T->tm_mon+10)%12) + 5)/10
	    - (3* ((j + 100L)/100L))/4 + T->tm_mday + 59L) % 146097L;
	y -= 400;
  }
  else	t += 365*y + (y+3)/4 - (y-1)/100 + T->tm_yday;

  while (t < 0)	{ T->tm_year -= 400; t += 146097L;}

	/* Compute Week day	*/

  T->tm_wday = (t+6L)%7L;

	/* Compute Year	*/

  T->tm_year += 400L*(t/146097L);
  t %= 146097L;
  y = 4 *(t + (t-60)/36524L) / 1461L;
  T->tm_year += y;
  T->tm_yday = t - y*365L - (y+3)/4 + (y-1)/100;
  
	/* Compute mday + mon from yday	*/

  if (y&3)	month[1] = 28;
  if ( ((y%100) == 0) && (y))	month[1] = 28;

  for (y=T->tm_yday, j=0; y>=month[j]; y -= month[j], j++)	;
  T->tm_mon  = j;
  T->tm_mday = y+1;
#if DEBUG
  printf("Time %dh %dmn %ds\n", T->tm_hour, T->tm_min, T->tm_sec);
#endif

  RETURN;
}

