Board index » delphi » Need help with julian date functions

Need help with julian date functions

I got these functions from the SWAG archives and they work great except
for one small thing. I had to modify the DateToJulian routine since the
year 2001 came up essentially as 1901 and it made it useless for date
sorting.

The data I'm working with starts in the calendar year 1994.

Here are the functions. The DateToJulian is working and sorts the data
just fine. The problem arises when I try to convert back fom julian to
the xx/xx/xx format. I'm absolutely stumped as to where or how to reduce
the julian number to get back my original data.

***************

function DateFactor(MonthNum, DayNum, YearNum : Real) : Real;

{ Needed by DateToJulian function. Taken from SWAG. }

var
  Factor : Real;
begin
  Factor := (365 * YearNum) + DayNum + (31 * (MonthNum - 1));
  if MonthNum < 3 then
    Factor :=  Factor + Int((YearNum-1) / 4) -
               Int(0.75 * (Int((YearNum-1) / 100) + 1))
  else
    Factor :=  Factor - Int(0.4 * MonthNum + 2.3) + Int(YearNum / 4) -
               Int(0.75 * (Int(YearNum / 100) + 1));
  DateFactor := Factor;
end;

function DateToJulian(DateLine : S8) : longint;

{ modified julian date function that takes in account for year 2000
  since our database is from 1994 on }

var
  Factor, MonthNum, DayNum, YearNum : Real;
  Ti : longint;

begin
  if Length(DateLine) = 7 then
    DateLine := '0' + DateLine;
  MonthNum := 0.0;
  for Ti := 1 to 2 do
    MonthNum := (10 * MonthNum) + (Ord(DateLine[Ti])-Ord('0'));
  DayNum := 0.0;
  for Ti := 4 to 5 do
    DayNum := (10 * DayNum) + (Ord(DateLine[Ti])-Ord('0'));
  YearNum := 0.0;
  for Ti := 7 to 8 do
    YearNum := (10 * YearNum) + (Ord(DateLine[Ti])-Ord('0'));

{ Modified here. Since my data starts with the year 1994, years after 1999
  would be showing up as before 1994. By adding 100 to any 2 digit year
  less than 9, problem was solved. }

  if DateLine[7] < '9' then
     YearNum := YearNum + 100;
  Factor := DateFactor(MonthNum, DayNum, YearNum);
  Ti := trunc((Factor - 679351.0) - 32767.0);
  if Ti < 0 then Ti := Ti + 2147483647;
  DatetoJulian := Ti;
end;

function JulianToDate( DateInt : longint ): S11;

Var
  holdstr,
  strDay   : string[2];
  anystr   : string[11];
  StrMonth : string[3];
  stryear  :  string[4];
  test, error, I : Integer;
  Dummy, Year : longint;
  Save, Temp : Real;
  JulianToanystring : S11;

