Introspection fix
[gnumeric.git] / plugins / fn-christian-date / functions.c
blob29d6784d61ae7a5d7652db067cc2656ed43e6b6c
1 /*
2 * fn-christian-date.c: Christian date functions.
4 * Author:
5 * Andreas J. Guelzow <aguelzow@pyrshep.ca>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <https://www.gnu.org/licenses/>.
20 #include <gnumeric-config.h>
21 #include <gnumeric.h>
22 #include <gnm-i18n.h>
23 #include <func.h>
24 #include <value.h>
26 #include <parse-util.h>
27 #include <cell.h>
28 #include <value.h>
29 #include <mathfunc.h>
30 #include <workbook.h>
31 #include <sheet.h>
33 #include <math.h>
34 #include <gnm-datetime.h>
36 #include <glib.h>
37 #include <goffice/goffice.h>
38 #include <gnm-plugin.h>
40 GNM_PLUGIN_MODULE_HEADER;
42 #define DATE_CONV(ep) sheet_date_conv ((ep)->sheet)
44 static void
45 eastersunday_calc_for_year (int year, GDate *date)
47 int month;
48 int day;
49 int century, n, k, i, j, l;
51 century = year/100;
52 n = year - 19 * (year / 19);
53 k = (century - 17) / 25;
54 i = century - century / 4 - (century - k) / 3 + 19 * n + 15;
55 i %= 30;
56 i = i - (i / 28) * (1 - (i / 28) * (29 / (i+1)) * ((21 - n) / 11 ));
57 j = year + year / 4 + i + 2 - century + century / 4;
58 j %= 7;
59 l = i - j;
60 month = 3 + (l + 40) / 44;
61 day = l + 28 - 31 * (month / 4);
63 g_date_clear (date, 1);
64 g_date_set_dmy (date, day, month, year);
67 static void
68 eastersunday_calc_no_year (GDate *date, GODateConventions const *conv, int diff)
70 int year, serial;
71 int today = go_date_timet_to_serial (time (NULL), conv);
73 go_date_serial_to_g (date, today, conv);
74 year = g_date_get_year (date);
75 eastersunday_calc_for_year (year, date);
76 serial = go_date_g_to_serial (date, conv) + diff;
77 if (serial < today)
78 eastersunday_calc_for_year (year + 1, date);
81 static int
82 adjust_year (int year, GODateConventions const *conv)
84 if (year < 0)
85 return -1;
86 else if (year <= 29)
87 return 2000 + year;
88 else if (year <= 99)
89 return 1900 + year;
90 else if (year < (gnm_datetime_allow_negative () ? 1582
91 : go_date_convention_base (conv)))
92 return -1;
93 else if (year > 9956)
94 return -1;
95 else
96 return year;
99 static GnmValue *
100 eastersunday_calc (GnmValue const *val, GnmFuncEvalInfo *ei, int diff)
102 GODateConventions const *conv = DATE_CONV (ei->pos);
103 GDate date;
104 int serial;
106 if (val) {
107 int year = adjust_year (value_get_as_int (val), conv);
109 if (year < 0)
110 return value_new_error_NUM (ei->pos);
112 eastersunday_calc_for_year (year, &date);
113 } else
114 eastersunday_calc_no_year (&date, conv, diff);
116 serial = go_date_g_to_serial (&date, conv) + diff;
118 if (diff < 0 &&
119 serial > 0 && serial <= 60 &&
120 go_date_convention_base (conv) == 1900) {
121 /* We crossed the 29-Feb-1900 hole in the 1900 method. */
122 serial--;
125 return value_new_int (serial);
128 /***************************************************************************/
130 static GnmFuncHelp const help_eastersunday[] = {
131 { GNM_FUNC_HELP_NAME, F_("EASTERSUNDAY:Easter Sunday in the Gregorian calendar "
132 "according to the Roman rite of the Christian Church") },
133 { GNM_FUNC_HELP_ARG, F_("year:year between 1582 and 9956, defaults to the year of the next Easter Sunday")},
134 { GNM_FUNC_HELP_NOTE, F_("Two digit years are adjusted as elsewhere in Gnumeric. Dates before 1904 may also be prohibited.")},
135 { GNM_FUNC_HELP_EXAMPLES, "=EASTERSUNDAY(2001)" },
136 { GNM_FUNC_HELP_EXAMPLES, "=EASTERSUNDAY()" },
137 { GNM_FUNC_HELP_ODF, F_("The 1-argument version of EASTERSUNDAY is compatible with OpenOffice "
138 "for years after 1904. "
139 "This function is not specified in ODF/OpenFormula.")},
140 { GNM_FUNC_HELP_SEEALSO, "ASHWEDNESDAY"},
141 { GNM_FUNC_HELP_END }
144 static GnmValue *
145 gnumeric_eastersunday (GnmFuncEvalInfo * ei, GnmValue const * const *argv)
147 return eastersunday_calc (argv[0], ei, 0);
151 /***************************************************************************/
153 static GnmFuncHelp const help_ashwednesday[] = {
154 { GNM_FUNC_HELP_NAME, F_("ASHWEDNESDAY:Ash Wednesday in the Gregorian calendar "
155 "according to the Roman rite of the Christian Church") },
156 { GNM_FUNC_HELP_ARG, F_("year:year between 1582 and 9956, defaults to the year of the next Ash Wednesday")},
157 { GNM_FUNC_HELP_NOTE, F_("Two digit years are adjusted as elsewhere in Gnumeric. Dates before 1904 may also be prohibited.")},
158 { GNM_FUNC_HELP_EXAMPLES, "=ASHWEDNESDAY(2001)" },
159 { GNM_FUNC_HELP_EXAMPLES, "=ASHWEDNESDAY()" },
160 { GNM_FUNC_HELP_SEEALSO, "EASTERSUNDAY"},
161 { GNM_FUNC_HELP_END }
164 static GnmValue *
165 gnumeric_ashwednesday (GnmFuncEvalInfo * ei, GnmValue const * const *argv)
167 return eastersunday_calc (argv[0], ei, -46);
171 /***************************************************************************/
173 static GnmFuncHelp const help_pentecostsunday[] = {
174 { GNM_FUNC_HELP_NAME, F_("PENTECOSTSUNDAY:Pentecost Sunday in the Gregorian calendar "
175 "according to the Roman rite of the Christian Church") },
176 { GNM_FUNC_HELP_ARG, F_("year:year between 1582 and 9956, defaults to the year of the next Pentecost Sunday")},
177 { GNM_FUNC_HELP_NOTE, F_("Two digit years are adjusted as elsewhere in Gnumeric. Dates before 1904 may also be prohibited.")},
178 { GNM_FUNC_HELP_EXAMPLES, "=PENTECOSTSUNDAY(2001)" },
179 { GNM_FUNC_HELP_EXAMPLES, "=PENTECOSTSUNDAY()" },
180 { GNM_FUNC_HELP_SEEALSO, "EASTERSUNDAY"},
181 { GNM_FUNC_HELP_END }
184 static GnmValue *
185 gnumeric_pentecostsunday (GnmFuncEvalInfo * ei, GnmValue const * const *argv)
187 return eastersunday_calc (argv[0], ei, +49);
190 /***************************************************************************/
192 static GnmFuncHelp const help_goodfriday[] = {
193 { GNM_FUNC_HELP_NAME, F_("GOODFRIDAY:Good Friday in the Gregorian calendar "
194 "according to the Roman rite of the Christian Church") },
195 { GNM_FUNC_HELP_ARG, F_("year:year between 1582 and 9956, defaults to the year of the next Good Friday")},
196 { GNM_FUNC_HELP_NOTE, F_("Two digit years are adjusted as elsewhere in Gnumeric. Dates before 1904 may also be prohibited.")},
197 { GNM_FUNC_HELP_EXAMPLES, "=GOODFRIDAY(2001)" },
198 { GNM_FUNC_HELP_EXAMPLES, "=GOODFRIDAY()" },
199 { GNM_FUNC_HELP_SEEALSO, "EASTERSUNDAY"},
200 { GNM_FUNC_HELP_END }
203 static GnmValue *
204 gnumeric_goodfriday (GnmFuncEvalInfo * ei, GnmValue const * const *argv)
206 return eastersunday_calc (argv[0], ei, -2);
209 /***************************************************************************/
211 static GnmFuncHelp const help_ascensionthursday[] = {
212 { GNM_FUNC_HELP_NAME, F_("ASCENSIONTHURSDAY:Ascension Thursday in the Gregorian calendar "
213 "according to the Roman rite of the Christian Church") },
214 { GNM_FUNC_HELP_ARG, F_("year:year between 1582 and 9956, defaults to the year of the next Ascension Thursday")},
215 { GNM_FUNC_HELP_NOTE, F_("Two digit years are adjusted as elsewhere in Gnumeric. Dates before 1904 may also be prohibited.")},
216 { GNM_FUNC_HELP_EXAMPLES, "=ASCENSIONTHURSDAY(2001)" },
217 { GNM_FUNC_HELP_EXAMPLES, "=ASCENSIONTHURSDAY()" },
218 { GNM_FUNC_HELP_SEEALSO, "EASTERSUNDAY"},
219 { GNM_FUNC_HELP_END }
222 static GnmValue *
223 gnumeric_ascensionthursday (GnmFuncEvalInfo * ei, GnmValue const * const *argv)
225 return eastersunday_calc (argv[0], ei, +39);
228 /***************************************************************************/
230 GnmFuncDescriptor const christian_datetime_functions[] = {
231 {"ascensionthursday", "|f", help_ascensionthursday,
232 gnumeric_ascensionthursday, NULL, NULL, NULL,
233 GNM_FUNC_VOLATILE + GNM_FUNC_AUTO_DATE,
234 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
235 GNM_FUNC_TEST_STATUS_NO_TESTSUITE},
236 {"ashwednesday", "|f", help_ashwednesday,
237 gnumeric_ashwednesday, NULL, NULL, NULL,
238 GNM_FUNC_VOLATILE + GNM_FUNC_AUTO_DATE,
239 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
240 GNM_FUNC_TEST_STATUS_NO_TESTSUITE},
241 {"eastersunday", "|f", help_eastersunday,
242 gnumeric_eastersunday, NULL, NULL, NULL,
243 GNM_FUNC_VOLATILE + GNM_FUNC_AUTO_DATE,
244 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
245 GNM_FUNC_TEST_STATUS_NO_TESTSUITE},
246 {"goodfriday", "|f", help_goodfriday,
247 gnumeric_goodfriday, NULL, NULL, NULL,
248 GNM_FUNC_VOLATILE + GNM_FUNC_AUTO_DATE,
249 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
250 GNM_FUNC_TEST_STATUS_NO_TESTSUITE},
251 {"pentecostsunday", "|f", help_pentecostsunday,
252 gnumeric_pentecostsunday, NULL, NULL, NULL,
253 GNM_FUNC_VOLATILE + GNM_FUNC_AUTO_DATE,
254 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
255 GNM_FUNC_TEST_STATUS_NO_TESTSUITE},
256 {NULL}