i suspect this is going to be like the long-standing joke of

  cheap, fast, stable: choose two


over the years, i've seen two schools of code for dealing with dates... years, specifically... one school is string based and the other is math based... both have their faults and pluses...

eg: string based fault : prepend '19' to single digit year value
    math based fault : 2003 - 1900 = 103 (3 is intended result)

so what i have is satellite tracking two line element files... these files contain an epoch for the numbers contained in the TLE... the epoch is laid out as

  YYdoy.frac-doy == 14211.03356282

where

  YY : 1 or 2 digit year without century ('62' or ' 3' or '05')
  doy : day of year, 1, 2 or 3 digits, jan 1 is day 0 ('  0' or ' 15' or '020')
  frac-doy : 8 digit fractional day of the year

what i'm needing to do is to choose a route to make the year portion four digits so that historical TLEs can be used... the program makes a comparison of the epoch to determine which of two is newer... the newer one is placed into the in-memory database for later usage... working with historical TLEs from 1957 to 1999 mandates four digit years be used or historical TLEs will override TLEs from 2000 to 2056 since 00 thru 56 are less than 57 (1957 first launch)...

previous to any processing, the epoch taken from the TLE in the file is processed so that leading blanks in the epoch are replaced with zeros... today's epochs don't really need this as creation and processing methods have evloved over the years... this is done as a precaution for those times when processing historical TLEs which have not been converted to having leading zeros instead of blanks (aka spaces)...

we've launched over 40000 objects and there are possibly hundreds or thousands of TLEs for each one... at least one site is known to have over 9 million TLEs in their database... these routines are executed for each and every TLE loaded as we fill our in-memory database...

finally (yeah i know, but i thought the history and methodology was important) my questions, as the subject alludes to, are which of the following methods would you choose? why? would you choose another method? why?

all input is greatly welcomed! as always, thanks for your time and attention! :)

{******************************************************************************}
{******************************************************************************}

// make sure we have the full four digit year for the epoch!
// eg: 14211.03356282 becomes 2014211.03356282 which is 2014-07-30 00:48:19.827

// method 1 (string manipulation)
if (Integer_Value(MyEpochStr,1,2) < 57) then // first launch in 1957 MyEpochStr := FloatToStrF('20'+MyEpochStr,ffFixed,16,8) // value < 57 so year is 21st century (2000 thru 2056)
else
MyEpochStr := FloatToStrF('19'+MyEpochStr,ffFixed,16,8); // value is >= 57 so year is 20th century (1957 thru 1999) MyEpoch := Real_Value(MyEpochStr,1,Length(MyEpochStr)); // convert to real for mathmatical comparison

{******************************************************************************}

// method 2 (combination string and math??)
if (Integer_Value(MyEpochStr,1,2) < 57) then // first launch in 1957 MyEpochStr := FloatToStrF(Real_Value(MyEpochStr,1,Length(MyEpochStr)) + 2000000,ffFixed,16,8)
else
MyEpochStr := FloatToStrF(Real_Value(MyEpochStr,1,Length(MyEpochStr)) + 1900000,ffFixed,16,8); MyEpoch := Real_Value(MyEpochStr,1,Length(MyEpochStr)); // convert to real for mathmatical comparison

{******************************************************************************}

// method 3 (math manipulation)
MyEpoch := Real_Value(MyEpochStr,1,Length(MyEpochStr)); // convert to real for mathmatical comparison if (int(MyEpoch / 1000) < 57) then // first launch in 1957 MyEpoch := (MyEpoch / 1000 + 2000) * 1000 // value < 57 so year is 21st century (2000 thru 2056)
else
MyEpoch := (MyEpoch / 1000 + 1900) * 1000; // value is >= 57 so year is 20th century (1957 thru 1999) MyEpochStr := FloatToStrF(MyEpoch,ffFixed,16,8); // store to MyEpochStr for later use (16 characters!)

{******************************************************************************}
{******************************************************************************}



support routines for the above:


  Function Integer_Value(buffer : string; start, length : integer) : integer;

  var
    MyResult : integer = 0;
    answer   : integer - 0;

  begin
    buffer := Copy(buffer,start,length);
    Convert_Blanks(buffer);
    if buffer = '' then
      buffer := '0';
    Val(buffer,answer,MyResult);
    if MyResult = 0 then
      Integer_Value := answer
    else
      Integer_Value := 0;
  end; // Function Integer_Value


  Function Real_Value(buffer : string; start, length : integer) : double;

  var
    MyResult : integer = 0;
    answer   : double = 0.0;

  begin
    buffer := Copy(buffer,start,length);
    Convert_Blanks(buffer);
    if buffer = '' then
      buffer := '0';
    Val(buffer,answer,MyResult);
    if MyResult = 0 then
      Real_Value := answer
    else
      Real_Value := 0.0;
  end; // Function Real_Value



