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;