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
26 #include <gnumeric-config.h>
27 #include <goffice/goffice.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.
39 gnm_datetime_allow_negative (void)
41 static int 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);
53 go_format_unref (fmt
);
57 return (gboolean
)allow
;
61 datetime_value_to_serial_raw (GnmValue
const *v
, GODateConventions
const *conv
)
65 if (VALUE_IS_NUMBER (v
))
66 serial
= value_get_as_float (v
);
68 char const *str
= value_peek_string (v
);
69 GnmValue
*conversion
= format_match_number (str
, go_format_default_date (), conv
);
72 serial
= value_get_as_float (conversion
);
73 value_release (conversion
);
78 if (serial
< 0 && !gnm_datetime_allow_negative ())
84 /* ------------------------------------------------------------------------- */
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
)
92 return go_date_serial_raw_to_serial (serial
);
95 /* ------------------------------------------------------------------------- */
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);
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
128 annual_year_basis (GnmValue
const *value_date
, GOBasisType basis
,
129 GODateConventions
const *date_conv
)
134 case GO_BASIS_MSRB_30_360
:
136 case GO_BASIS_ACT_ACT
:
137 if (!datetime_value_to_g (&date
, value_date
, date_conv
))
139 return g_date_is_leap_year (g_date_get_year (&date
))
141 case GO_BASIS_ACT_360
:
143 case GO_BASIS_ACT_365
:
145 case GO_BASIS_30E_360
:
153 yearfrac (GDate
const *from
, GDate
const *to
, GOBasisType basis
)
158 if (!g_date_valid (from
) || !g_date_valid (to
))
161 days
= go_date_days_between_basis (from
, to
, basis
);
166 tmp
= from
; from
= to
; to
= tmp
;
170 case GO_BASIS_ACT_ACT
: {
171 int y1
= g_date_get_year (from
);
172 int y2
= g_date_get_year (to
);
177 gnm_date_add_years (&d1
, 1);
178 if (g_date_compare (to
, &d1
) > 0) {
179 /* More than one year. */
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
) -
191 /* Less than one year. */
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)))
202 peryear
= 365 + (gnm_float
)feb29s
/ years
;
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.
222 gnm_date_add_days (GDate
*d
, int n
)
224 if (!g_date_valid (d
))
228 guint32 lim
= 23936166; /* 31-Dec-65535 */
229 guint32 j
= g_date_get_julian (d
);
231 if (j
> lim
|| (unsigned)n
> lim
- j
)
234 g_date_add_days (d
, n
);
236 int m
= g_date_get_julian (d
) - 1;
241 g_date_subtract_days (d
, -n
);
250 /* Like g_date_add_months, but...
252 * 1. Do not spew criticals.
253 * 2. Number of months is signed.
256 gnm_date_add_months (GDate
*d
, int n
)
258 if (!g_date_valid (d
))
262 int m
= (65535 - g_date_get_year (d
)) * 12 +
263 (12 - g_date_get_month (d
));
268 g_date_add_months (d
, n
);
270 int m
= (g_date_get_year (d
) - 1) * 12 +
271 (g_date_get_month (d
) - 1);
276 g_date_subtract_months (d
, -n
);
285 /* Like g_date_add_years, but...
287 * 1. Do not spew criticals.
288 * 2. Number of years is signed.
291 gnm_date_add_years (GDate
*d
, int n
)
293 if (!g_date_valid (d
))
297 int m
= 65535 - g_date_get_year (d
);
302 g_date_add_years (d
, n
);
304 int m
= g_date_get_year (d
) - 1;
309 g_date_subtract_years (d
, -n
);
318 #define DAY_SECONDS (3600*24)
320 datetime_value_to_seconds (GnmValue
const *v
, GODateConventions
const *conv
)
323 gnm_float d
= datetime_value_to_serial_raw (v
, conv
);
324 if (d
>= G_MAXINT
|| d
< G_MININT
)
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. */
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
)