File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / calendar / gregor.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:47:53 2012 UTC (12 years, 5 months ago) by misho
Branches: php, MAIN
CVS tags: v5_4_3elwix, v5_4_29p0, v5_4_29, v5_4_20p0, v5_4_20, v5_4_17p0, v5_4_17, v5_3_10, HEAD
php

    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>