begin
   i := 0;
   holdstr := '';
   JulianToanystring := '00000000000';
   if DateInt = 2147483647 then
      DateInt := 0;
   Temp  := int(DateInt) + 32767 + 679351.0;
   Save  := Temp;
   Dummy := trunc(Temp/365.5) ;
   while Save >= DateFactor(1.0,1.0,Dummy+0.0) do
   begin
      Dummy := Succ(Dummy);
      i := i + 1;
   end;
   Dummy := Pred(Dummy);
   Year  := Dummy;

   { Determine number Of Days into current year }

   Temp  := 1.0 + Save - DateFactor(1.0,1.0,Year+0.0);

   { Put the Year into the output string }

   for I := 8 downto 5 do
   begin
      JulianToanystring[I] := Char((Dummy mod 10) + Ord('0'));
      Dummy := Dummy div 10;
   end;
   Dummy := 1 + Trunc(Temp/31.5);
   while Save >= DateFactor(Dummy+0.0,1.0,Year+0.0) do
      Dummy := Succ(Dummy);
   Dummy := Pred(Dummy);
   Temp  := 1.0 + Save - DateFactor(Dummy+0.0,1.0,Year+0.0);
   for I := 2 downto 1 do
   begin
      JulianToanystring[I] := Char((Dummy mod 10)+Ord('0'));
      Dummy := Dummy div 10;
   end;
   Dummy := Trunc(Temp);
   for I := 4 downto 3 do
   begin
      JulianToanystring[I] := Char((Dummy mod 10)+Ord('0'));
      Dummy := Dummy div 10;
   end;
   holdstr := copy(juliantoanystring,1,2);
   val(holdstr, test, error);
   case test of

   1 : StrMonth := 'Jan';

   2 : StrMonth := 'Feb';

   3 : StrMonth := 'Mar';

   4 : StrMonth := 'Apr';

   5 : StrMonth := 'May';

   6 : StrMonth := 'Jun';

   7 : StrMonth := 'Jul';

   8 : StrMonth := 'Aug';

   9 : StrMonth := 'Sep';

   10 : StrMonth := 'Oct';

   11 : StrMonth := 'Nov';

   12 : StrMonth := 'Dec';

   end;
   stryear := copy(juliantoanystring, 5, 4);
   strDay  := copy(juliantoanystring, 3, 2);
   anystr  := StrDay + '-' + StrMonth + '-' +stryear;
   JulianToDate := anystr;
end;

*************

Any help would be appreciated in this!

--
Happy birthday HAL - 1/12/97

 

Re:Need help with julian date functions


In article <5bomqt$...@nexp.crl.com>, dtur...@crl.com says...

Quote
>...Here are the functions. The DateToJulian is working and sorts the data
>just fine. The problem arises when I try to convert back fom julian to
>the xx/xx/xx format. I'm absolutely stumped as to where or how to reduce
>the julian number to get back my original data.

This routine ought to do exactly what you want. If not using the 80387,
just substitute 'real' for 'single' and 'extended' floating point types.

procedure GregorianDate(JD: extended; var yr,mn,dy: single);
{**********************************************************}
{ Convert a Julian Day number to a Gregorian Calendar date
  Procedure valid for all dates since January 1st 4713 B.C.
  Duffet-Smith: Practical Astronomy with Your Calculator p.11 }
var J,I,F,A,B,C,D,E,G : extended;

begin
     { add 0.5 to Julian Date }
      J := JD + 0.5;
     { set I integer part & F fractional part of J }
      I := int(J); F := frac(J);

     { Compute intermediate quantities A,B,C,D,E,G }

     If I > 2299160 then
        A := int( (I-1867216.25) / 36524.25 )
     else
        A := I ;

     B := I + 1 + A - int(A/4);
     C := B + 1524 ;
     D := int( (c-122.1) / 365.25 );
     E := int(365.25*D) ;
     G := int( (C-E) / 30.6001 );

    { From these calculate the day, month, and year (Gregorian) }
    { Day }
    dy := C-E+F-int(30.6001*G);
    { Month }
    If G < 13.5 then mn := G-1 else mn := G-13;
    { Year }
    If mn > 2.5 then yr := D-4716 else yr := D-4715;

end; { GregorianDate() }

Re:Need help with julian date functions


In article <5bpgtn$...@tron.sci.fi> of Sat, 18 Jan 1997 03:43:51 in
comp.lang.pascal.borland, The Bishop <jes...@inq.fi> wrote:

Quote
>In article <5bomqt$...@nexp.crl.com>, dtur...@crl.com says...

>>...Here are the functions. The DateToJulian is working and sorts the data
>>just fine. The problem arises when I try to convert back fom julian to
>>the xx/xx/xx format. I'm absolutely stumped as to where or how to reduce
>>the julian number to get back my original data.

>This routine ought to do exactly what you want. If not using the 80387,
>just substitute 'real' for 'single' and 'extended' floating point types.

>procedure GregorianDate(JD: extended; var yr,mn,dy: single);
>{**********************************************************}
>{ Convert a Julian Day number to a Gregorian Calendar date
>  Procedure valid for all dates since January 1st 4713 B.C.
>  Duffet-Smith: Practical Astronomy with Your Calculator p.11 }

   Duffett-Smith
