/* @(#)ast_trjd.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	trjd.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 module deals with transformations from / to Julian Dates.
\end{TeX}

.VERSION 1.0	04-Mar-1987: Creation
.VERSION 1.1	28-Jan-1988: Adapted for Midas Environment.
______________________________________________________________________*/

#include <trtime.h>

#define LONG_MAX	2147483647		/* 2**31 - 1		*/
#define LONG_MIN	(-LONG_MAX-1)		/* -2**31		*/

#define JD1970		2440587.5e0	/* JD   of 00:00:00 Jan. 1, 1970   */

/*========================================================================*/
double itojd(t)
/*+++
.PURPOSE Transform integer time to Julian Day
.RETURNS The equivalent Julian Date
.REMARKS	
---*/
	long int t;	/* IN:	Time in seconds since Jan 1, 1970	*/
{
	double JD;	/* OUT: Julian date	*/

  JD  = t;
  JD /= 86400.e0;	/* In days since 1970	*/
  JD += JD1970;

  return(JD);
}

/*========================================================================*/
double tmtojd(T)
/*+++
.PURPOSE Transform structure time to Julian Day
.RETURNS JD equivalence
.REMARKS	
---*/
	struct tm *T;	/* IN:	Time as a structure		*/
{
	long int jm, j;
	double JD;

  tr_tm(T);		/* Can be wrong...	*/

  if (T->tm_year <= -4712)
  {	j = 1 + (T->tm_year + 4712)/400;   	/* Number of 400-yr cycles */
  	jm = -j * 146097L;
	j  = T->tm_year + 400*j;
  }
  else	jm = 0, j = T->tm_year;

  j  -= (11 - T->tm_mon)/10;
  jm += (1461L* ( j + 4712L))/4 + (306L * ((T->tm_mon+10)%12) + 5)/10
	- (3* ((j + 4900L)/100))/4 + T->tm_mday + 96;
  JD = jm;

  jm  = ((long)(12+T->tm_hour))*3600L + T->tm_min*60 + T->tm_sec;
  JD += (jm/86400.e0);

  return(JD);
}

/*========================================================================*/
int tr_jdi(JD, t)
/*+++
.PURPOSE Transform Julian Date to time in seconds from Jan 1, 1970
.RETURNS 0 (success) / -1 (outside limits)
.REMARKS	
---*/
	double	JD;	/* IN:	Julian date	*/
	long int *t;	/* OUT: Date in seconds since Jan 1, 1970 */
{
	register double x;

  x = ((JD - JD1970)*86400.e0);

  if ((x <= LONG_MIN)||(x >= LONG_MAX))
	return(-1);
  *t = x;
 
  return(0);
}

/*========================================================================*/
int tr_jdtm(JD, T)
/*+++
.PURPOSE Transform Julian Date to time structure
.RETURNS 0 
.REMARKS 
---*/
	double	JD;	/* IN:	Julian date	*/
	struct tm *T;	/* OUT: Date in structure	*/
{
	register long int j, n4, nd10;
	double x;

  x = JD + 0.5e0 + 0.5e0/86400.e0;	/* Round day	*/
  j = x;
  if (x < 0)	 --j; 
  x = x - j;				/* Fraction of day	*/

  T->tm_year = -4712;
  while (j <= 4480)	{ j += 146097L; T->tm_year -= 400;}

  n4 = 4*(j+((2*((4*j-17918L)/146097L)*3)/4+1)/2-37);
  nd10=10*( ((n4-237)%1461)/4)+5;

  T->tm_year += n4/1461;
  T->tm_mon  = (nd10/306+2)%12;
  T->tm_mday = (nd10%306)/10+1;

  x *= 86400.e0;			/* Seconds	*/
  j = x;
  T->tm_hour = j/3600;
  T->tm_min  = 0;
  T->tm_sec  = j%3600;

  tr_tm(T);				/* Add missing info...	*/

  return(0);
}

