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>