X-Git-Url: https://git.dlugolecki.net.pl/?a=blobdiff_plain;f=gedcom%2Fcalendar%2Fgregor.c;fp=gedcom%2Fcalendar%2Fgregor.c;h=60dd10a5e95da8efff683acacaccaab14860b219;hb=410d63fd737654b7e6b2b14f6a4ad8c810c3ab13;hp=0000000000000000000000000000000000000000;hpb=d3934f67da413f5bc18a927cc0b13503831cc1f3;p=gedcom-parse.git diff --git a/gedcom/calendar/gregor.c b/gedcom/calendar/gregor.c new file mode 100644 index 0000000..60dd10a --- /dev/null +++ b/gedcom/calendar/gregor.c @@ -0,0 +1,274 @@ +/* This file is taken from http://www.genealogy.org/~scottlee/ + Only this initial comment has been added. The next comment + gives the original copyright notice. +*/ + + +/* $selId: gregor.c,v 2.0 1995/10/24 01:13:06 lees Exp $ + * Copyright 1993-1995, Scott E. Lee, all rights reserved. + * Permission granted to use, copy, modify, distribute and sell so long as + * the above copyright and this permission statement are retained in all + * copies. THERE IS NO WARRANTY - USE AT YOUR OWN RISK. + */ + +/************************************************************************** + * + * These are the externally visible components of this file: + * + * void + * SdnToGregorian( + * long int sdn, + * int *pYear, + * int *pMonth, + * int *pDay); + * + * Convert a SDN to a Gregorian calendar date. If the input SDN is less + * than 1, the three output values will all be set to zero, otherwise + * *pYear will be >= -4714 and != 0; *pMonth will be in the range 1 to 12 + * inclusive; *pDay will be in the range 1 to 31 inclusive. + * + * long int + * GregorianToSdn( + * int inputYear, + * int inputMonth, + * int inputDay); + * + * Convert a Gregorian calendar date to a SDN. Zero is returned when the + * input date is detected as invalid or out of the supported range. The + * return value will be > 0 for all valid, supported dates, but there are + * some invalid dates that will return a positive value. To verify that a + * date is valid, convert it to SDN and then back and compare with the + * original. + * + * char *MonthNameShort[13]; + * + * Convert a Gregorian month number (1 to 12) to the abbreviated (three + * character) name of the Gregorian month (null terminated). An index of + * zero will return a zero length string. + * + * char *MonthNameLong[13]; + * + * Convert a Gregorian month number (1 to 12) to the name of the Gregorian + * month (null terminated). An index of zero will return a zero length + * string. + * + * VALID RANGE + * + * 4714 B.C. to at least 10000 A.D. + * + * Although this software can handle dates all the way back to 4714 + * B.C., such use may not be meaningful. The Gregorian calendar was + * not instituted until October 15, 1582 (or October 5, 1582 in the + * Julian calendar). Some countries did not accept it until much + * later. For example, Britain converted in 1752, The USSR in 1918 and + * Greece in 1923. Most European countries used the Julian calendar + * prior to the Gregorian. + * + * CALENDAR OVERVIEW + * + * The Gregorian calendar is a modified version of the Julian calendar. + * The only difference being the specification of leap years. The + * Julian calendar specifies that every year that is a multiple of 4 + * will be a leap year. This leads to a year that is 365.25 days long, + * but the current accepted value for the tropical year is 365.242199 + * days. + * + * To correct this error in the length of the year and to bring the + * vernal equinox back to March 21, Pope Gregory XIII issued a papal + * bull declaring that Thursday October 4, 1582 would be followed by + * Friday October 15, 1582 and that centennial years would only be a + * leap year if they were a multiple of 400. This shortened the year + * by 3 days per 400 years, giving a year of 365.2425 days. + * + * Another recently proposed change in the leap year rule is to make + * years that are multiples of 4000 not a leap year, but this has never + * been officially accepted and this rule is not implemented in these + * algorithms. + * + * ALGORITHMS + * + * The calculations are based on three different cycles: a 400 year + * cycle of leap years, a 4 year cycle of leap years and a 5 month + * cycle of month lengths. + * + * The 5 month cycle is used to account for the varying lengths of + * months. You will notice that the lengths alternate between 30 + * and 31 days, except for three anomalies: both July and August + * have 31 days, both December and January have 31, and February + * is less than 30. Starting with March, the lengths are in a + * cycle of 5 months (31, 30, 31, 30, 31): + * + * Mar 31 days \ + * Apr 30 days | + * May 31 days > First cycle + * Jun 30 days | + * Jul 31 days / + * + * Aug 31 days \ + * Sep 30 days | + * Oct 31 days > Second cycle + * Nov 30 days | + * Dec 31 days / + * + * Jan 31 days \ + * Feb 28/9 days | + * > Third cycle (incomplete) + * + * For this reason the calculations (internally) assume that the + * year starts with March 1. + * + * TESTING + * + * This algorithm has been tested from the year 4714 B.C. to 10000 + * A.D. The source code of the verification program is included in + * this package. + * + * REFERENCES + * + * Conversions Between Calendar Date and Julian Day Number by Robert J. + * Tantzen, Communications of the Association for Computing Machinery + * August 1963. (Also published in Collected Algorithms from CACM, + * algorithm number 199). + * + **************************************************************************/ + +#include "sdncal.h" + +#define SDN_OFFSET 32045 +#define DAYS_PER_5_MONTHS 153 +#define DAYS_PER_4_YEARS 1461 +#define DAYS_PER_400_YEARS 146097 + +void +SdnToGregorian( + long int sdn, + int *pYear, + int *pMonth, + int *pDay) +{ + int century; + int year; + int month; + int day; + long int temp; + int dayOfYear; + + if (sdn <= 0) { + *pYear = 0; + *pMonth = 0; + *pDay = 0; + return; + } + + temp = (sdn + SDN_OFFSET) * 4 - 1; + + /* Calculate the century (year/100). */ + century = temp / DAYS_PER_400_YEARS; + + /* Calculate the year and day of year (1 <= dayOfYear <= 366). */ + temp = ((temp % DAYS_PER_400_YEARS) / 4) * 4 + 3; + year = (century * 100) + (temp / DAYS_PER_4_YEARS); + dayOfYear = (temp % DAYS_PER_4_YEARS) / 4 + 1; + + /* Calculate the month and day of month. */ + temp = dayOfYear * 5 - 3; + month = temp / DAYS_PER_5_MONTHS; + day = (temp % DAYS_PER_5_MONTHS) / 5 + 1; + + /* Convert to the normal beginning of the year. */ + if (month < 10) { + month += 3; + } else { + year += 1; + month -= 9; + } + + /* Adjust to the B.C./A.D. type numbering. */ + year -= 4800; + if (year <= 0) year--; + + *pYear = year; + *pMonth = month; + *pDay = day; +} + +long int +GregorianToSdn( + int inputYear, + int inputMonth, + int inputDay) +{ + int year; + int month; + + /* check for invalid dates */ + if (inputYear == 0 || inputYear < -4714 || + inputMonth <= 0 || inputMonth > 12 || + inputDay <= 0 || inputDay > 31) + { + return(0); + } + + /* check for dates before SDN 1 (Nov 25, 4714 B.C.) */ + if (inputYear == -4714) { + if (inputMonth < 11) { + return(0); + } + if (inputMonth == 11 && inputDay < 25) { + return(0); + } + } + + /* Make year always a positive number. */ + if (inputYear < 0) { + year = inputYear + 4801; + } else { + year = inputYear + 4800; + } + + /* Adjust the start of the year. */ + if (inputMonth > 2) { + month = inputMonth - 3; + } else { + month = inputMonth + 9; + year--; + } + + return( ((year / 100) * DAYS_PER_400_YEARS) / 4 + + ((year % 100) * DAYS_PER_4_YEARS) / 4 + + (month * DAYS_PER_5_MONTHS + 2) / 5 + + inputDay + - SDN_OFFSET ); +} + +char *MonthNameShort[13] = { + "", + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" +}; + +char *MonthNameLong[13] = { + "", + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December" +};