+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2006, 2007, 2008, 2010, 2011 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
#include <config.h>
-#include "calendar.h"
+
+#include "data/calendar.h"
+
#include <assert.h>
#include <stdbool.h>
-#include <data/settings.h>
-#include <data/val-type.h>
+
+#include "data/settings.h"
+#include "data/val-type.h"
#include "gettext.h"
#define _(msgid) gettext (msgid)
return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0);
}
-static int
-raw_gregorian_to_offset (int y, int m, int d)
+int
+calendar_raw_gregorian_to_offset (int y, int m, int d)
{
return (EPOCH - 1
+ 365 * (y - 1)
+ d);
}
-/* Returns the number of days from 14 Oct 1582 to (Y,M,D) in the
- Gregorian calendar. Returns SYSMIS for dates before 14 Oct
- 1582. */
-double
-calendar_gregorian_to_offset (int y, int m, int d,
- calendar_error_func *error, void *aux)
+int *
+calendar_gregorian_adjust (int *y, int *m, int *d,
+ const struct fmt_settings *settings)
{
/* Normalize year. */
- if (y >= 0 && y < 100)
+ if (*y >= 0 && *y < 100)
{
- int epoch = settings_get_epoch ();
- int century = epoch / 100 + (y < epoch % 100);
- y += century * 100;
+ int epoch = fmt_settings_get_epoch (settings);
+ int century = epoch / 100 + (*y < epoch % 100);
+ *y += century * 100;
}
/* Normalize month. */
- if (m < 1 || m > 12)
+ if (*m < 1 || *m > 12)
{
- if (m == 0)
+ if (*m == 0)
{
- y--;
- m = 12;
+ *y -= 1;
+ *m = 12;
}
- else if (m == 13)
+ else if (*m == 13)
{
- y++;
- m = 1;
+ *y += 1;
+ *m = 1;
}
else
- {
- error (aux, _("Month %d is not in acceptable range of 0 to 13."), m);
- return SYSMIS;
- }
+ return m;
}
/* Normalize day. */
- if (d < 0 || d > 31)
- {
- error (aux, _("Day %d is not in acceptable range of 0 to 31."), d);
- return SYSMIS;
- }
+ if (*d < 0 || *d > 31)
+ return d;
/* Validate date. */
- if (y < 1582 || (y == 1582 && (m < 10 || (m == 10 && d < 15))))
+ if (*y < 1582 || (*y == 1582 && (*m < 10 || (*m == 10 && *d < 15))))
+ return y;
+
+ return NULL;
+}
+
+/* Returns the number of days from 14 Oct 1582 to (Y,M,D) in the
+ Gregorian calendar. Returns SYSMIS for dates before 14 Oct
+ 1582. */
+double
+calendar_gregorian_to_offset (int y, int m, int d,
+ const struct fmt_settings *settings,
+ char **errorp)
+{
+ int *bad_value = calendar_gregorian_adjust (&y, &m, &d, settings);
+ if (!bad_value)
+ {
+ if (errorp)
+ *errorp = NULL;
+ return calendar_raw_gregorian_to_offset (y, m, d);
+ }
+ else
{
- error (aux, _("Date %04d-%d-%d is before the earliest acceptable "
- "date of 1582-10-15."), y, m, d);
+ if (errorp)
+ {
+ if (bad_value == &y)
+ *errorp = xasprintf (_("Date %04d-%d-%d is before the earliest "
+ "supported date 1582-10-15."), y, m, d);
+ else if (bad_value == &m)
+ *errorp = xasprintf (_("Month %d is not in the acceptable range of "
+ "0 to 13."), m);
+ else
+ *errorp = xasprintf (_("Day %d is not in the acceptable range of "
+ "0 to 31."), d);
+ }
return SYSMIS;
}
-
- /* Calculate offset. */
- return raw_gregorian_to_offset (y, m, d);
}
/* Returns the number of days in the given YEAR from January 1 up
calendar_offset_to_gregorian (int ofs, int *y, int *m, int *d, int *yd)
{
int year = *y = calendar_offset_to_year (ofs);
- int january1 = raw_gregorian_to_offset (year, 1, 1);
+ int january1 = calendar_raw_gregorian_to_offset (year, 1, 1);
int yday = *yd = ofs - january1 + 1;
int march1 = january1 + cum_month_days (year, 3);
int correction = ofs < march1 ? 0 : (is_leap_year (year) ? 1 : 2);
calendar_offset_to_yday (int ofs)
{
int year = calendar_offset_to_year (ofs);
- int january1 = raw_gregorian_to_offset (year, 1, 1);
+ int january1 = calendar_raw_gregorian_to_offset (year, 1, 1);
int yday = ofs - january1 + 1;
return yday;
}