Util::Date (version $)


package Util::Date;

##############################################################################
#
# DESCRIPTION: This class handles dates and times. It handles date 
# DESCRIPTION: formatting and conversion to and from mission time.
#
# HISTORY
# HISTORY: $Log: Date.pm,v $
# HISTORY: Revision 1.3  2014/02/27 07:01:06  apsop
# HISTORY: VERSION header now shows CVS Revision
# HISTORY:
# HISTORY: Revision 1.2  2006/08/01 20:35:34  apsop
# HISTORY: Add in CVS history indicator.
# HISTORY:
# HISTORY: 1.0 -> 1.1 2000-07-18
# HISTORY: Fixed a bug where today's date was one day ahead, possibly
# HISTORY: creating dates like June 31.
# HISTORY: 
# HISTORY: 1.1 -> 1.2 2000-10-23
# HISTORY: Fixed a bug where seconds were set equal to minutes
# HISTORY:
# HISTORY: 1.2 -> 1.3 2003-07-10
# HISTORY Added mjd method
#
# VERSION: $Revision: 1.3 $
#
##############################################################################

use Util::Ftool;

use strict;

###########################################################
# class data 
###########################################################
my $REFDATE=""; # reference date and time when converting to
my $REFTIME=""; # seconds

my $FILENAME=""; # Filename object
my $LEAPFILE=""; # leapsecond table

my %MONTH = ("01" => "January",
             "02" => "February",
             "03" => "March",
             "04" => "April",
             "05" => "May",
             "06" => "June",
             "07" => "July",
             "08" => "August",
             "09" => "September",
             "10" => "October",
             "11" => "November",
             "12" => "December" );


###########################################################################
# This constructor has three forms:
# - new() initializes to the current local date and time
# - new(yyyy-mm-dd, hh:mm:ss) initializes to the given date and time
# - new(yyyy-mm-ddThh:mm:ss) initializes from the FITS keyword date format
# - new(mission_time) initializes from the given mission time in seconds 
#                     since the reference time.
###########################################################################
sub new { 
    my $proto = shift;
    my $class = ref($proto) || $proto;

    my $self={};

    if( !@_  ) {
        ############################################################
        # no arguments so initialize to today's local date and time
        ############################################################
        my @time=gmtime(time);

        my $year =$time[5]+1900;
        my $month=sprintf("%02d",$time[4]+1);
        my $day  =sprintf("%02d",$time[3]  );

        $self->{DATE} = "$year-$month-$day";

        my $hours=sprintf("%02d",$time[2]);
        my $min  =sprintf("%02d",$time[1]);
        my $sec  =sprintf("%02d",$time[0]);

        $self->{TIME} = "$hours:$min:$sec";


    } elsif( $_[0] =~ /^\d\d\d\d-\d\d-\d\d$/ ) {
        ###################################
        # first argument looks like a date
        ###################################
        $self->{DATE}=shift;
        $self->{TIME}=shift || "00:00:00";

    } elsif($_[0] =~ /\d\d\d\d-\d\d-\d\dT/){
        ######################################################
        # looks like a FITS style yyyy-mm-ddThh:mm:ss format
        ######################################################
        ($self->{DATE}, $self->{TIME}) = $_[0] =~ /^(.*)T(.*)$/;
        if( ! $self->{TIME} ) {
            $self->{TIME}="00:00:00";
        }

    } else {
        ###################################################################
        # treat the first arg as a number of seconds since 
        #  the reference time
        ###################################################################
        if (not $LEAPFILE or not -f $LEAPFILE) {
            $LEAPFILE = $FILENAME->fetch_cal("leapsec");
        }

        if($REFDATE && $REFTIME && $FILENAME) {
            #####################################################
            # we have all the class data we need to run sec2time
            #####################################################
            my $sec2time=Util::Ftool->new("sec2time")
                                    ->params({offset   => $_[0],
                                              leapfile => $LEAPFILE,
                                              datezero => $REFDATE,
                                              timezero => $REFTIME})
                                    ->verbose(0)
                                    ->run();

            my $parfile=$sec2time->parfile();
            $self->{DATE}=$parfile->read("date");
            $self->{TIME}=$parfile->read("time");    
            
            #####################################
            # clip off decimal seconds
            #####################################
            $self->{TIME} =~ s/\..*$//;
                                    
        } else {
            ##################################################
            # the class has not been initialized, so 
            # a message to stderr is probably the best thing
            ##################################################
            print STDERR "Date class not properly initialized:\n";
            print STDERR "REFDATE=|$REFDATE|\n";
            print STDERR "REFTIME=|$REFTIME|\n";
            print STDERR "FILENAME=|$FILENAME|\n";

        }
    }

    bless($self,$class);
    return $self;


} # end of constructor

