Annotation of embedaddon/php/ext/calendar/julian.c, revision 1.1.1.1

1.1       misho       1: /* $selId: julian.c,v 2.0 1995/10/24 01:13:06 lees Exp $
                      2:  * Copyright 1993-1995, Scott E. Lee, all rights reserved.
                      3:  * Permission granted to use, copy, modify, distribute and sell so long as
                      4:  * the above copyright and this permission statement are retained in all
                      5:  * copies.  THERE IS NO WARRANTY - USE AT YOUR OWN RISK.
                      6:  */
                      7: 
                      8: /**************************************************************************
                      9:  *
                     10:  * These are the externally visible components of this file:
                     11:  *
                     12:  *     void
                     13:  *     SdnToJulian(
                     14:  *         long int  sdn,
                     15:  *         int      *pYear,
                     16:  *         int      *pMonth,
                     17:  *         int      *pDay);
                     18:  *
                     19:  * Convert a SDN to a Julian calendar date.  If the input SDN is less than
                     20:  * 1, the three output values will all be set to zero, otherwise *pYear
                     21:  * will be >= -4713 and != 0; *pMonth will be in the range 1 to 12
                     22:  * inclusive; *pDay will be in the range 1 to 31 inclusive.
                     23:  *
                     24:  *     long int
                     25:  *     JulianToSdn(
                     26:  *         int inputYear,
                     27:  *         int inputMonth,
                     28:  *         int inputDay);
                     29:  *
                     30:  * Convert a Julian calendar date to a SDN.  Zero is returned when the
                     31:  * input date is detected as invalid or out of the supported range.  The
                     32:  * return value will be > 0 for all valid, supported dates, but there are
                     33:  * some invalid dates that will return a positive value.  To verify that a
                     34:  * date is valid, convert it to SDN and then back and compare with the
                     35:  * original.
                     36:  *
                     37:  * VALID RANGE
                     38:  *
                     39:  *     4713 B.C. to at least 10000 A.D.
                     40:  *
                     41:  *     Although this software can handle dates all the way back to 4713
                     42:  *     B.C., such use may not be meaningful.  The calendar was created in
                     43:  *     46 B.C., but the details did not stabilize until at least 8 A.D.,
                     44:  *     and perhaps as late at the 4th century.  Also, the beginning of a
                     45:  *     year varied from one culture to another - not all accepted January
                     46:  *     as the first month.
                     47:  *
                     48:  * CALENDAR OVERVIEW
                     49:  *
                     50:  *     Julias Ceasar created the calendar in 46 B.C. as a modified form of
                     51:  *     the old Roman republican calendar which was based on lunar cycles.
                     52:  *     The new Julian calendar set fixed lengths for the months, abandoning
                     53:  *     the lunar cycle.  It also specified that there would be exactly 12
                     54:  *     months per year and 365.25 days per year with every 4th year being a
                     55:  *     leap year.
                     56:  *
                     57:  *     Note that the current accepted value for the tropical year is
                     58:  *     365.242199 days, not 365.25.  This lead to an 11 day shift in the
                     59:  *     calendar with respect to the seasons by the 16th century when the
                     60:  *     Gregorian calendar was created to replace the Julian calendar.
                     61:  *
                     62:  *     The difference between the Julian and today's Gregorian calendar is
                     63:  *     that the Gregorian does not make centennial years leap years unless
                     64:  *     they are a multiple of 400, which leads to a year of 365.2425 days.
                     65:  *     In other words, in the Gregorian calendar, 1700, 1800 and 1900 are
                     66:  *     not leap years, but 2000 is.  All centennial years are leap years in
                     67:  *     the Julian calendar.
                     68:  *
                     69:  *     The details are unknown, but the lengths of the months were adjusted
                     70:  *     until they finally stablized in 8 A.D. with their current lengths:
                     71:  *
                     72:  *         January          31
                     73:  *         February         28/29
                     74:  *         March            31
                     75:  *         April            30
                     76:  *         May              31
                     77:  *         June             30
                     78:  *         Quintilis/July   31
                     79:  *         Sextilis/August  31
                     80:  *         September        30
                     81:  *         October          31
                     82:  *         November         30
                     83:  *         December         31
                     84:  *
                     85:  *     In the early days of the calendar, the days of the month were not
                     86:  *     numbered as we do today.  The numbers ran backwards (decreasing) and
                     87:  *     were counted from the Ides (15th of the month - which in the old
                     88:  *     Roman republican lunar calendar would have been the full moon) or
                     89:  *     from the Nonae (9th day before the Ides) or from the beginning of
                     90:  *     the next month.
                     91:  *
                     92:  *     In the early years, the beginning of the year varied, sometimes
                     93:  *     based on the ascension of rulers.  It was not always the first of
                     94:  *     January.
                     95:  *
                     96:  *     Also, today's epoch, 1 A.D. or the birth of Jesus Christ, did not
                     97:  *     come into use until several centuries later when Christianity became
                     98:  *     a dominant religion.
                     99:  *
                    100:  * ALGORITHMS
                    101:  *
                    102:  *     The calculations are based on two different cycles: a 4 year cycle
                    103:  *     of leap years and a 5 month cycle of month lengths.
                    104:  *
                    105:  *     The 5 month cycle is used to account for the varying lengths of
                    106:  *     months.  You will notice that the lengths alternate between 30 and
                    107:  *     31 days, except for three anomalies: both July and August have 31
                    108:  *     days, both December and January have 31, and February is less than
                    109:  *     30.  Starting with March, the lengths are in a cycle of 5 months
                    110:  *     (31, 30, 31, 30, 31):
                    111:  *
                    112:  *         Mar   31 days  \
                    113:  *         Apr   30 days   |
                    114:  *         May   31 days    > First cycle
                    115:  *         Jun   30 days   |
                    116:  *         Jul   31 days  /
                    117:  *
                    118:  *         Aug   31 days  \
                    119:  *         Sep   30 days   |
                    120:  *         Oct   31 days    > Second cycle
                    121:  *         Nov   30 days   |
                    122:  *         Dec   31 days  /
                    123:  *
                    124:  *         Jan   31 days  \
                    125:  *         Feb 28/9 days   |
                    126:  *                          > Third cycle (incomplete)
                    127:  *
                    128:  *     For this reason the calculations (internally) assume that the year
                    129:  *     starts with March 1.
                    130:  *
                    131:  * TESTING
                    132:  *
                    133:  *     This algorithm has been tested from the year 4713 B.C. to 10000 A.D.
                    134:  *     The source code of the verification program is included in this
                    135:  *     package.
                    136:  *
                    137:  * REFERENCES
                    138:  *
                    139:  *     Conversions Between Calendar Date and Julian Day Number by Robert J.
                    140:  *     Tantzen, Communications of the Association for Computing Machinery
                    141:  *     August 1963.  (Also published in Collected Algorithms from CACM,
                    142:  *     algorithm number 199).  [Note: the published algorithm is for the
                    143:  *     Gregorian calendar, but was adjusted to use the Julian calendar's
                    144:  *     simpler leap year rule.]
                    145:  *
                    146:  **************************************************************************/
                    147: 
                    148: #include "sdncal.h"
                    149: #include <limits.h>
                    150: 
                    151: #define JULIAN_SDN_OFFSET         32083
                    152: #define DAYS_PER_5_MONTHS  153
                    153: #define DAYS_PER_4_YEARS   1461
                    154: 
                    155: void SdnToJulian(
                    156:                                        long int sdn,
                    157:                                        int *pYear,
                    158:                                        int *pMonth,
                    159:                                        int *pDay)
                    160: {
                    161:        int year;
                    162:        int month;
                    163:        int day;
                    164:        long int temp;
                    165:        int dayOfYear;
                    166: 
                    167:        if (sdn <= 0) {
                    168:                goto fail;
                    169:        }
                    170:        /* Check for overflow */
                    171:        if (sdn > (LONG_MAX - JULIAN_SDN_OFFSET * 4 + 1) / 4 || sdn < LONG_MIN / 4) {
                    172:                goto fail;
                    173:        }
                    174:        temp = sdn * 4 + (JULIAN_SDN_OFFSET * 4 - 1);
                    175: 
                    176:        /* Calculate the year and day of year (1 <= dayOfYear <= 366). */
                    177:        {
                    178:                long yearl = temp / DAYS_PER_4_YEARS;
                    179:                if (yearl > INT_MAX || yearl < INT_MIN) {
                    180:                        goto fail;
                    181:                }
                    182:                year = (int) yearl;
                    183:        }
                    184:        dayOfYear = (temp % DAYS_PER_4_YEARS) / 4 + 1;
                    185: 
                    186:        /* Calculate the month and day of month. */
                    187:        temp = dayOfYear * 5 - 3;
                    188:        month = temp / DAYS_PER_5_MONTHS;
                    189:        day = (temp % DAYS_PER_5_MONTHS) / 5 + 1;
                    190: 
                    191:        /* Convert to the normal beginning of the year. */
                    192:        if (month < 10) {
                    193:                month += 3;
                    194:        } else {
                    195:                year += 1;
                    196:                month -= 9;
                    197:        }
                    198: 
                    199:        /* Adjust to the B.C./A.D. type numbering. */
                    200:        year -= 4800;
                    201:        if (year <= 0)
                    202:                year--;
                    203: 
                    204:        *pYear = year;
                    205:        *pMonth = month;
                    206:        *pDay = day;
                    207:        return;
                    208: 
                    209: fail:
                    210:        *pYear = 0;
                    211:        *pMonth = 0;
                    212:        *pDay = 0;
                    213: }
                    214: 
                    215: long int JulianToSdn(
                    216:                                                int inputYear,
                    217:                                                int inputMonth,
                    218:                                                int inputDay)
                    219: {
                    220:        int year;
                    221:        int month;
                    222: 
                    223:        /* check for invalid dates */
                    224:        if (inputYear == 0 || inputYear < -4713 ||
                    225:                inputMonth <= 0 || inputMonth > 12 ||
                    226:                inputDay <= 0 || inputDay > 31) {
                    227:                return (0);
                    228:        }
                    229:        /* check for dates before SDN 1 (Jan 2, 4713 B.C.) */
                    230:        if (inputYear == -4713) {
                    231:                if (inputMonth == 1 && inputDay == 1) {
                    232:                        return (0);
                    233:                }
                    234:        }
                    235:        /* Make year always a positive number. */
                    236:        if (inputYear < 0) {
                    237:                year = inputYear + 4801;
                    238:        } else {
                    239:                year = inputYear + 4800;
                    240:        }
                    241: 
                    242:        /* Adjust the start of the year. */
                    243:        if (inputMonth > 2) {
                    244:                month = inputMonth - 3;
                    245:        } else {
                    246:                month = inputMonth + 9;
                    247:                year--;
                    248:        }
                    249: 
                    250:        return ((year * DAYS_PER_4_YEARS) / 4
                    251:                        + (month * DAYS_PER_5_MONTHS + 2) / 5
                    252:                        + inputDay
                    253:                        - JULIAN_SDN_OFFSET);
                    254: }
                    255: 
                    256: /*
                    257:  * Local variables:
                    258:  * tab-width: 4
                    259:  * c-basic-offset: 4
                    260:  * End:
                    261:  * vim600: sw=4 ts=4 fdm=marker
                    262:  * vim<600: sw=4 ts=4
                    263:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>