About: minor sizing improvements.
[gnumeric.git] / plugins / fn-christian-date / functions.c
blob8df9376affb2bd877cdc0de764a5a49af9930b21
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * fn-christian-date.c: Christian date functions.
5 * Author:
6 * Andreas J. Guelzow <aguelzow@pyrshep.ca>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <https://www.gnu.org/licenses/>.
21 #include <gnumeric-config.h>
22 #include <gnumeric.h>
23 #include <gnm-i18n.h>
24 #include <func.h>
25 #include <value.h>
27 #include <parse-util.h>
28 #include <cell.h>
29 #include <value.h>
30 #include <mathfunc.h>
31 #include <workbook.h>
32 #include <sheet.h>
34 #include <math.h>
35 #include <gnm-datetime.h>
37 #include <glib.h>
38 #include <goffice/goffice.h>
39 #include <gnm-plugin.h>
41 GNM_PLUGIN_MODULE_HEADER;
43 #define DATE_CONV(ep) workbook_date_conv ((ep)->sheet->workbook)
45 static void
46 eastersunday_calc_for_year (int year, GDate *date)
48 int month;
49 int day;
50 int century, n, k, i, j, l;
52 century = year/100;
53 n = year - 19 * (year / 19);
54 k = (century - 17) / 25;
55 i = century - century / 4 - (century - k) / 3 + 19 * n + 15;
56 i %= 30;
57 i = i - (i / 28) * (1 - (i / 28) * (29 / (i+1)) * ((21 - n) / 11 ));
58 j = year + year / 4 + i + 2 - century + century / 4;
59 j %= 7;
60 l = i - j;
61 month = 3 + (l + 40) / 44;
62 day = l + 28 - 31 * (month / 4);
64 g_date_clear (date, 1);
65 g_date_set_dmy (date, day, month, year);
68 static void
69 eastersunday_calc_no_year (GDate *date, GODateConventions const *conv, int diff)
71 int year, serial;
72 int today = go_date_timet_to_serial (time (NULL), conv);
74 go_date_serial_to_g (date, today, conv);
75 year = g_date_get_year (date);
76 eastersunday_calc_for_year (year, date);
77 serial = go_date_g_to_serial (date, conv) + diff;
78 if (serial < today)
79 eastersunday_calc_for_year (year + 1, date);
82 static int
83 adjust_year (int year, GODateConventions const *conv)
85 if (year < 0)
86 return -1;
87 else if (year <= 29)
88 return 2000 + year;
89 else if (year <= 99)
90 return 1900 + year;
91 else if (year < (gnm_datetime_allow_negative () ? 1582
92 : go_date_convention_base (conv)))
93 return -1;
94 else if (year > 9956)
95 return -1;
96 else
97 return year;
100 static GnmValue *
101 eastersunday_calc (GnmValue const *val, GnmFuncEvalInfo *ei, int diff)
103 GODateConventions const *conv = DATE_CONV (ei->pos);
104 GDate date;
105 int serial;
107 if (val) {
108 int year = adjust_year (value_get_as_int (val), conv);
110 if (year < 0)
111 return value_new_error_NUM (ei->pos);
113 eastersunday_calc_for_year (year, &date);
114 } else
115 eastersunday_calc_no_year (&date, conv, diff);
117 serial = go_date_g_to_serial (&date, conv) + diff;
119 if (diff < 0 &&
120 serial > 0 && serial <= 60 &&
121 go_date_convention_base (conv) == 1900) {
122 /* We crossed the 29-Feb-1900 hole in the 1900 method. */
123 serial--;
126 return value_new_int (serial);
129 /***************************************************************************/
131 static GnmFuncHelp const help_eastersunday[] = {
132 { GNM_FUNC_HELP_NAME, F_("EASTERSUNDAY:Easter Sunday in the Gregorian calendar "
133 "according to the Roman rite of the Christian Church") },
134 { GNM_FUNC_HELP_ARG, F_("year:year between 1582 and 9956, defaults to the year of the next Easter Sunday")},
135 { GNM_FUNC_HELP_NOTE, F_("Two digit years are adjusted as elsewhere in Gnumeric. Dates before 1904 may also be prohibited.")},
136 { GNM_FUNC_HELP_EXAMPLES, "=EASTERSUNDAY(2001)" },
137 { GNM_FUNC_HELP_EXAMPLES, "=EASTERSUNDAY()" },
138 { GNM_FUNC_HELP_ODF, F_("The 1-argument version of EASTERSUNDAY is compatible with OpenOffice "
139 "for years after 1904. "
140 "This function is not specified in ODF/OpenFormula.")},
141 { GNM_FUNC_HELP_SEEALSO, "ASHWEDNESDAY"},
142 { GNM_FUNC_HELP_END }
145 static GnmValue *
146 gnumeric_eastersunday (GnmFuncEvalInfo * ei, GnmValue const * const *argv)
148 return eastersunday_calc (argv[0], ei, 0);
152 /***************************************************************************/
154 static GnmFuncHelp const help_ashwednesday[] = {
155 { GNM_FUNC_HELP_NAME, F_("ASHWEDNESDAY:Ash Wednesday in the Gregorian calendar "
156 "according to the Roman rite of the Christian Church") },
157 { GNM_FUNC_HELP_ARG, F_("year:year between 1582 and 9956, defaults to the year of the next Ash Wednesday")},
158 { GNM_FUNC_HELP_NOTE, F_("Two digit years are adjusted as elsewhere in Gnumeric. Dates before 1904 may also be prohibited.")},
159 { GNM_FUNC_HELP_EXAMPLES, "=ASHWEDNESDAY(2001)" },
160 { GNM_FUNC_HELP_EXAMPLES, "=ASHWEDNESDAY()" },
161 { GNM_FUNC_HELP_SEEALSO, "EASTERSUNDAY"},
162 { GNM_FUNC_HELP_END }
165 static GnmValue *
166 gnumeric_ashwednesday (GnmFuncEvalInfo * ei, GnmValue const * const *argv)
168 return eastersunday_calc (argv[0], ei, -46);
172 /***************************************************************************/
174 static GnmFuncHelp const help_pentecostsunday[] = {
175 { GNM_FUNC_HELP_NAME, F_("PENTECOSTSUNDAY:Pentecost Sunday in the Gregorian calendar "
176 "according to the Roman rite of the Christian Church") },
177 { GNM_FUNC_HELP_ARG, F_("year:year between 1582 and 9956, defaults to the year of the next Pentecost Sunday")},
178 { GNM_FUNC_HELP_NOTE, F_("Two digit years are adjusted as elsewhere in Gnumeric. Dates before 1904 may also be prohibited.")},
179 { GNM_FUNC_HELP_EXAMPLES, "=PENTECOSTSUNDAY(2001)" },
180 { GNM_FUNC_HELP_EXAMPLES, "=PENTECOSTSUNDAY()" },
181 { GNM_FUNC_HELP_SEEALSO, "EASTERSUNDAY"},
182 { GNM_FUNC_HELP_END }
185 static GnmValue *
186 gnumeric_pentecostsunday (GnmFuncEvalInfo * ei, GnmValue const * const *argv)
188 return eastersunday_calc (argv[0], ei, +49);
191 /***************************************************************************/
193 static GnmFuncHelp const help_goodfriday[] = {
194 { GNM_FUNC_HELP_NAME, F_("GOODFRIDAY:Good Friday in the Gregorian calendar "
195 "according to the Roman rite of the Christian Church") },
196 { GNM_FUNC_HELP_ARG, F_("year:year between 1582 and 9956, defaults to the year of the next Good Friday")},
197 { GNM_FUNC_HELP_NOTE, F_("Two digit years are adjusted as elsewhere in Gnumeric. Dates before 1904 may also be prohibited.")},
198 { GNM_FUNC_HELP_EXAMPLES, "=GOODFRIDAY(2001)" },
199 { GNM_FUNC_HELP_EXAMPLES, "=GOODFRIDAY()" },
200 { GNM_FUNC_HELP_SEEALSO, "EASTERSUNDAY"},
201 { GNM_FUNC_HELP_END }
204 static GnmValue *
205 gnumeric_goodfriday (GnmFuncEvalInfo * ei, GnmValue const * const *argv)
207 return eastersunday_calc (argv[0], ei, -2);
210 /***************************************************************************/
212 static GnmFuncHelp const help_ascensionthursday[] = {
213 { GNM_FUNC_HELP_NAME, F_("ASCENSIONTHURSDAY:Ascension Thursday in the Gregorian calendar "
214 "according to the Roman rite of the Christian Church") },
215 { GNM_FUNC_HELP_ARG, F_("year:year between 1582 and 9956, defaults to the year of the next Ascension Thursday")},
216 { GNM_FUNC_HELP_NOTE, F_("Two digit years are adjusted as elsewhere in Gnumeric. Dates before 1904 may also be prohibited.")},
217 { GNM_FUNC_HELP_EXAMPLES, "=ASCENSIONTHURSDAY(2001)" },
218 { GNM_FUNC_HELP_EXAMPLES, "=ASCENSIONTHURSDAY()" },
219 { GNM_FUNC_HELP_SEEALSO, "EASTERSUNDAY"},
220 { GNM_FUNC_HELP_END }
223 static GnmValue *
224 gnumeric_ascensionthursday (GnmFuncEvalInfo * ei, GnmValue const * const *argv)
226 return eastersunday_calc (argv[0], ei, +39);
229 /***************************************************************************/
231 GnmFuncDescriptor const christian_datetime_functions[] = {
232 {"ascensionthursday", "|f", help_ascensionthursday,
233 gnumeric_ascensionthursday, NULL, NULL, NULL,
234 GNM_FUNC_VOLATILE + GNM_FUNC_AUTO_DATE,
235 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
236 GNM_FUNC_TEST_STATUS_NO_TESTSUITE},
237 {"ashwednesday", "|f", help_ashwednesday,
238 gnumeric_ashwednesday, NULL, NULL, NULL,
239 GNM_FUNC_VOLATILE + GNM_FUNC_AUTO_DATE,
240 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
241 GNM_FUNC_TEST_STATUS_NO_TESTSUITE},
242 {"eastersunday", "|f", help_eastersunday,
243 gnumeric_eastersunday, NULL, NULL, NULL,
244 GNM_FUNC_VOLATILE + GNM_FUNC_AUTO_DATE,
245 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
246 GNM_FUNC_TEST_STATUS_NO_TESTSUITE},
247 {"goodfriday", "|f", help_goodfriday,
248 gnumeric_goodfriday, NULL, NULL, NULL,
249 GNM_FUNC_VOLATILE + GNM_FUNC_AUTO_DATE,
250 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
251 GNM_FUNC_TEST_STATUS_NO_TESTSUITE},
252 {"pentecostsunday", "|f", help_pentecostsunday,
253 gnumeric_pentecostsunday, NULL, NULL, NULL,
254 GNM_FUNC_VOLATILE + GNM_FUNC_AUTO_DATE,
255 GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
256 GNM_FUNC_TEST_STATUS_NO_TESTSUITE},
257 {NULL}