for those interested in it, here's the fractional-doy breakout routine (in displayEpochString)...


  Function getJulianDay_Year(year : integer) : double;

  var
    dYear   : double = 0.0;
    a       : double = 0.0;
    b       : double = 0.0;
    dResult : double = 0.0;

  begin
    dYear := year - 1;
    A := Math.Floor(dYear / 100);
    B := 2 - A + Math.Floor(A / 4);
    dResult := Math.Floor(365.25 * dYear) + 1721422.9 + B;
    getJulianDay_Year := dResult;
  end;



  Function getJulianDay_SatEpoch(year : integer; dSatEpochDoY : integer) : 
double;

  var
    dResult : double = 0.0;

  begin
// this tidy section not needed any more with four digit years in epoch
//    //Tidy up the year and put it into the correct century
//    year := year mod 100;
//    if (year < 57) then                               // first launch in 1957
//      year := year + 2000
//    else
//      year := year + 1900;
dResult := getJulianDay_Year(year); // julian day of first of year
    dResult := dResult + dSatEpochDoY;                // add in jDoY
    getJulianDay_SatEpoch := dResult;
  end;



  Function displayEpochString(SatEpoch : double) : string;

  var
    test           : boolean = False;
    DT             : TDateTime;
    Y              : word = 0;
    Mo             : word = 0;
    D              : word = 0;
    H              : word = 0;
    Mi             : word = 0;
    S              : word = 0;
    MS             : word = 0;
    tstr           : string = '';
    MyEpochStr     : string = '';
    MyJEpoch       : double = 0.0;
    dWork          : double = 0.0;
    dWork1         : double = 0.0;
    MyEpochDayFrac : double = 0.0;
    MyEpochDoY     : integer = 0;
    MyEpochYear    : integer = 0;

  begin
    tstr := FloatToStr(SatEpoch);                     // whole epoch number
    if pos('.',tstr) < 1 then
      tstr := tstr + '.0';
    MyEpochStr  := AddChar('0',Copy(tstr,1,pos('.',tstr)-1),5);
MyEpochYear := Integer_Value(MyEpochStr,1,4); // epoch year - characters 1-4 because we adjusted to 4 digit year MyEpochDoY := Integer_Value(MyEpochStr,5,3); // epoch DoY - characters 5-8 because we adjusted to 4 digit year MyEpochDayFrac := Frac(Real_Value(tstr,pos('.',tstr),9)); // epoch fractional day starts with decimal point MyJEpoch := getJulianDay_SatEpoch(MyEpochYear, MyEpochDoY); // JD for year and DoY only. time portion calc'd below... test := TryJulianDateToDateTime(MyJEpoch,DT); // convert julian epoch to TDateTime record
    if test then
      begin
DecodeDateTime(DT,Y,Mo,D,H,Mi,S,MS); // pull TDateTime record apart dWork := MyEpochDayFrac * 24; // calc the hours from the fractional day of the epoch
        H := trunc(dWork);                            // store whole hours
        dWork1 := Frac(dWork);                        // get frac hours
dWork := dWork1 * 60; // calc the minutes from the fractional hours
        Mi := trunc(dWork);                           // store whole minutes
        dWork1 := Frac(dWork);                        // get frac minutes
dWork := dWork1 * 60; // calc the seconds from the fractional minutes
        S := trunc(dWork);                            // store whole seconds
        dWork1 := Frac(dWork);                        // get frac seconds
dWork := dWork1 * 1000; // calc the milliseconds from the fractional seconds MS := trunc(dWork); // store whole milliseconds - trunc() b/c we don't care about fractional part or rounding at this level DT := EncodeDateTime(Y,Mo,D,H,Mi,S,MS); // convert it all back to TDateTime record displayEpochString:=FormatDateTime('YYYY-MM-DD hh:nn:ss.zzz',DT); // send back a nicely formatted DateTime string
      end
    else
displayEpochString:='XXXX-XX-XX XX:XX:XX.XXX'; // send back all X's because Julian to DateTime failed
  end;


--
 NOTE: No off-list assistance is given without prior approval.
       Please *keep mailing list traffic on the list* unless
       private contact is specifically requested and granted.
_______________________________________________
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal

Reply via email to