###################
# ACCESSORS:
###################

#########################################################################
# the following method initializes all the class data needed for conversions
# between dates and mission time in seconds.
# Refdate and reftime and the date and time at zero elapsed seconds.
# Leapsec is the name of the leap second calibration file.
#########################################################################
sub init_class { #(refdate, reftime, leapsec)
    my $self=shift;

    $self->refdate(shift);
    $self->reftime(shift);
    $self->filename(shift);

}


########################################################################
# get or set the reference date class data for date - time conversions
########################################################################
sub refdate {
    my $self = shift;
    if (@_) { $REFDATE = shift }
    return $REFDATE;
}

########################################################################
# get or set the reference time class data for date - time conversions
########################################################################
sub reftime {
    my $self = shift;
    if (@_) { $REFTIME = shift }
    return $REFTIME;
}

#############################################################################
# get or set the leapsecond file name class data for date - time conversions
#############################################################################
sub filename {
    my $self = shift;
    if (@_) { $FILENAME = shift }
    return $FILENAME;
}

#############################################################################
# return the date in yyyy-mm-dd format
#############################################################################
sub date {
    my $self = shift;
    return $self->{DATE};
}

#############################################################################
# return the time in hh:mm:ss format
#############################################################################
sub time {
    my $self = shift;
    return $self->{TIME};
}

#################################################################
# return the number of seconds since the reference date and time
#################################################################
sub seconds {
    my $self=shift;

    my $leapsec = $FILENAME->fetch_cal("leapsec");
    my $time2sec=Util::Ftool->new("time2sec")
                            ->params({"date"   => $self->{DATE},
                                      "time"   => $self->{TIME},
                                      leapfile => $leapsec,
                                      datezero => $REFDATE,
                                      timezero => $REFTIME      })
                        ->verbose(0)
                        ->run();

    return $time2sec->parfile()->read("offset");
} # end of seconds method

#################################################################
# return the Modified Julian Day corresponding to this date
# This implementation is not terribly efficient, since it first 
# converts the date to seconds and then to MJD
#################################################################
sub mjd {

    my $self = shift;
    my $leapsec = $FILENAME->fetch_cal("leapsec");
    
    my $seconds = $self->seconds();
    
    my $sec2time = Util::Ftool->new("sec2time")
                              ->params({offset   => $seconds,
                                        leapfile => $leapsec,
                                        datezero => $REFDATE,
                                        timezero => $REFTIME})
                              ->verbose(0)
                              ->run();
    
    return $sec2time->parfile()->read("mjd");
    
} # end of mjd method

##################################################
# parses the date into year, month and day fields. Returns these 
# as an array (year, month, day).
##################################################
sub year_month_day {
    my $self=shift;

    return ($self->{DATE} =~ /(\d\d\d\d)-(\d\d)-(\d\d)/ );

}

####################################
# print the the date in words
####################################
sub in_words {
    my $self=shift;

 
    my ($year,$month,$day) = $self->year_month_day();
    $day   =~ s/^0*//;

    return "$MONTH{$month} $day, $year";

}



1;