|
|
|
|
||
|
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.
|
||
|
|
|