Annotation of embedaddon/php/ext/calendar/gregor.c, revision 1.1

1.1     ! misho       1: /* $selId: gregor.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:  *     SdnToGregorian(
        !            14:  *         long int  sdn,
        !            15:  *         int      *pYear,
        !            16:  *         int      *pMonth,
        !            17:  *         int      *pDay);
        !            18:  *
        !            19:  * Convert a SDN to a Gregorian calendar date.  If the input SDN is less
        !            20:  * than 1, the three output values will all be set to zero, otherwise
        !            21:  * *pYear will be >= -4714 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:  *     GregorianToSdn(
        !            26:  *         int inputYear,
        !            27:  *         int inputMonth,
        !            28:  *         int inputDay);
        !            29:  *
        !            30:  * Convert a Gregorian 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:  *     char *MonthNameShort[13];
        !            38:  *
        !            39:  * Convert a Gregorian month number (1 to 12) to the abbreviated (three
        !            40:  * character) name of the Gregorian month (null terminated).  An index of
        !            41:  * zero will return a zero length string.
        !            42:  *
        !            43:  *     char *MonthNameLong[13];
        !            44:  *
        !            45:  * Convert a Gregorian month number (1 to 12) to the name of the Gregorian
        !            46:  * month (null terminated).  An index of zero will return a zero length
        !            47:  * string.
        !            48:  *
        !            49:  * VALID RANGE
        !            50:  *
        !            51:  *     4714 B.C. to at least 10000 A.D.
        !            52:  *
        !            53:  *     Although this software can handle dates all the way back to 4714
        !            54:  *     B.C., such use may not be meaningful.  The Gregorian calendar was
        !            55:  *     not instituted until October 15, 1582 (or October 5, 1582 in the
        !            56:  *     Julian calendar).  Some countries did not accept it until much
        !            57:  *     later.  For example, Britain converted in 1752, The USSR in 1918 and
        !            58:  *     Greece in 1923.  Most European countries used the Julian calendar
        !            59:  *     prior to the Gregorian.
        !            60:  *
        !            61:  * CALENDAR OVERVIEW
        !            62:  *
        !            63:  *     The Gregorian calendar is a modified version of the Julian calendar.
        !            64:  *     The only difference being the specification of leap years.  The
        !            65:  *     Julian calendar specifies that every year that is a multiple of 4
        !            66:  *     will be a leap year.  This leads to a year that is 365.25 days long,
        !            67:  *     but the current accepted value for the tropical year is 365.242199
        !            68:  *     days.
        !            69:  *
        !            70:  *     To correct this error in the length of the year and to bring the
        !            71:  *     vernal equinox back to March 21, Pope Gregory XIII issued a papal
        !            72:  *     bull declaring that Thursday October 4, 1582 would be followed by
        !            73:  *     Friday October 15, 1582 and that centennial years would only be a
        !            74:  *     leap year if they were a multiple of 400.  This shortened the year
        !            75:  *     by 3 days per 400 years, giving a year of 365.2425 days.
        !            76:  *
        !            77:  *     Another recently proposed change in the leap year rule is to make
        !            78:  *     years that are multiples of 4000 not a leap year, but this has never
        !            79:  *     been officially accepted and this rule is not implemented in these
        !            80:  *     algorithms.
        !            81:  *
        !            82:  * ALGORITHMS
        !            83:  *
        !            84:  *     The calculations are based on three different cycles: a 400 year
        !            85:  *     cycle of leap years, a 4 year cycle of leap years and a 5 month
        !            86:  *     cycle of month lengths.
        !            87:  *
        !            88:  *     The 5 month cycle is used to account for the varying lengths of
        !            89:  *     months.  You will notice that the lengths alternate between 30
        !            90:  *     and 31 days, except for three anomalies: both July and August
        !            91:  *     have 31 days, both December and January have 31, and February
        !            92:  *     is less than 30.  Starting with March, the lengths are in a
        !            93:  *     cycle of 5 months (31, 30, 31, 30, 31):
        !            94:  *
        !            95:  *         Mar   31 days  \
        !            96:  *         Apr   30 days   |
        !            97:  *         May   31 days    > First cycle
        !            98:  *         Jun   30 days   |
        !            99:  *         Jul   31 days  /
        !           100:  *
        !           101:  *         Aug   31 days  \
        !           102:  *         Sep   30 days   |
        !           103:  *         Oct   31 days    > Second cycle
        !           104:  *         Nov   30 days   |
        !           105:  *         Dec   31 days  /
        !           106:  *
        !           107:  *         Jan   31 days  \
        !           108:  *         Feb 28/9 days   |
        !           109:  *                          > Third cycle (incomplete)
        !           110:  *
        !           111:  *     For this reason the calculations (internally) assume that the
        !           112:  *     year starts with March 1.
        !           113:  *
        !           114:  * TESTING
        !           115:  *
        !           116:  *     This algorithm has been tested from the year 4714 B.C. to 10000
        !           117:  *     A.D.  The source code of the verification program is included in
        !           118:  *     this package.
        !           119:  *
        !           120:  * REFERENCES
        !           121:  *
        !           122:  *     Conversions Between Calendar Date and Julian Day Number by Robert J.
        !           123:  *     Tantzen, Communications of the Association for Computing Machinery
        !           124:  *     August 1963.  (Also published in Collected Algorithms from CACM,
        !           125:  *     algorithm number 199).
        !           126:  *
        !           127:  **************************************************************************/
        !           128: 
        !           129: #include "sdncal.h"
        !           130: #include <limits.h>
        !           131: 
        !           132: #define GREGOR_SDN_OFFSET         32045
        !           133: #define DAYS_PER_5_MONTHS  153
        !           134: #define DAYS_PER_4_YEARS   1461
        !           135: #define DAYS_PER_400_YEARS 146097
        !           136: 
        !           137: void SdnToGregorian(
        !           138:                                           long int sdn,
        !           139:                                           int *pYear,
        !           140:                                           int *pMonth,
        !           141:                                           int *pDay)
        !           142: {
        !           143:        int century;
        !           144:        int year;
        !           145:        int month;
        !           146:        int day;
        !           147:        long int temp;
        !           148:        int dayOfYear;
        !           149: 
        !           150:        if (sdn <= 0 ||
        !           151:                        sdn > (LONG_MAX - 4 * GREGOR_SDN_OFFSET) / 4) {
        !           152:                goto fail;
        !           153:        }
        !           154:        temp = (sdn + GREGOR_SDN_OFFSET) * 4 - 1;
        !           155: 
        !           156:        /* Calculate the century (year/100). */
        !           157:        century = temp / DAYS_PER_400_YEARS;
        !           158: 
        !           159:        /* Calculate the year and day of year (1 <= dayOfYear <= 366). */
        !           160:        temp = ((temp % DAYS_PER_400_YEARS) / 4) * 4 + 3;
        !           161:        year = (century * 100) + (temp / DAYS_PER_4_YEARS);
        !           162:        dayOfYear = (temp % DAYS_PER_4_YEARS) / 4 + 1;
        !           163: 
        !           164:        /* Calculate the month and day of month. */
        !           165:        temp = dayOfYear * 5 - 3;
        !           166:        month = temp / DAYS_PER_5_MONTHS;
        !           167:        day = (temp % DAYS_PER_5_MONTHS) / 5 + 1;
        !           168: 
        !           169:        /* Convert to the normal beginning of the year. */
        !           170:        if (month < 10) {
        !           171:                month += 3;
        !           172:        } else {
        !           173:                year += 1;
        !           174:                month -= 9;
        !           175:        }
        !           176: 
        !           177:        /* Adjust to the B.C./A.D. type numbering. */
        !           178:        year -= 4800;
        !           179:        if (year <= 0)
        !           180:                year--;
        !           181: 
        !           182:        *pYear = year;
        !           183:        *pMonth = month;
        !           184:        *pDay = day;
        !           185:        return;
        !           186: 
        !           187: fail:
        !           188:        *pYear = 0;
        !           189:        *pMonth = 0;
        !           190:        *pDay = 0;
        !           191: }
        !           192: 
        !           193: long int GregorianToSdn(
        !           194:                                                   int inputYear,
        !           195:                                                   int inputMonth,
        !           196:                                                   int inputDay)
        !           197: {
        !           198:        int year;
        !           199:        int month;
        !           200: 
        !           201:        /* check for invalid dates */
        !           202:        if (inputYear == 0 || inputYear < -4714 ||
        !           203:                inputMonth <= 0 || inputMonth > 12 ||
        !           204:                inputDay <= 0 || inputDay > 31) {
        !           205:                return (0);
        !           206:        }
        !           207:        /* check for dates before SDN 1 (Nov 25, 4714 B.C.) */
        !           208:        if (inputYear == -4714) {
        !           209:                if (inputMonth < 11) {
        !           210:                        return (0);
        !           211:                }
        !           212:                if (inputMonth == 11 && inputDay < 25) {
        !           213:                        return (0);
        !           214:                }
        !           215:        }
        !           216:        /* Make year always a positive number. */
        !           217:        if (inputYear < 0) {
        !           218:                year = inputYear + 4801;
        !           219:        } else {
        !           220:                year = inputYear + 4800;
        !           221:        }
        !           222: 
        !           223:        /* Adjust the start of the year. */
        !           224:        if (inputMonth > 2) {
        !           225:                month = inputMonth - 3;
        !           226:        } else {
        !           227:                month = inputMonth + 9;
        !           228:                year--;
        !           229:        }
        !           230: 
        !           231:        return (((year / 100) * DAYS_PER_400_YEARS) / 4
        !           232:                        + ((year % 100) * DAYS_PER_4_YEARS) / 4
        !           233:                        + (month * DAYS_PER_5_MONTHS + 2) / 5
        !           234:                        + inputDay
        !           235:                        - GREGOR_SDN_OFFSET);
        !           236: }
        !           237: 
        !           238: char *MonthNameShort[13] =
        !           239: {
        !           240:        "",
        !           241:        "Jan",
        !           242:        "Feb",
        !           243:        "Mar",
        !           244:        "Apr",
        !           245:        "May",
        !           246:        "Jun",
        !           247:        "Jul",
        !           248:        "Aug",
        !           249:        "Sep",
        !           250:        "Oct",
        !           251:        "Nov",
        !           252:        "Dec"
        !           253: };
        !           254: 
        !           255: char *MonthNameLong[13] =
        !           256: {
        !           257:        "",
        !           258:        "January",
        !           259:        "February",
        !           260:        "March",
        !           261:        "April",
        !           262:        "May",
        !           263:        "June",
        !           264:        "July",
        !           265:        "August",
        !           266:        "September",
        !           267:        "October",
        !           268:        "November",
        !           269:        "December"
        !           270: };

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