/*--------------------------------------------------------------
 *   gtime_adt.h  : header file for timestamp related ADTs.
 *   
 *   Change Log :
 *		  6-05-1996 Initial version,  Liujian Qian
 *   $Id: gadt_time.h,v 1.6 1999/01/27 20:59:56 qian Exp $
 *-------------------------------------------------------------*/

#ifndef _GTIME_H_
#define _GTIME_H_

#include <string.h>
#include <stdlib.h>
#include <math.h>

#include "gadt.h"
#include "greg_tbls.h"		      //for translation tables
 

class GSpan;   		      //forward declarations
class GTimestamp;

//
// Gregorian calendar standards and routines.
// For reference, see [C. Dyreson & R. Snodgrass, "The MultiCal Project"]
//
#define g_max_year           (9999999999ll)
#define g_max_month          (12)
#define g_century_of(x)      ((x) / 100)
#define g_year_of_century(x) ((x) %100)
#define g_year_of_decade(x)  (x % 10)
#define g_decade(x)          (g_year_of_century(x) / 10)


#define LEAP400 		97   //97 leap days in every 400 years
#define SECONDS_IN_MINUTE 	60
#define SECONDS_IN_HOUR 	3600
#define SECONDS_IN_DAY 		86400
#define SECONDS_IN_WEEK		86400*7
#define SECONDS_IN_YEAR 	86400*365
#define SECONDS_IN_LEAP_YEAR 	86400*366
#define LEAPDAYS_UPTO_1970 	477
#define YEARS_IN_GREG 		400
#define DAYS_IN_GREG 		146097
#define SECONDS_IN_GREG 	0x2f0605980ull
#define SECONDS_TO_1970 	0xe7791f700ull

#define century_year(x)  	(x % 100 == 0)
#define year_div_by_400(x) 	(x % 400 == 0)
#define IS_LEAP_YEAR(x) 	((x % 4 == 0) && \
				 ((x % 400 == 0) || (!(x % 100 == 0))))

/**
 * unit of a time label/stamp
 */
enum TimeUnit
{
    _INVALID	=-1,
    _SECOND	=0,
    _MINUTE	=1,
    _HOUR	=2,
    _DAY	=3,
    _WEEK	=4,
    _YEAR	=5,
    _MONTH	=6,
    _SEASON	=7,
    _DECADE	=8,
    _CENTURY	=9,	
    _KYEAR	=10,	//thousand years
    _MYEAR	=11	//million years
};

/**
 */
enum Months
{
    _BAD	= -1,
    _JAN	= 0,    _FEB	= 1,    _MAR	= 2,    _APR	= 3,
    _MAY	= 4,	_JUN    = 5,	_JUL	= 6,	_AUG	= 7,
    _SEP	= 8, 	_OCT	= 9,	_NOV	= 10,	_DEC	= 11
};
    

/**
 *    Gregorian date/time structure. The value 
 *    for the field 'month' and 'day' begin with 1; the rest 
 *    all begin with 0. For example, the following code generates 
 *    a GDate object for Dec 1, 1981:
 *    GDate d(1981, 12, 1);
 */
struct GDate {
    int64  year;
    Months  month;
    short day;
    short hour;	
    short minute;
    short second;
    static char* month_names[13];
    static uint8 days_in_mon[13];
    
    GDate() 
    {
	year = day = hour = minute = second = 0;
	month = _JAN;
    }

    GDate(int64 y, int m, int d, int h=0, int mi=0, int s=0) :
	year(y), month( (Months)m), day(d), hour(h), minute(mi), second(s) 
    {};

    Months nameToMonth(const char* mon);
};


//types of timestamps
#define TS_REGULAR      8	//0100
#define TS_SPECIAL      12	//1100
#define TS_SPAN		2	//0010: fixed span
#define TS_VSPAN	15	//1111: variable span


