Degenerate Conic

Algorithms • Modern Fortran Programming • Orbital Mechanics

Aug 12, 2017

Time Conversions with SPICE

vintage-old-clock-vector

JPL's SPICE Toolkit (SPICELIB) is the premier software library for computations related to solar system geometry. It is freely distributed, and is also one of the best-documented libraries I have ever come across. SPICELIB also includes a comprehensive set of routines for date and time conversions. An example is shown here:

program spice_test

use iso_fortran_env, only: wp => real64

implicit none

interface
    ! SPICELIB routines
    subroutine timout ( et, pictur, output )
        import :: wp
        implicit none
        real(wp),intent(in) :: et
        character(len=*),intent(in) :: pictur
        character(len=*),intent(out) :: output
    end subroutine timout
    subroutine str2et ( string, et )
        import :: wp
        implicit none
        character(len=*),intent(in) :: string
        real(wp),intent(out) :: et
    end subroutine str2et
    subroutine furnsh ( file )
        implicit none
        character(len=*),intent(in) :: file
    end subroutine furnsh
end interface

character(len=*),parameter :: time_in = &
    '2017 Aug 12 00:00:00 TDB'
character(len=*),parameter :: pictur = &
    'Mon DD,YYYY HR:MN:SC.#### UTC ::UTC'
real(wp) :: et
character(len=100) :: time_out

! load the leap second kernel:
call furnsh('naif0012.tls')

! example conversion:
call str2et(time_in, et)
call timout(et, pictur, time_out)

write(*,*) 'time_in: ', time_in
write(*,*) 'et: ', et
write(*,*) 'time_out: ', time_out

end program spice_test

A few things to note:

  • Here we are using the SPICE routines str2et and timout to convert a string from a TDB calendar date to ephemeris time and then to a UTC calendar date. These routines are very flexible and can convert a wide range of date formats. Other routines are available to do other transformations.
  • The base time system of SPICE is Barycentric Dynamical Time (TDB). "Ephemeris time" is a count of TDB seconds since the J2000 epoch (Jan 1, 2000 12:00:00).
  • We have to load the latest leap second kernel (naif0012.tls in this case), which is necessary to define UTC.
  • The SPICE routines are not in a module (the code is Fortran 77), and so have no explicit interfaces. Thus it is good practice to specify them as I do here.

The output of this example is:

time_in:  2017 Aug 12 00:00:00 TDB
et:       555768000.00000000
time_out: Aug 11,2017 23:58:50.8169 UTC

See also

Jan 22, 2015

Julian Date

Julian date is a count of the number of days since noon on January 1, 4713 BC in the proleptic Julian calendar. This epoch was chosen by Joseph Scaliger in 1583 as the start of the "Julian Period": a 7,980 year period that is the multiple of the 19-year Metonic cycle, the 28-year solar/dominical cycle, and the 15-year indiction cycle. It is a conveniently-located epoch since it precedes all written history. A simple Fortran function for computing Julian date given the Gregorian calendar year, month, day, and time is:

function julian_date(y,m,d,hour,minute,sec)

use, intrinsic :: iso_fortran_env, only: wp => real64

implicit none

real(wp) :: julian_date
integer,intent(in) :: y,m,d ! Gregorian year, month, day
integer,intent(in) :: hour,minute,sec ! Time of day

integer :: julian_day_num

julian_day_num = d-32075+1461*(y+4800+(m-14)/12)/4+367*&
                 (m-2-(m-14)/12*12)/12-3*((y+4900+(m-14)/12)/100)/4

julian_date = real(julian_day_num,wp) + &
              (hour-12.0_wp)/24.0_wp + &
              minute/1440.0_wp + &
              sec/86400.0_wp

end function julian_date

References

  1. "Converting Between Julian Dates and Gregorian Calendar Dates", United States Naval Observatory.
  2. D. Steel, "Marking Time: The Epic Quest to Invent the Perfect Calendar", John Wiles & Sons, 2000.

Aug 24, 2014

Computus

eggs

The Computus is the algorithm for the calculation of the date of Easter. The following is a simple Fortran subroutine of the Computus, using the "Meeus/Jones/Butcher" Gregorian Easter algorithm. Note that this subroutine makes use of Fortran integer division.

subroutine easter(year,month,day)
!Compute the date of Gregorian Easter,
! using the "Meeus/Jones/Butcher" algorithm

implicit none

integer,intent(in) :: year
integer,intent(out) :: month,day

integer :: a,b,c,d,e,f,g,h,i,k,l,m

a = mod(year,19)
b = year/100
c = mod(year,100)
d = b/4
e = mod(b,4)
f = (b+8)/25
g = (b-f+1)/3
h = mod((19*a+b-d-g+15),30)
i = c/4
k = mod(c,4)
l = mod((32+2*e+2*i-h-k),7)
m = (a+11*h+22*l)/451
month = (h+l-7*m+114)/31
day = mod(h+l-7*m+114,31)+1

end subroutine easter

The sequence of dates repeat themselves over a cycle of 5,700,000 years. The following histogram shows the percentage occurrence of each date (from March 22nd to April 25th), over the entire cycle:

easter2

See also

  1. D. Steel, "Marking Time: The Epic Quest to Invent the Perfect Calendar", Wiley, 1999.
  2. J. R. Stockton, "The Calculation of Easter Sunday after the Book of Common Prayer of the Church of England".