ETHZ_Logo RAMSES_Logo_Right   RAMSES   RAMSES_Logo_Left Systems Ecology  
Start    search button      Modules:   A-Z   Function   Layer        QuickRefs:   DM   AuxLib   AuxLibE   SciLib   EasyMW   MW   ISIS   RMSLib

DEFINITION MODULE JulianDays;

  (*******************************************************************

    Module  JulianDays     (Version 3.0)

      Copyright (c) 1989-2006 by Andreas Fischlin and ETH Zurich.

    Purpose   Translate back and forth dates into a number of
              days (Julian days) in order to allow the computing
              with dates.

    Remarks   Julian days measure time continuously in days; where
              the integral part defines the number of days and the
              fractional part defines hours, minutes and seconds
              of the day not yet completed. The unit is J.D.,
              which stands for (unmodified) Julian Days.  The origin
              of the time scale can be set arbitrarily to any
              supported date. 
              
              This implementation supports the Gregorian calendar
              (Gregorian calendar correction by Pope Gregor
              XIII), which is valid after 15.Oct.1582 up to the
              present and much of the foreseeable future.  Note
              that this date followed immediately after
              4.Oct.1582 to correct for accumulated errors in the
              previously used Julian calendar.  The latter has
              been introduced by Julius Caesar "ab urbe
              condiata", the foundation of Rome, i.e. 753 BC and
              accounted already for months with variable day
              numbers and leap years to accomodate the actual
              length of the year, which was estimated to be
              365.25 days (see below, tropical year).  Note the
              10 day gap between the Julian and Gregorian
              calendar where the Julian calendar ends on October
              4, 1582 (JD = 2299160), and the Gregorian calendar
              starts immediately thereafter on October 15, 1582.
              The Gregorian calendar will need no corrections for
              3333 years.  Afterwards, the deviation of the
              calendar from the true tropical year will have
              accumulated to more than a day and another calendar
              correction will be required.

              Note, Julian Days sensu stricto all fall within the
              so-called Julian Period.  The latter is used in
              astronomy and has been proposed by Joseph Justus
              Scaliger (1581).  It begins with the First Julian
              Date (J.D.) = middle noon (12h00 standard world
              time or Greenwich time), 1.Jan.4713 BC (= year
              -4712).  Note, there is also the so-called modified
              Julian Date (M.J.D.) in use today (much used in
              space travel) which starts at 17.Nov.1858 00h00'00"
              => 0.0 M.J.D. = 2'400'000.5 J.D.
              
              The fractional part of a julian days value can
              represent any time as a fraction of 24 hours, i.e.
              (i) UT (Universal Time or Greenwich civil time
              based on the Earth's rotation and being 0.0 at
              midnight); (iii TAI (International Atomic Time);
              (iii) UTC (Coordinated Universal Time, the legal
              time, which is kept within 0.9 seconds of UT by
              introducing leap second as necessary); or (iv)
              standard time (often referred to as local time and
              defined by a fixed offset (in multiples of half
              hours) from UT).  In case your location is close to
              the international date line (~180° longitude) there
              is little risk to obtain a wrong date with any of
              above listed time systems.  If in doubt first
              convert to UT by subtracting the fixed offset before
              using any of the algorithms from this module.
              Note, this offset may vary with seasons as daylight
              saving time rules are now applied within most
              standard time zones (cf.
              http://en.wikipedia.org/wiki/Local_time).

              IMPLEMENTATION RESTRICTION: This module does not
              support the full Julian period and is fully valid
              only after 15th October 1582, since it's current
              implementation is restricted and does not correctly
              support the Gregorian calendar correction.  Instead
              it supports the often needed setting of an
              arbitrary set calendar range, where the minimum of
              the range corresponds to the origin of the time
              scale as measured in julian days (for details see
              routine SetCalendarRange).

              The year as actually perceived on Earth is the
              tropical year, i.e. the actual number of days (not
              really a constant of course): 365 days, 5 h, 48
              min, 46.98 sec

                tropical year = 365.242210416667 d

              The tropical year is different from the so-called
              sidereal year (siderisches Jahr).  It is the time
              the sun needs to complete a revolution measured
              relative to stars on the sun's orbit as seen on
              Earth: 365 days, 6 h, 9 min, 9.54 sec

                sidereal year = 365.256360416667 d


    Programming

      o Design
        Andreas Fischlin          24/09/1989

      o Implementation
        Andreas Fischlin          24/09/1989


    ETH Zurich
    Systems Ecology
    CHN E 35.1
    Universitaetstrasse 16
    8092 Zurich
    SWITZERLAND

    URLs:
        <mailto:RAMSES@env.ethz.ch>
        <http://www.sysecol.ethz.ch>
        <http://www.sysecol.ethz.ch/SimSoftware/RAMSES>


    Last revision of definition:  20/01/2000  AF

  *******************************************************************)


  CONST
    Jan = 1; Feb = 2; Mar = 3; Apr = 4; Mai = 5; Jun = 6;
    Jul = 7; Aug = 8; Sep = 9; Oct = 10; Nov = 11; Dec = 12;

    Sun = 1; Mon = 2; Tue = 3; Wed = 4; Thur = 5; Fri = 6; Sat = 7;

  TYPE
    Month = [Jan..Dec];
    WeekDay = [Sun..Sat];
    DateAndTime = RECORD
                    year: INTEGER;          (* e.g. 1582,...,1994,...,2040 etc.*)
                    month: Month;
                    day: INTEGER;           (* [1..31] (depends on month) *)
                    hour,                   (* [0..23] *)
                    min: INTEGER;           (* [0..59] *)
                    sec: INTEGER;           (* [0..59] *)
                    dayOfWeek: WeekDay;     (* e.g. Sun *)
                    secFrac: REAL;          (* fraction of a second,
                                               e.g. 0.13 for 13 hundredth of a second *)
                  END;

  PROCEDURE DateTimeToJulDay(dt: DateAndTime): LONGREAL;
  PROCEDURE JulDayToDateTime(jd: LONGREAL; VAR dt: DateAndTime);
  (*
    Above two routines allow to convert between a julian day given
    as a real number and an ordinary calendar date plus the time of
    the day.
  *)

  PROCEDURE DateToJulDay(day,month,year: INTEGER): LONGINT;
  PROCEDURE JulDayToDate(jd: LONGINT; VAR day: INTEGER;
                                      VAR month: Month;
                                      VAR year: INTEGER;
                                      VAR dayOfWeek: WeekDay);
  (*
    Above two routines allow to convert between a julian day and an
    ordinary calendar date. Hereby ignoring the time of the day.
  *)

  PROCEDURE IsLeapYear(yr: INTEGER): BOOLEAN;

  PROCEDURE SetCalendarRange(firstYear,lastYear,firstSunday: INTEGER);
    (*
      This procedure allows to set the calendar range for which
      the algorithms of this module shall work.  Basically they
      work correctly within the Gregorian Calendar, which starts
      from the date 15.Oct.1582 and needs no correction for the
      next 3333 years, i.e. till 4915.

      However, implementation restrictions reduce somewhat the
      actually usable range and require to satisfy strictly the
      following constraints: Parameter firstYear must be an year
      following immediately a leap year.  The day of the first
      Sunday in January in the first year (firstSunday) must be
      specified, otherwise weekdays can't be computed correctly
      and some algorithms will fail.  The origin of the time
      scale (0.0) as defined by a call to SetCalendarRange is the
      begin of the day with date 31st December of the year, which
      preceeds firstYear, i.e. 1.Jan.firstYear 0h00 = 1.0 J.D.
      The days between the origin of the time scale till the day
      before firstSunday are to be excluded (at most 7 days, i.e.
      the interval [0.0 ..  firstSunday) ).  The value for
      lastYear is by 1 smaller than 4915.  SetCalendarRange
      attempts to detect faulty values in the actual parameters.
      However, not all are checked fully, to allow for the use of
      this module within a calendar range before 15.Oct.1582
      (results without any warranty for correctness!).  If errors
      are detected, they will lead to an error condition (HALT)
      and the previous calendar range is preserved.  Correctness
      of the implementation has only been tested for the largest
      part of the Gregorian calendar, i.e. the range [6.Jan.1585
      ..  31.Dez.4914] (see below).

      For efficiency reasons, no tests are made in the routines
      JulDayToDate or JulDayToDateTime whether the actual julian
      day argument falls within the current calendar range.  If
      in doubt and to avoid the inevitable calendar range run
      time errors within JulDayToDate or JulDayToDateTime, use
      procedure JulDayInCalendar to check wether the actual
      julian day argument is valid.

      The default range is firstYear = 1949, lastYear = 2099,
      firstSunday = 2, since the 2nd January 1949 is a Sunday,
      which corresponds to the following call to SetCalendarRange:

        SetCalendarRange(1949,2099,2)

      Other possibilities within the supported Gregorian calendar
      range:

        Sunday, 6.Jan.1585  (1st possible date within Gregorian calendar)
        Sunday, 6.Jan.1805
        Sunday, 1.Jan.1809
        Sunday, 6.Jan.1861  (1st possible date within modified J.D. period)
        Sunday, 1.Jan.1905

        Sunday, 2.Jan.1949  (default used by this module)
        Sunday, 1.Jan.1967  (Unix systems use 1.1.1970 as origin)
        Sunday, 3.Jan.1971  (Unix systems use 1.1.1970 as origin)
        Sunday, 5.Jan.1997
        Sunday, 2.Jan.2000

      For your information, the 5th January -4711 (1.Jan.4712 BC)
      is a Sunday, i.e. it is the first Sunday in January within
      the period, which is covered by (unmodified) Julian days.
      Noon of this day, i.e. 12h00 world standard or Greenwich
      time [ST], corresponds to 370.0 J.D. This day started at
      0h00 ST ~ 369.5 J.D. and ended at 24h00 ST ~ 370.5 J.D.
      Note, this implementation does not prevent its use before
      the Gregorian calendar correction and may actually
      correctly function if only used for ranges before or after
      the 15th October 1582.  However, only little testing was
      done for the period before 15th October 1582.

      Note that calling this procedure may be useful in order to
      use Julian days of type INTEGER instead of LONGINT. Then
      the calendar routines can cover fully 137 years without
      causing an overflow when assigning the LONGINT result of
      procedure DateToJulDay to an INTEGER variable.  If using
      LONGINT the full Gregorian calendar period (15.Oct.1582
      till 4915) is covered.
    *)

  PROCEDURE GetCalendarRange(VAR firstYear,lastYear,firstSunday: INTEGER);
    (*
      Allows to inquire the currently set calendar range.
    *)

  PROCEDURE JulDayInCalendar(jd: LONGINT): BOOLEAN;
    (*
      Checks wether the julian day jd, falls within the
      currently set calendar range.  For efficiency reasons
      this test is neither done by routine JulDayToDate nor
      JulDayToDateTime.  If you wish to check it, you have to
      call JulDayInCalendar before calling one of above
      routines in order to avoid a program halt.  To check a
      julian day jd of type LONGREAL, call JulDayInCalendar
      as follows:

        JulDayInCalendar(LITRUNC(jd))

      where LITRUNC is from module DMPortab.
    *)

END JulianDays.

  Contact RAMSES@env.ethz.ch Last updated: 25-Jul-2011 [Top of page]