You don't say which edition; but p.11 matches the 2nd edition.

Quote
>var J,I,F,A,B,C,D,E,G : extended;

There OUGHT to be an expression of the algorithm which uses whole-number
variables only, since the calendar is essentially digital rather than
analogue.  I have converted a standard date-to-MJD routine from floats
to integers, in /programs/mjd_test.pas at sig URL.

Quote
>     If I > 2299160 then
>        A := int( (I-1867216.25) / 36524.25 )
>     else
>        A := I ;
>     B := I + 1 + A - int(A/4);

I have suspected a typo in the book in the lines which lead to this, and
I suspect also a miscoding of the book
.
Book: "Otherwise, set A=I." - should that be B=I ??  I'm asking P D-S.
Pending better evidence, I advise careful checking around JD 2299160.  I
get :

        2299160     6303  10  31
        2299161     1582  10  16 - and a bit thereafter is plausible.

JD 2299160 is the Gregorian adjustment date - in 1582, so take care if
where you live was British (we changed in 1752).  To avoid such, I'd
rather use a MJD function, which eliminates the adjustment and the half-
day problems.

I changed the code to what I think the book should have :

     If I > 2299160 then begin
        A := int( (I-1867216.25) / 36524.25 );
        B := I + 1 + A - int(A/4) end
     else
        B := I ;

and this gives better, but not perfect results;  
        2299155   1582   9  30
        2299156   1582   9  31        <???
        2299157   1582  10   2
        2299158   1582  10   3
        2299159   1582  10   4
        2299160   1582  10   5
        2299161   1582  10  16   and thence OK for at least 5 days

Actually, the revised Pascal algorithm seems to make Oct 1st into Sept
31st in other years, including 1997.

I ADVISE CAREFUL CHECKING.  Something like a
        for JD := 2200000 to 2700000 do begin
          GregorianDate(JD, yr, mn, dy) ;
          (* Check that dy went up by 1, or was month-end & is 1 & month
             went up by 1, or was 12 & is 1 & year increnented; else
             report *)
          end ;
--
John Stockton, Surrey, UK.  j...@merlyn.demon.co.uk  Turnpike v1.12  MIME
    http://www.merlyn.demon.co.uk/
    My news-service had variable input backlog, 0-24 hours.

Re:Need help with julian date functions


In article <vEcz2RAB754yE...@merlyn.demon.co.uk>,
   Dr John Stockton <j...@merlyn.demon.co.uk> wrote:

Quote
>I changed the code to what I think the book should have :

>     If I > 2299160 then begin
>        A := int( (I-1867216.25) / 36524.25 );
>        B := I + 1 + A - int(A/4) end
>     else
>        B := I ;

>and this gives better, but not perfect results;  
>        2299155   1582   9  30
>        2299156   1582   9  31        <???
>        2299157   1582  10   2
>        2299158   1582  10   3
>        2299159   1582  10   4
>        2299160   1582  10   5
>        2299161   1582  10  16   and thence OK for at least 5 days

>Actually, the revised Pascal algorithm seems to make Oct 1st into Sept
>31st in other years, including 1997.

I have the 3rd edition of the book and the algorithm described is exactly
as shown above. I ran it and it gave me perfect results. I noticed that
you use integer date. Did you notice that the book uses the fractional
part of the date? If you rounded the date, this is why you have a 1 day
difference and you get an error on the 1st of the month. In case this
is not the error, I can send you the program I made, so that you can
find the difference.

Hope I helped

Babis Athineos

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*  E-mail: mailto:ba...@hol.gr        *  Snail-mail: Papadoniou 61  *
*  WWW   : http://users.hol.gr/~babis *              11145 Athens   *
*                                     *              Greece         *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

Re:Need help with julian date functions