/**

       GFC's timestamp class.

       GTimestamp is based on the work by MultiCal project of U.
       Arizona.

GLOSSARY
        <pre>
 	CHRONON:   Unit of time measuring as adopted by a clock. A second
		   for our purpose. (Would geographical features  be 
		   measured to a microsecond??)
	TIMESTAMP: A paticular time in the history. Defined by the
		   number of chronons from the origin.
	SPAN:      A period of time. A FIXED span is just a count of 
		   chronons; while a VARIABLE span (line a 'month')
		   may have a duration that depends on a paticular calendar.
	ORIGIN:    We specify "Midnight January 1, 1970 GMT" as the origin for
		   timestamps (same as the unix time origin.) This is merely
		   a reference point. The actual timestamp represented can
		   cover the whole history of the Earth, using just 64 bits.
	</pre>	   
	
TIMESTAMP FORMAT:

	We use a 64 bit integer to represent the timestamp.
	The bits pattern is as below:

	<pre>
      63                                                               0       
      xxxx,x,xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
       |   |	                            |  
       |   |  seconds from the ORIGIN (59 bits; good for 36 billion years)
       |  sign (1:after ORIGIN, 0: before ORIGIN)
      type (see below)

      Type:
	1100: for special timestamps ("beginning", "forever",and null).
	      	C000000000000001 = beginning (big bang)
		C000000000000002 = forever  (big crunch?)
		C000000000000000 = NULL timestamp.
	0100: a regular timestamp.
	0010: a fixed span or duration (sign is meaningless here)
	1111: a variable span. (to be defined -- L.Q.)
	</pre>
*/
class GTimestamp : public GTemporal
{
public:
    /**
     * timestamp internal representation.
     */
    typedef struct tag_time_internal
    {
#if defined(i386) 	
	//using byte order on Intel x86 processors.
	unsigned secs_lo :  32;  // seconds since origin
	                         // word boundary
	unsigned secs_hi :  27;  // seconds since origin
	unsigned sign    :  1;   // sign flag -- 0 before, 1 after origin
	unsigned type 	 :  4;   // types
#else
   	//assumming byte order for Sun Sparc processors.
	unsigned type 	 :  4;   // types
	unsigned sign    :  1;   // sign flag -- 0 before, 1 after origin
	unsigned secs_hi :  27;  // seconds since origin
	                         // word boundary
	unsigned secs_lo :  32;  // seconds since origin
#endif
    } timestamp_internal;

    /**
     * actual storage: 64 bits whatsoever.
     */
    union 
    {
	timestamp_internal	ts;
	int64			val;
    }t;
    
    static long _seconds[6];
    
public:

    /**
     * constructors
     */
    GTimestamp();
    /**
     */
    GTimestamp(char* special);
    /**
     */
    GTimestamp(const GDate& d);
    /**
     */
    GTimestamp(int year);
    /**
     */
    GTimestamp(int year, int mon, int day);
    /**
     */
    GTimestamp(int year, int mon, int day, int hour, int minute, int sec);
    /**
     */
    GTimestamp(const GTimestamp& copy);
    virtual GTimestamp& operator= (const GTimestamp& other);

    virtual GType 	 type	   (void) const {return _Timestamp; }    
    virtual Result	 init      (void) ;
    virtual uint32	 getPSize() const;
    
    /**
     *translate a GMT user time gregorian date into a timestamp.
     *The user format must be exact as "Oct 09 12:23:45 1996"   
     */
    virtual Result 	 input     (const char* in);
    /**
     *translates a timestamp into GMT user format, with the form of
     *"Oct 09 12:23:45 GMT 1996".                                        
     *To translate GMT time into local time, use system library functions.
     */
    virtual Result 	 output    (char*& out);

    /** same as output; except in a terse format according to the
     *  unit of the timestamp.
     */
    Result 		 output    (char*& out, TimeUnit u );
    virtual Result	 pack	   (DataPipe& p);
    virtual Result 	 unpack    (DataPipe& p);
        
