[gnumeric] Add weekend specifier to WORKDAY. Half of [#172458]
- From: Andreas J. Guelzow <guelzow src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnumeric] Add weekend specifier to WORKDAY. Half of [#172458]
- Date: Sat, 3 Jul 2010 16:57:34 +0000 (UTC)
commit 6864d5ba2f6c844b939b64fd20a94d3c1cd026fe
Author: Andreas J Guelzow <aguelzow pyrshep ca>
Date: Sat Jul 3 10:57:11 2010 -0600
Add weekend specifier to WORKDAY. Half of [#172458]
2010-07-03 Andreas J. Guelzow <aguelzow pyrshep ca>
* functions.c (help_workday): add new argument description
(gnumeric_workday): implement weekend extension
(datetime_functions): add argument to "workday"
NEWS | 1 +
plugins/fn-date/ChangeLog | 6 ++
plugins/fn-date/functions.c | 108 ++++++++++++++++++++++++++++--------------
3 files changed, 79 insertions(+), 36 deletions(-)
---
diff --git a/NEWS b/NEWS
index 661df10..f6ba290 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,7 @@ Andreas:
* Improve configurable text export of numbers. [#126444]
* Improve horizontal fill. [#594193]
* Improve function syntax tooltips. [#623317]
+ * Add weekend specifier to WORKDAY. Half of [#172458]
--------------------------------------------------------------------------
Gnumeric 1.10.7
diff --git a/plugins/fn-date/ChangeLog b/plugins/fn-date/ChangeLog
index 65bcd6d..a6567a7 100644
--- a/plugins/fn-date/ChangeLog
+++ b/plugins/fn-date/ChangeLog
@@ -1,3 +1,9 @@
+2010-07-03 Andreas J. Guelzow <aguelzow pyrshep ca>
+
+ * functions.c (help_workday): add new argument description
+ (gnumeric_workday): implement weekend extension
+ (datetime_functions): add argument to "workday"
+
2010-06-28 Morten Welinder <terra gnome org>
* Release 1.10.7
diff --git a/plugins/fn-date/functions.c b/plugins/fn-date/functions.c
index cf3a459..0e4d9e5 100644
--- a/plugins/fn-date/functions.c
+++ b/plugins/fn-date/functions.c
@@ -733,10 +733,13 @@ static GnmFuncHelp const help_workday[] = {
{ GNM_FUNC_HELP_ARG, F_("date:date serial value")},
{ GNM_FUNC_HELP_ARG, F_("days:number of days to add")},
{ GNM_FUNC_HELP_ARG, F_("holidays:array of holidays")},
+ { GNM_FUNC_HELP_ARG, F_("weekend:array indicating whether a weekday (S, M, T, W, T, F, S) is on the weekend, defaults to {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}.")},
{ GNM_FUNC_HELP_DESCRIPTION, F_("WORKDAY adjusts @{date} by @{days} skipping over weekends and @{holidays} in the process.") },
{ GNM_FUNC_HELP_NOTE, F_("@{days} may be negative.") },
- { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible.") },
+ { GNM_FUNC_HELP_EXCEL, F_("This function is Excel compatible if the last argument is omitted.") },
+ { GNM_FUNC_HELP_ODF, F_("This function is OpenFormula compatible.") },
{ GNM_FUNC_HELP_EXAMPLES, "=WORKDAY(DATE(2001,12,14),2)" },
+ { GNM_FUNC_HELP_EXAMPLES, "=WORKDAY(DATE(2001,12,14),2,{FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE})" },
{ GNM_FUNC_HELP_SEEALSO, "NETWORKDAYS"},
{ GNM_FUNC_HELP_END }
};
@@ -760,16 +763,36 @@ gnumeric_workday (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
gnm_float days = value_get_as_float (argv[1]);
int idays;
gnm_float *holidays = NULL;
- int nholidays;
+ gnm_float *weekends = NULL;
+ gnm_float const default_weekends[] = {1.,0.,0.,0.,0.,0.,1.};
+ int nholidays, nweekends, n_non_weekend;
GDateWeekday weekday;
int serial;
+ int i;
datetime_value_to_g (&date, argv[0], conv);
if (!g_date_valid (&date))
goto bad;
+ if (argv[3]) {
+ GnmValue *result = NULL;
+
+ weekends = collect_floats_value (argv[3], ei->pos,
+ COLLECT_COERCE_STRINGS |
+ COLLECT_ZEROONE_BOOLS |
+ COLLECT_IGNORE_BLANKS,
+ &nweekends, &result);
+ if (result)
+ return result;
+ if (nweekends != 7)
+ return value_new_error_VALUE (ei->pos);
+
+ } else {
+ weekends = (gnm_float *)default_weekends;
+ nweekends = 7;
+ }
if (argv[2]) {
- int i, j;
+ int j;
GDate hol;
GnmValue *result = NULL;
@@ -793,7 +816,7 @@ gnumeric_workday (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
go_date_serial_to_g (&hol, hserial, conv);
if (!g_date_valid (&hol))
goto bad;
- if (g_date_get_weekday (&hol) >= G_DATE_SATURDAY)
+ if (weekends[g_date_get_weekday (&hol) % 7] != 0.)
continue;
holidays[j++] = hserial;
}
@@ -802,6 +825,12 @@ gnumeric_workday (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
holidays = NULL;
nholidays = 0;
}
+ n_non_weekend = 0;
+ for (i = 0; i < 7; i++)
+ if (weekends[i] == 0)
+ n_non_weekend++;
+ if (n_non_weekend == 0)
+ return value_new_error_VALUE (ei->pos);
if (days > INT_MAX / 2 || -days > INT_MAX / 2)
return value_new_error_NUM (ei->pos);
@@ -813,68 +842,75 @@ gnumeric_workday (GnmFuncEvalInfo *ei, GnmValue const * const *argv)
if (idays > 0) {
int h = 0;
- if (weekday >= G_DATE_SATURDAY) {
- serial -= (weekday - G_DATE_FRIDAY);
- weekday = G_DATE_FRIDAY;
+ weekday = weekday % 7;
+ while (weekends[weekday]) {
+ weekday = (weekday > 0) ? (weekday - 1) : G_DATE_SATURDAY;
+ serial--;
}
while (idays > 0) {
- int dm5 = idays % 5;
- int ds = idays / 5 * 7 + dm5;
+ int dm_part_week = idays % n_non_weekend;
+ int ds = idays / n_non_weekend * 7;
+ int old_serial = serial;
+
+ serial += ds;
- weekday += dm5;
- if (weekday >= G_DATE_SATURDAY) {
- ds += 2;
- weekday -= 5;
+ while (dm_part_week) {
+ serial++;
+ weekday = (weekday + 1) % 7;
+ if (!weekends[weekday])
+ dm_part_week--;
}
/*
- * "ds" is now the number of calendar days to advance
- * but we may be passing holiday.
+ * we may have passed holidays.
*/
idays = 0;
- while (h < nholidays && holidays[h] <= serial + ds) {
- if (holidays[h] > serial)
+ while (h < nholidays && holidays[h] <= serial) {
+ if (holidays[h] > old_serial)
idays++;
h++;
}
-
- serial += ds;
}
} else if (idays < 0) {
int h = nholidays - 1;
- if (weekday >= G_DATE_SATURDAY) {
- serial += (G_DATE_SUNDAY - weekday + 1);
- weekday = G_DATE_MONDAY;
+ weekday = weekday % 7;
+ while (weekends[weekday]) {
+ weekday = (weekday + 1) % 7;
+ serial++;
}
idays = -idays;
while (idays > 0) {
- int dm5 = idays % 5;
- int ds = idays / 5 * 7 + dm5;
+ int dm_part_week = idays % n_non_weekend;
+ int ds = idays / n_non_weekend * 7;
+ int old_serial = serial;
+
+ serial -= ds;
- weekday -= dm5;
- if ((int)weekday < (int)G_DATE_MONDAY) {
- ds += 2;
- weekday += 5;
+ while (dm_part_week) {
+ serial--;
+ weekday = (weekday > 0) ? (weekday - 1)
+ : G_DATE_SATURDAY;
+ if (!weekends[weekday])
+ dm_part_week--;
}
-
+
/*
- * "ds" is now the number of calendar days to retreat
- * but we may be passing holiday.
+ * we may have passed holidays.
*/
idays = 0;
- while (h >= 0 && holidays[h] >= serial + ds) {
- if (holidays[h] < serial)
+ while (h >= 0 && holidays[h] >= serial) {
+ if (holidays[h] < old_serial)
idays++;
h--;
}
-
- serial -= ds;
}
}
+ if (weekends != default_weekends)
+ g_free (weekends);
g_free (holidays);
go_date_serial_to_g (&date, serial, conv);
@@ -1244,7 +1280,7 @@ GnmFuncDescriptor const datetime_functions[] = {
gnumeric_weeknum, NULL, NULL, NULL, NULL,
GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_UNITLESS,
GNM_FUNC_IMPL_STATUS_COMPLETE, GNM_FUNC_TEST_STATUS_BASIC },
- { "workday", "ff|?", help_workday,
+ { "workday", "ff|?A", help_workday,
gnumeric_workday, NULL, NULL, NULL, NULL,
GNM_FUNC_SIMPLE + GNM_FUNC_AUTO_DATE,
GNM_FUNC_IMPL_STATUS_SUBSET, GNM_FUNC_TEST_STATUS_BASIC },
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]