From 61f1130e38bf334a920e9529dc5871c6d2b1e43f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Walter?= Date: Thu, 10 Oct 2013 21:54:52 +0000 Subject: [PATCH] Bug 55649: WORKDAY Function returns incorrect date when spanning a weekend, or the start date is a weekend git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1531124 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/ss/formula/atp/WorkdayCalculator.java | 36 ++++++++--------- .../ss/formula/atp/TestWorkdayFunction.java | 40 +++++++++++++++++++ 2 files changed, 58 insertions(+), 18 deletions(-) diff --git a/src/java/org/apache/poi/ss/formula/atp/WorkdayCalculator.java b/src/java/org/apache/poi/ss/formula/atp/WorkdayCalculator.java index 315fe0d31..4b7ecf0fb 100644 --- a/src/java/org/apache/poi/ss/formula/atp/WorkdayCalculator.java +++ b/src/java/org/apache/poi/ss/formula/atp/WorkdayCalculator.java @@ -61,24 +61,24 @@ public class WorkdayCalculator { * @param holidays an array of holidays. * @return date past x workdays. */ - public Date calculateWorkdays(double start, int workdays, double[] holidays) { - Date startDate = DateUtil.getJavaDate(start); - Calendar endDate = Calendar.getInstance(); - endDate.setTime(startDate); - endDate.add(Calendar.DAY_OF_YEAR, workdays); - int skippedDays = 0; - do { - double end = DateUtil.getExcelDate(endDate.getTime()); - int saturdaysPast = this.pastDaysOfWeek(start, end, Calendar.SATURDAY); - int sundaysPast = this.pastDaysOfWeek(start, end, Calendar.SUNDAY); - int nonWeekendHolidays = this.calculateNonWeekendHolidays(start, end, holidays); - skippedDays = saturdaysPast + sundaysPast + nonWeekendHolidays; - endDate.add(Calendar.DAY_OF_YEAR, skippedDays); - start = end + isNonWorkday(end, holidays); - } while (skippedDays != 0); - return endDate.getTime(); - } - + public Date calculateWorkdays(double start, int workdays, double[] holidays) { + Date startDate = DateUtil.getJavaDate(start); + int direction = workdays < 0 ? -1 : 1; + Calendar endDate = Calendar.getInstance(); + endDate.setTime(startDate); + double excelEndDate = DateUtil.getExcelDate(endDate.getTime()); + while (workdays != 0) { + endDate.add(Calendar.DAY_OF_YEAR, direction); + excelEndDate += direction; + if (endDate.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY + && endDate.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY + && !isHoliday(excelEndDate, holidays)) { + workdays -= direction; + } + } + return endDate.getTime(); + } + /** * Calculates how many days of week past between a start and an end date. * diff --git a/src/testcases/org/apache/poi/ss/formula/atp/TestWorkdayFunction.java b/src/testcases/org/apache/poi/ss/formula/atp/TestWorkdayFunction.java index 6540de028..b71e0c312 100644 --- a/src/testcases/org/apache/poi/ss/formula/atp/TestWorkdayFunction.java +++ b/src/testcases/org/apache/poi/ss/formula/atp/TestWorkdayFunction.java @@ -85,6 +85,46 @@ public class TestWorkdayFunction extends TestCase { new StringEval(STARTING_DATE.toString()), new NumberEval(151) }, EC)).getNumberValue())); } + public void testReturnWorkdaysSpanningAWeekendSubtractingDays() { + String startDate = "2013/09/30"; + int days = -1; + String expectedWorkDay = "2013/09/27"; + StringEval stringEval = new StringEval(startDate); + double numberValue = ((NumberEval) WorkdayFunction.instance.evaluate(new ValueEval[]{ + stringEval, new NumberEval(days) }, EC)).getNumberValue(); + assertEquals(expectedWorkDay, formatter.format(DateUtil.getJavaDate(numberValue))); + } + + public void testReturnWorkdaysSpanningAWeekendAddingDays() { + String startDate = "2013/09/27"; + int days = 1; + String expectedWorkDay = "2013/09/30"; + StringEval stringEval = new StringEval(startDate); + double numberValue = ((NumberEval) WorkdayFunction.instance.evaluate(new ValueEval[]{ + stringEval, new NumberEval(days) }, EC)).getNumberValue(); + assertEquals(expectedWorkDay, formatter.format(DateUtil.getJavaDate(numberValue))); + } + + public void testReturnWorkdaysWhenStartIsWeekendAddingDays() { + String startDate = "2013/10/06"; + int days = 1; + String expectedWorkDay = "2013/10/07"; + StringEval stringEval = new StringEval(startDate); + double numberValue = ((NumberEval) WorkdayFunction.instance.evaluate(new ValueEval[]{ + stringEval, new NumberEval(days) }, EC)).getNumberValue(); + assertEquals(expectedWorkDay, formatter.format(DateUtil.getJavaDate(numberValue))); + } + + public void testReturnWorkdaysWhenStartIsWeekendSubtractingDays() { + String startDate = "2013/10/06"; + int days = -1; + String expectedWorkDay = "2013/10/04"; + StringEval stringEval = new StringEval(startDate); + double numberValue = ((NumberEval) WorkdayFunction.instance.evaluate(new ValueEval[]{ + stringEval, new NumberEval(days) }, EC)).getNumberValue(); + assertEquals(expectedWorkDay, formatter.format(DateUtil.getJavaDate(numberValue))); + } + public void testReturnWorkdaysWithDaysTruncated() { assertEquals(new Date(109, APRIL, 30), DateUtil.getJavaDate(((NumberEval) WorkdayFunction.instance.evaluate(new ValueEval[]{ new StringEval(STARTING_DATE.toString()), new NumberEval(151.99999) }, EC)).getNumberValue()));