    virtual int		 cmp(const GADT& a) const;
    virtual GADT* 	 clone	   () const {return new GTimestamp;}
    
    //comparison methods
    int	 		cmp(const GTimestamp& other) const;

    /**
     * change the temporal scale of this value
     */
    virtual Result	scale	  (int) ;

    /**
     * check if this temporal value is Earlier Than 'a' 
     */
    virtual int		before	  (const GTemporal& a) const;
    
    /**
     * check if this  temporal value is Later than 'a'
     */
    virtual int 	after	  (const GTemporal& a) const;
    
    /**
     * check if this temporal value is during 'a'
     */
    virtual int		during	  (const GTemporal& a) const;

    /**
     * check if this temporal value overlaps 'a'
     */
    virtual int		overlap	  (const GTemporal& a) const;
    
    /**
     */
    bool 		operator!=(GTimestamp st2) const; 

    /**
     */
    bool 		operator==(GTimestamp st2) const; 

    /**
     */
    bool 		operator<(GTimestamp st2) const;  

    /**
     */
    bool 		operator<=(GTimestamp st2) const; 

    /**
     */
    bool 		operator>=(GTimestamp st2) const; 

    /**
     */
    bool 		operator>(GTimestamp st2) const;  

    /**
     * type conversion (timestamp -> int64)
     */
    operator 		int64() const { return (uint64) t.val; }   
    

    /** 
     */
    GTimestamp&  	operator+=(uint64 seconds); 
    /**
     */
    GTimestamp&  	operator-=(uint64 seconds); 
    /**
     */
    GTimestamp&  	operator+=(GTimestamp span); 
    /**
     */
    GTimestamp&  	operator-=(GTimestamp span); 

    /**
     * convert a gregorian date into timestamp (seconds since origin.)          
     * Originally written by "MultiCal" group; modified to support hour/min/sec.
     */
    Result  		date2TS  (const GDate* date); 

    /**
     * handy versionf of date2TS
     */
    void		setDate  (const GDate& date) {date2TS(&date);}; 
    
    /**
     * Translate from seconds format to explicit Greogrian date. 
     * Original version by "MultiCal" group; modified to  support
     * hour/min/sec.                                             
     */
    Result		date  (GDate* date) const;

    /**
     * Return a time label that is in user format and in accordance to     
     * the precision. (For example, if the precision is set to year, the   
     * time label will only includ the year number, such as "1996", instead
     * of "JAN 1 00:00:00 1996".)                                          
     */
    Result		timeLabel(TimeUnit unit, char* str);

    /**
     * set timestamp to just indicate the year.
     */
    void		setYear(int year);    	

    /**
     * This method turns the timestamp into a special one 
     * representing beginning of the universe (big bang). This 
     * timestamp is smaller than any other timestamp.          
     */
    void		setToOrigin();		

    /**
     * This turns the timestamp into a "forever" one,
     * which is greater than any other timestamp.    
     */
    void		setToForever();		

    /**
     * This method turn the timestamp into a fixed span.	
     */	
    void		setToSpan(int64 span=-1);	
    
    //status reporting/setting

    friend ostream& 	operator << (ostream& s, GTimestamp& t);    
};


//for proper initialization of timestamp ADT in GFC
static class _GITimestamp{
    static int  cnt;
public:
    _GITimestamp()
    {
	if(cnt++==0) 
	    GADTManager::registerADT(new GADTDef(_Timestamp,"Timestamp",
						 1, 0, new GTimestamp));
    }
    ~_GITimestamp()
    {
	if(--cnt==0)
	    GADTManager::removeADT(_Timestamp);
    }
} gi_timestamp;

//two special timestamps: global.
extern GTimestamp ORIGIN;
extern GTimestamp FOREVER;


#endif











Documentation generated by lqian@lqian-sun on Wed Jul 14 09:36:10 EDT 1999