Calendar manipulation routines from Scott E. Lee.
[gedcom-parse.git] / gedcom / calendar / french.c
1 /* This file is taken from http://www.genealogy.org/~scottlee/
2    Only this initial comment has been added.  The next comment
3    gives the original copyright notice.
4 */
5
6
7 /* $selId: french.c,v 2.0 1995/10/24 01:13:06 lees Exp $
8  * Copyright 1993-1995, Scott E. Lee, all rights reserved.
9  * Permission granted to use, copy, modify, distribute and sell so long as
10  * the above copyright and this permission statement are retained in all
11  * copies.  THERE IS NO WARRANTY - USE AT YOUR OWN RISK.
12  */
13
14 /**************************************************************************
15  *
16  * These are the externally visible components of this file:
17  *
18  *     void
19  *     SdnToFrench(
20  *         long int  sdn,
21  *         int      *pYear,
22  *         int      *pMonth,
23  *         int      *pDay);
24  *
25  * Convert a SDN to a French republican calendar date.  If the input SDN is
26  * before the first day of year 1 or after the last day of year 14, the
27  * three output values will all be set to zero, otherwise *pYear will be in
28  * the range 1 to 14 inclusive; *pMonth will be in the range 1 to 13
29  * inclusive; *pDay will be in the range 1 to 30 inclusive.  If *pMonth is
30  * 13, the SDN represents one of the holidays at the end of the year and
31  * *pDay will be in the range 1 to 6 inclusive.
32  *
33  *     long int
34  *     FrenchToSdn(
35  *         int year,
36  *         int month,
37  *         int day);
38  *
39  * Convert a French republican calendar date to a SDN.  Zero is returned
40  * when the input date is detected as invalid or out of the supported
41  * range.  The return value will be > 0 for all valid, supported dates, but
42  * there are some invalid dates that will return a positive value.  To
43  * verify that a date is valid, convert it to SDN and then back and compare
44  * with the original.
45  *
46  *     char *FrenchMonthName[14];
47  *
48  * Convert a French republican month number (1 to 13) to the name of the
49  * French republican month (null terminated).  An index of 13 (for the
50  * "extra" days at the end of the year) will return the string "Extra".  An
51  * index of zero will return a zero length string.
52  *
53  * VALID RANGE
54  *
55  *     These routines only convert dates in years 1 through 14 (Gregorian
56  *     dates 22 September 1792 through 22 September 1806).  This more than
57  *     covers the period when the calendar was in use.
58  *
59  *     I would support a wider range of dates, but I have not been able to
60  *     find an authoritative definition of when leap years were to have
61  *     occurred.  There are suggestions that it was to skip a leap year ever
62  *     100 years like the Gregorian calendar.
63  *
64  * CALENDAR OVERVIEW
65  *
66  *     The French republican calendar was adopted in October 1793 during
67  *     the French Revolution and was abandoned in January 1806.  The intent
68  *     was to create a new calendar system that was based on scientific
69  *     principals, not religious traditions.
70  *
71  *     The year is divided into 12 months of 30 days each.  The remaining 5
72  *     to 6 days in the year are grouped at the end and are holidays.  Each
73  *     month is divided into three decades (instead of weeks) of 10 days
74  *     each.
75  *
76  *     The epoch (first day of the first year) is 22 September 1792 in the
77  *     Gregorian calendar.  Leap years are every fourth year (year 3, 7,
78  *     11, etc.)
79  *
80  * TESTING
81  *
82  *     This algorithm has been tested from the year 1 to 14.  The source
83  *     code of the verification program is included in this package.
84  *
85  * REFERENCES
86  *
87  *     I have found no detailed, authoritative reference on this calendar.
88  *     The algorithms are based on a preponderance of less authoritative
89  *     sources.
90  *
91  **************************************************************************/
92
93 #include "sdncal.h"
94
95 #define SDN_OFFSET         2375474
96 #define DAYS_PER_4_YEARS   1461
97 #define DAYS_PER_MONTH     30
98 #define FIRST_VALID        2375840
99 #define LAST_VALID         2380952
100
101 void
102 SdnToFrench(
103     long int  sdn,
104     int      *pYear,
105     int      *pMonth,
106     int      *pDay)
107 {
108     long int  temp;
109     int       dayOfYear;
110
111     if (sdn < FIRST_VALID || sdn > LAST_VALID) {
112         *pYear = 0;
113         *pMonth = 0;
114         *pDay = 0;
115         return;
116     }
117
118     temp = (sdn - SDN_OFFSET) * 4 - 1;
119     *pYear = temp / DAYS_PER_4_YEARS;
120     dayOfYear = (temp % DAYS_PER_4_YEARS) / 4;
121     *pMonth = dayOfYear / DAYS_PER_MONTH + 1;
122     *pDay = dayOfYear % DAYS_PER_MONTH + 1;
123 }
124
125 long int
126 FrenchToSdn(
127     int year,
128     int month,
129     int day)
130 {
131     /* check for invalid dates */
132     if (year < 1 || year > 14 ||
133         month < 1 || month > 13 ||
134         day < 1 || day > 30)
135     {
136         return(0);
137     }
138
139     return( (year * DAYS_PER_4_YEARS) / 4
140             + (month - 1) * DAYS_PER_MONTH
141             + day
142             + SDN_OFFSET );
143 }
144
145 char *FrenchMonthName[14] = {
146     "",
147     "Vendemiaire",
148     "Brumaire",
149     "Frimaire",
150     "Nivose",
151     "Pluviose",
152     "Ventose",
153     "Germinal",
154     "Floreal",
155     "Prairial",
156     "Messidor",
157     "Thermidor",
158     "Fructidor",
159     "Extra"
160 };