On 1997-01-17 dtur...@crl.com said:
   >data just fine. The problem arises when I try to convert back fom
   >julian to the xx/xx/xx format. I'm absolutely stumped as to where
   >or how to reduce the julian number to get back my original data.

Here's a TP4 function I wrote years ago to solve this problem for
astronomical applications.  This function returns a string containing
the local date and time for ANY valid Julian Day, and will correctly
allow for all 366-day years. It's worked well for me; but feel free to
modify it to your purposes. A short example program is appended.

I chose to return this string in the astronomical format of: "yyyy mmm
dd hh:mm"  where "mmm" is the month _name_.  Spelling out the month
avoids interpretation problems, eg: I read "1997 01 10" as January 10,
but Americans read it as October 1.  I will leave to you the problems of
non-English month names, and "Summer Time" <g> !

If you need some test data, the American Association of Variable Star
Observers produces calendars giving the Julian Day Numbers for each day
of the year.  The 1997 calendar is available from their website at
http://www.aavso.org

cheers,
Fraser Farrell

..THE WORLD WILL END TONIGHT AT 9:00pm (9:30pm in Adelaide)...

{----- cut here -------------------------------------------------------}

function jdtodate (jday : extended; tzone : real) : string ;
{takes a Julian Day "jday" and converts to local date & time according
to the time zone "tzone" specified.  "jday" can have values from 0 up to
several million, and a fractional part, so it has to be Extended type.
"tzone" is NOT an Integer because some of us are afflicted with strange
time zones!  The use of "Trunc" may occasionally cause an error of one
minute in the returned time.

A test value : JD 2450450.0000 = 1997 Jan 01 12:00 UT }

const
    monthname : array [1..12] of string[3] =
     ('Jan','Feb','Mar','Apr','May','Jun',
     'Jul','Aug','Sep','Oct','Nov','Dec');

var
    jd,jdf,alpha,a,b,c,d,e      : longint;
    minute,hour,day,month,year  : integer;
    minutes,hours,days,months,years   : string[5];

begin
    if jday > 0 then       {Julian Day <= 0 is meaningless}
        begin
          {add the time zone to the Julian Day, and reset to UT midnight}
          jday:=jday+0.5+tzone/24;
          {cut out the whole and fractional parts}
          jd:=trunc(jday); jdf:=jday-jd;

          if jd<2299161 then a:=jd      {Julian Calendar < 1582 Oct 15}
             else                       {Gregorian Calendar}
                        begin
                    alpha:=trunc((jd-1867216.25)/36524.25);
               a:=jd+1+alpha-trunc(alpha/4);  {leap year correction}
                       end;
                b:=a+1524;
                c:=trunc((b-122.1)/365.25);
                d:=trunc(365.25*c);
                e:=trunc((b-d)/30.6001);

          {extract the year month & day}
                day:=b-d-trunc(30.6001*e);
                if e<14 then month:=e-1 else month:=e-13;
                if month>2 then year:=c-4716 else year:=c-4715;

          {extract hours and minutes from the julian day fraction}
          hour:=trunc(24*jdf); minute:=trunc(1440*jdf-60*hour);

          {convert month number to a name}
          months:=monthname[month];
          {convert year to a string - easier to handle later on...}
          str(year,years);

          {add a "0" to the front of days,hours,minutes <10 ; and
          convert to strings}
          if day<10 then
             begin str(day:1,days); days:=concat('0',days) end
                   else str(day:2,days);
          if hour<10 then
             begin str(hour:1,hours); hours:=concat('0',hours) end
                   else str(hour:2,hours);
          if minute<10 then
             begin str(minute:1,minutes); minutes:=concat('0',minutes) end
                   else str(minute:2,minutes);

          {build the output string}
          jdtodate:=concat(years,' ',months,' ',days,' ',hours,':',minutes);
       end
        else jdtodate:='JD conversion error';
end;

{--- demo program -------------------------------------------------------}

{$N+,E+}  {MUST be compiled with these switches}
var  JD : extended;
     local_time_zone : real;

