Update Spanish translation
[gnumeric.git] / src / gnm-datetime.c
blob505e585f937a08dbb8f81ff15abb40bec1a822c1
2 /*
3 * gnm-datetime.c:
5 * Copyright (C) 2005
6 * Miguel de Icaza (miguel@gnu.org)
7 * Morten Welinder <terra@gnome.org>
8 * Jukka-Pekka Iivonen <iivonen@iki.fi>
9 * Andreas J. Guelzow <aguelzow@taliesin.ca>
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of the
14 * License, or (at your option) version 3.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
24 * USA
26 #include <gnumeric-config.h>
27 #include <goffice/goffice.h>
28 #include <value.h>
29 #include <string.h>
30 #include <gnm-datetime.h>
31 #include <gnm-format.h>
32 #include <number-match.h>
35 * Figure out whether the format engine in goffice allows negative values
36 * or (as XL) considers them errors.
38 gboolean
39 gnm_datetime_allow_negative (void)
41 static int allow = -1;
43 if (allow == -1) {
44 GOFormat *fmt = go_format_new_from_XL ("yyyy-mm-dd");
45 GnmValue *v = value_new_int (-42);
46 GODateConventions const *conv =
47 go_date_conv_from_str ("Lotus:1900");
48 char *text = format_value (fmt, v, -1, conv);
50 allow = (strcmp (text, "1899-11-19") == 0);
52 value_release (v);
53 go_format_unref (fmt);
54 g_free (text);
57 return (gboolean)allow;
60 gnm_float
61 datetime_value_to_serial_raw (GnmValue const *v, GODateConventions const *conv)
63 gnm_float serial;
65 if (VALUE_IS_NUMBER (v))
66 serial = value_get_as_float (v);
67 else {
68 char const *str = value_peek_string (v);
69 GnmValue *conversion = format_match_number (str, go_format_default_date (), conv);
71 if (conversion) {
72 serial = value_get_as_float (conversion);
73 value_release (conversion);
74 } else
75 serial = G_MAXINT;
78 if (serial < 0 && !gnm_datetime_allow_negative ())
79 serial = G_MAXINT;
81 return serial;
84 /* ------------------------------------------------------------------------- */
86 int
87 datetime_value_to_serial (GnmValue const *v, GODateConventions const *conv)
89 gnm_float serial = datetime_value_to_serial_raw (v, conv);
90 if (serial >= G_MAXINT || serial < G_MININT)
91 return G_MAXINT;
92 return go_date_serial_raw_to_serial (serial);
95 /* ------------------------------------------------------------------------- */
97 gboolean
98 datetime_value_to_g (GDate *res, GnmValue const *v, GODateConventions const *conv)
100 int serial = datetime_value_to_serial (v, conv);
101 if (serial == G_MAXINT) {
102 g_date_clear (res, 1);
103 return FALSE;
105 go_date_serial_to_g (res, serial, conv);
106 return g_date_valid (res);
109 /* ------------------------------------------------------------------------- */
112 * Returns the number of days in the year for the given date accoring to
113 * the day counting system specified by 'basis' argument. Basis may have
114 * one of the following values:
116 * 0 for US 30/360 (days in a month/days in a year)
117 * 1 for actual days/actual days
118 * 2 for actual days/360
119 * 3 for actual days/365
120 * 4 for European 30/360
122 * This function returns 360 for basis 0, 2, and 4, it returns value
123 * 365 for basis 3, and value 365 or 366 for basis 1 accoring to the
124 * year of the given date (366 is returned if the date is in a leap
125 * year).
128 annual_year_basis (GnmValue const *value_date, GOBasisType basis,
129 GODateConventions const *date_conv)
131 GDate date;
133 switch (basis) {
134 case GO_BASIS_MSRB_30_360:
135 return 360;
136 case GO_BASIS_ACT_ACT:
137 if (!datetime_value_to_g (&date, value_date, date_conv))
138 return -1;
139 return g_date_is_leap_year (g_date_get_year (&date))
140 ? 366 : 365;
141 case GO_BASIS_ACT_360:
142 return 360;
143 case GO_BASIS_ACT_365:
144 return 365;
145 case GO_BASIS_30E_360:
146 return 360;
147 default:
148 return -1;
152 gnm_float
153 yearfrac (GDate const *from, GDate const *to, GOBasisType basis)
155 int days;
156 gnm_float peryear;
158 if (!g_date_valid (from) || !g_date_valid (to))
159 return gnm_nan;
161 days = go_date_days_between_basis (from, to, basis);
163 if (days < 0) {
164 const GDate *tmp;
165 days = -days;
166 tmp = from; from = to; to = tmp;
169 switch (basis) {
170 case GO_BASIS_ACT_ACT: {
171 int y1 = g_date_get_year (from);
172 int y2 = g_date_get_year (to);
173 GDate d1, d2;
174 int feb29s, years;
176 d1 = *from;
177 gnm_date_add_years (&d1, 1);
178 if (g_date_compare (to, &d1) > 0) {
179 /* More than one year. */
180 years = y2 + 1 - y1;
182 g_date_clear (&d1, 1);
183 g_date_set_dmy (&d1, 1, 1, y1);
185 g_date_clear (&d2, 1);
186 g_date_set_dmy (&d2, 1, 1, y2 + 1);
188 feb29s = g_date_get_julian (&d2) - g_date_get_julian (&d1) -
189 365 * (y2 + 1 - y1);
190 } else {
191 /* Less than one year. */
192 years = 1;
194 if ((g_date_is_leap_year (y1) && g_date_get_month (from) < 3) ||
195 (g_date_is_leap_year (y2) &&
196 (g_date_get_month (to) * 0x100 + g_date_get_day (to) >= 2 * 0x100 + 29)))
197 feb29s = 1;
198 else
199 feb29s = 0;
202 peryear = 365 + (gnm_float)feb29s / years;
204 break;
207 default:
208 peryear = annual_year_basis (NULL, basis, NULL);
211 return days / peryear;
214 /* ------------------------------------------------------------------------- */
215 /* Like g_date_add_days, but...
217 * 1. Do not spew criticals.
218 * 2. Number of days is signed.
221 void
222 gnm_date_add_days (GDate *d, int n)
224 if (!g_date_valid (d))
225 return;
227 if (n >= 0) {
228 guint32 lim = 23936166; /* 31-Dec-65535 */
229 guint32 j = g_date_get_julian (d);
231 if (j > lim || (unsigned)n > lim - j)
232 goto bad;
234 g_date_add_days (d, n);
235 } else {
236 int m = g_date_get_julian (d) - 1;
238 if (m + n <= 0)
239 goto bad;
241 g_date_subtract_days (d, -n);
244 return;
246 bad:
247 g_date_clear (d, 1);
250 /* Like g_date_add_months, but...
252 * 1. Do not spew criticals.
253 * 2. Number of months is signed.
255 void
256 gnm_date_add_months (GDate *d, int n)
258 if (!g_date_valid (d))
259 return;
261 if (n >= 0) {
262 int m = (65535 - g_date_get_year (d)) * 12 +
263 (12 - g_date_get_month (d));
265 if (n > m)
266 goto bad;
268 g_date_add_months (d, n);
269 } else {
270 int m = (g_date_get_year (d) - 1) * 12 +
271 (g_date_get_month (d) - 1);
273 if (m + n <= 0)
274 goto bad;
276 g_date_subtract_months (d, -n);
279 return;
281 bad:
282 g_date_clear (d, 1);
285 /* Like g_date_add_years, but...
287 * 1. Do not spew criticals.
288 * 2. Number of years is signed.
290 void
291 gnm_date_add_years (GDate *d, int n)
293 if (!g_date_valid (d))
294 return;
296 if (n >= 0) {
297 int m = 65535 - g_date_get_year (d);
299 if (n > m)
300 goto bad;
302 g_date_add_years (d, n);
303 } else {
304 int m = g_date_get_year (d) - 1;
306 if (m + n <= 0)
307 goto bad;
309 g_date_subtract_years (d, -n);
312 return;
314 bad:
315 g_date_clear (d, 1);
318 #define DAY_SECONDS (3600*24)
320 datetime_value_to_seconds (GnmValue const *v, GODateConventions const *conv)
322 int secs;
323 gnm_float d = datetime_value_to_serial_raw (v, conv);
324 if (d >= G_MAXINT || d < G_MININT)
325 return -1;
327 /* Add epsilon before we scale and translate because otherwise it
328 will not be enough. */
329 d = gnm_add_epsilon (d);
331 /* Get the number down between 0 and 1 before we scale. */
332 d -= gnm_floor (d);
334 /* Scale and round. */
335 secs = (int)(gnm_add_epsilon (d) * DAY_SECONDS + 0.5);
337 /* We rounded, so we might have gone too far. */
338 if (secs >= DAY_SECONDS)
339 secs -= DAY_SECONDS;
341 return secs;