##########################################################################
#
# Package: sogs_time_pkg.pl
#
# Purpose: Provides a set of routines to manipulate time is SOGS format
#
# Member routines:
#    $time = CurDate(); -- returns localtime in SOGS format (yyyy.ddd:hh:mm:ss).
#    $time = DecompressTime( $compressed_time); -- returns SOGS format from
#             compressed  format (yyyydddhhmmss).
#    $time = AdjustTime( $date_time, $delta_minutes); -- returns new SOGS format
#             time using input $data_time and a positive or negative integer 
#             number of minutes to be added.
#    $time = ConvertMJD( $mjd ); -- returns SOGS format from modified julian
#             day (nnnnn.nnnnnnnn)  
#
# modification history:
#
#   date    opr     who     reason
# -------- -----  --------  --------------------------------------
# 04/26/02 45738  J.Baum    first version
# 
#########################################################################
#
#---------------------------------------------------------------------
#--- get current date-time in SOGS format (yyyy.ddd:hh:mm:ss)
sub CurDate()
{
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
    $year   += 1900;
#----  Perl day of year is zero based !!
    $yday++; 
    my $cur_date = sprintf("%4d.%03d:%02d:%02d:%02d",
       $year,$yday,$hour,$min,$sec);
}
#---------------------------------------------------------------------
#---  decompress yyyydddhhmmss to yyyy.ddd:hh:mm:ss 
sub DecompressTime ($)
{
    my ( $decompressed ) = @_;
#   substitute five fixed length fields, inserting the appropriate separators
    $decompressed =~s/^(....)(...)(..)(..)(..)/$1\.$2:$3:$4:$5/;
    $decompressed;
}
#---------------------------------------------------------------------
#---  Adjust SOGS formatted time (yyyy.ddd:hh:mm:ss) by minutes.
#---  The first argument is the initial SOGS-format time, and the second
#---  argument is the minutes to adjust and it may be a positive or negative
#---  integer.
#---
#---  This method allows for very big deltas but is only efficient for smaller
#---  deltas, less than 1000 minutes. A different routine should be used for
#---  very large deltas. 
sub AdjustTime ($$)
{
    my ( $date_time, $delta_minute ) = @_;
    my $adjusted_time;
    my $year;
    my $day;
    my $hour;
    my $minute;

    $year   = 0 + substr($date_time,0,4);
    $day    = 0 + substr($date_time,5,3);
    $hour   = 0 + substr($date_time,9,2);
    $minute = 0 + substr($date_time,12,2) + $delta_minute;

    if ($minute < 0) {
       do {
          $minute += 60;
          $hour -= 1;
       } while $minute < 0;
       
       while ($hour < 0) {
          $hour += 24;
          $day -= 1;
          if ($day == 0) {
             if ( ($year % 4) == 1 ) {
                $day = 366;
             } else {
                $day = 365;
             }
             $year -= 1;
          }
       }
    } elsif ($minute > 59) {
       do {
          $minute -= 60;
          $hour += 1;
       } while $minute > 59;
       
       while ($hour > 23) {
          $hour -= 24;
          $day += 1;
          if (($day == 367) || ($day == 366 && ($year % 4) != 0 )) { 
             $day = 1;
             $year += 1;
          }
       }
    }
    $adjusted_time = sprintf("%d.%03d:%02d:%02d:",
       $year,$day,$hour,$minute).substr($date_time,15,2);
}
#---------------------------------------------------------------------
#--- convert MJD time to yyyy.ddd:hh:mm:ss
# Notes on method:
#    Not valid after 2101 because of missing leap day in year 2100. Not
#    a concern here. Assumes all dates are after 1980.
#
#    Intervals of (366 + 3*365 = 1461) years, starting at the start of a leap
#    year (e.g. 1980) have simple rules for finding the day boundaries of 
#    years within this interval.  Jan 1, 1980 is at MJD 44239.0. Calculations
#    use zero-origin for day_of_interval while day_of_year is one-origin.
# ---
sub ConvertMJD($)
{
    my ($mjd) = @_;
    my $jul_day;
    my $mjd_1980 = 44239.0;
    my $day_since_1980;
    my $leap_interval = 1461;
    my $day_of_interval;
    my $secs_of_day;
    my $year;
    my $day_of_year;
    my $hour;
    my $minute;
    my $second;

    $jul_day = int($mjd);
    if (!defined($jul_day) || $jul_day == 0) {
       PrintMsg("E","Cannot convert mjd keyword value $mjd to date.");
       exit( $PROCESS_FAILURE);
    }
    $secs_of_day = int(($mjd - $jul_day) * 86400.0);
    $hour = int( $secs_of_day/3600);
    $minute = int( ( $secs_of_day % 3600 )/ 60);
    $second = int( $secs_of_day % 60 );
    $day_since_1980 = $jul_day - $mjd_1980;
#-------------------------------------------------------------------------
#  get year and day of interval since start of most recent leap interval 
#-------------------------------------------------------------------------
    $year = 1980 + 4 * int( $day_since_1980 / $leap_interval);
    $day_of_interval = int( $day_since_1980 % $leap_interval);
#-------------------------------------------------------------------------
#  add year increment and get day of year within leap interval 
#-------------------------------------------------------------------------
    if ($day_of_interval <= 365 ) {
        $day_of_year = $day_of_interval + 1;
    }else{
        $year +=   int( ($day_of_interval - 1) / 365);
        $day_of_year = (($day_of_interval - 1) % 365) + 1;
    }
    sprintf("%d.%03d:%02d:%02d:%02d", $year,$day_of_year,$hour,$minute,$second);
}
1;