begin
write('Julian Day number ? '); readln(JD);
writeln;
writeln('The equivalent local times are :');
writeln('                    UT = ',jdtodate(JD,0));
writeln('         Alice Springs = ',jdtodate(JD,9.5));
writeln('                Sydney = ',jdtodate(JD,10));
writeln('              New York = ',jdtodate(JD,-5));
writeln('Auckland (summer time) = ',jdtodate(JD,13));
writeln('               Teheran = ',jdtodate(JD,3.5));
writeln('          Buenos Aires = ',jdtodate(JD,-3));
end.

Net-Tamer V 1.08 - Registered

Re:Need help with julian date functions


Sorry if you get the following message twice, but I don't find it using
DejaNews, so I repost it (our news server has many problems lately...)

In article <vEcz2RAB754yE...@merlyn.demon.co.uk>,
   Dr John Stockton <j...@merlyn.demon.co.uk> wrote:

Quote
>I changed the code to what I think the book should have :

>     If I > 2299160 then begin
>        A := int( (I-1867216.25) / 36524.25 );
>        B := I + 1 + A - int(A/4) end
>     else
>        B := I ;

>and this gives better, but not perfect results;  
>        2299155   1582   9  30
>        2299156   1582   9  31        <???
>        2299157   1582  10   2
>        2299158   1582  10   3
>        2299159   1582  10   4
>        2299160   1582  10   5
>        2299161   1582  10  16   and thence OK for at least 5 days

>Actually, the revised Pascal algorithm seems to make Oct 1st into Sept
>31st in other years, including 1997.

I have the 3rd edition of the book and the algorithm described is exactly
as shown above. I ran it and it gave me perfect results. I noticed that
you use integer date. Did you notice that the book uses the fractional
part of the date? If you rounded the date, this is why you have a 1 day
difference and you get an error on the 1st of the month. In case this
is not the error, I can send you the program I made, so that you can
find the difference.

Hope I helped

Babis Athineos

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*  E-mail: mailto:ba...@hol.gr        *  Snail-mail: Papadoniou 61  *
*  WWW   : http://users.hol.gr/~babis *              11145 Athens   *
*                                     *              Greece         *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

Re:Need help with julian date functions


In article <vEcz2RAB754yE...@merlyn.demon.co.uk> of Mon, 20 Jan 1997
16:35:13 in comp.lang.pascal.borland, Dr John Stockton

Quote
<j...@merlyn.demon.co.uk> wrote:

>>     If I > 2299160 then
>>        A := int( (I-1867216.25) / 36524.25 )
>>     else
>>        A := I ;
>>     B := I + 1 + A - int(A/4);

>I have suspected a typo in the book in the lines which lead to this, and
>I suspect also a miscoding of the book
>.
>Book: "Otherwise, set A=I." - should that be B=I ??  I'm asking P D-S.

JRS -> PD-S :

Quote
> However, I suspect a misprint in the book itself : should the last
> part of section 2 read not A=I but B=I ?  I'm fairly convinced that it
> should.

PD-S -> JRS :

Quote
> You are quite right about the misprint, which was corrected in the
> third edition of "Practical Astronomy with your Calculator". As for
> the PASCAL version, I suspect that the programmer has not been careful
> about the differences between the TRUNC, INT, and ROUND functions.

> You might be interested in "Astronomy with your Personal Computer"
> (second edition) if you wish to write your own programs, or more
> recently "Easy PC Astronomy", both of which I have published with
> Cambridge University Press.

So I'm now convinced that the following is the correct code ;

   If I > 2299160 then begin
        A := int( (I-1867216.25) / 36524.25 );
        B := I + 1 + A - int(A/4) end
     else
        B := I ;

--
John Stockton, Surrey, UK.  j...@merlyn.demon.co.uk  Turnpike v1.12  MIME
    http://www.merlyn.demon.co.uk/
    My news-service has had variable delivery backlog, 0-60 hours; now <<1.
    Standard signature separator is as above, a line containing "-- "

Other Threads