You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ye...@apache.org on 2012/08/11 18:14:49 UTC

svn commit: r1371969 - in /poi/trunk: ./ src/documentation/content/xdocs/ src/documentation/content/xdocs/spreadsheet/ src/java/org/apache/poi/ss/formula/eval/ src/java/org/apache/poi/ss/formula/functions/ src/java/org/apache/poi/ss/usermodel/ src/test...

Author: yegor
Date: Sat Aug 11 16:14:49 2012
New Revision: 1371969

URL: http://svn.apache.org/viewvc?rev=1371969&view=rev
Log:
Bugzilla 53644: XLS formula bugfix (CalFieldFunc) + WeekDay addon

Added:
    poi/trunk/src/java/org/apache/poi/ss/formula/functions/WeekdayFunc.java
Modified:
    poi/trunk/patch.xml
    poi/trunk/src/documentation/content/xdocs/spreadsheet/eval-devguide.xml
    poi/trunk/src/documentation/content/xdocs/status.xml
    poi/trunk/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java
    poi/trunk/src/java/org/apache/poi/ss/formula/functions/Address.java
    poi/trunk/src/java/org/apache/poi/ss/formula/functions/BooleanFunction.java
    poi/trunk/src/java/org/apache/poi/ss/formula/functions/CalendarFieldFunction.java
    poi/trunk/src/java/org/apache/poi/ss/usermodel/DateUtil.java
    poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestAddress.java
    poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestCalendarFieldFunction.java

Modified: poi/trunk/patch.xml
URL: http://svn.apache.org/viewvc/poi/trunk/patch.xml?rev=1371969&r1=1371968&r2=1371969&view=diff
==============================================================================
--- poi/trunk/patch.xml (original)
+++ poi/trunk/patch.xml Sat Aug 11 16:14:49 2012
@@ -50,11 +50,11 @@
          <filterchain>  
             <!-- capture any new files -->
             <linecontainsregexp>
-                <regexp pattern="(\?|A)......"/>
+                <regexp pattern="^(\?|A)......"/>
             </linecontainsregexp>
             <!-- filter out the first six characters -->
             <tokenfilter>
-              <replaceregex pattern="(.......)" replace=""/>
+              <replaceregex pattern="^(.......)" replace=""/>
             </tokenfilter>
             <!--remove line breaks -->
             <striplinebreaks/>

Modified: poi/trunk/src/documentation/content/xdocs/spreadsheet/eval-devguide.xml
URL: http://svn.apache.org/viewvc/poi/trunk/src/documentation/content/xdocs/spreadsheet/eval-devguide.xml?rev=1371969&r1=1371968&r2=1371969&view=diff
==============================================================================
--- poi/trunk/src/documentation/content/xdocs/spreadsheet/eval-devguide.xml (original)
+++ poi/trunk/src/documentation/content/xdocs/spreadsheet/eval-devguide.xml Sat Aug 11 16:14:49 2012
@@ -88,11 +88,11 @@
             <p>
                 As of Feb 2012, POI supports about 140 built-in functions,
                 see <link href="#appendixA">Appendix A</link> for the full list.
-                You can programmatically list supported / unsuported functions using trhe following helper methods:
+                You can programmatically list supported / unsuported functions using the following helper methods:
             </p>
             <source>
     // list of functions that POI can evaluate
-    Collection&lt;String&gt; suportedFuncs = WorkbookEvaluator.getSupportedFunctionNames();
+    Collection&lt;String&gt; supportedFuncs = WorkbookEvaluator.getSupportedFunctionNames();
 
     // list of functions that are not supported by POI
     Collection&lt;String&gt; unsupportedFuncs = WorkbookEvaluator.getNotSupportedFunctionNames();
@@ -366,6 +366,7 @@
     VAR
     VARP
     VLOOKUP
+    WEEKDAY
     WORKDAY
     YEAR
     YEARFRAC

Modified: poi/trunk/src/documentation/content/xdocs/status.xml
URL: http://svn.apache.org/viewvc/poi/trunk/src/documentation/content/xdocs/status.xml?rev=1371969&r1=1371968&r2=1371969&view=diff
==============================================================================
--- poi/trunk/src/documentation/content/xdocs/status.xml (original)
+++ poi/trunk/src/documentation/content/xdocs/status.xml Sat Aug 11 16:14:49 2012
@@ -34,6 +34,7 @@
 
     <changes>
         <release version="3.9-beta1" date="2012-??-??">
+          <action dev="poi-developers" type="add">53644 - XLS formula bugfix (CalFieldFunc) + WeekDay addon </action>
           <action dev="poi-developers" type="add">53446 - Fixed some problems extracting PNGs </action>
           <action dev="poi-developers" type="fix">53205 - Fixed some parsing errors and encoding issues in HDGF </action>
           <action dev="poi-developers" type="add">53204 - Improved performanceof PageSettingsBlock in HSSF </action>

Modified: poi/trunk/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java?rev=1371969&r1=1371968&r2=1371969&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java (original)
+++ poi/trunk/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java Sat Aug 11 16:14:49 2012
@@ -117,6 +117,7 @@ public final class FunctionEval {
 		retval[68] = CalendarFieldFunction.MONTH;
 		retval[69] = CalendarFieldFunction.YEAR;
 
+		retval[70] = WeekdayFunc.instance;
 		retval[71] = CalendarFieldFunction.HOUR;
 		retval[72] = CalendarFieldFunction.MINUTE;
 		retval[73] = CalendarFieldFunction.SECOND;

Modified: poi/trunk/src/java/org/apache/poi/ss/formula/functions/Address.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/formula/functions/Address.java?rev=1371969&r1=1371968&r2=1371969&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/formula/functions/Address.java (original)
+++ poi/trunk/src/java/org/apache/poi/ss/formula/functions/Address.java Sat Aug 11 16:14:49 2012
@@ -43,10 +43,10 @@ public class Address implements Function
             int col =  (int)NumericFunction.singleOperandEvaluate(args[1], srcRowIndex, srcColumnIndex);
 
             int refType;
-            if(args.length > 2){
+            if (args.length > 2  &&  args[2] != MissingArgEval.instance) {
                 refType = (int)NumericFunction.singleOperandEvaluate(args[2], srcRowIndex, srcColumnIndex);
             } else {
-                refType = REF_ABSOLUTE;
+                refType = REF_ABSOLUTE;		// this is also the default if parameter is not given
             }
             switch (refType){
                 case REF_ABSOLUTE:

Modified: poi/trunk/src/java/org/apache/poi/ss/formula/functions/BooleanFunction.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/formula/functions/BooleanFunction.java?rev=1371969&r1=1371968&r2=1371969&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/formula/functions/BooleanFunction.java (original)
+++ poi/trunk/src/java/org/apache/poi/ss/formula/functions/BooleanFunction.java Sat Aug 11 16:14:49 2012
@@ -20,6 +20,7 @@ package org.apache.poi.ss.formula.functi
 import org.apache.poi.ss.formula.eval.BoolEval;
 import org.apache.poi.ss.formula.eval.ErrorEval;
 import org.apache.poi.ss.formula.eval.EvaluationException;
+import org.apache.poi.ss.formula.eval.MissingArgEval;
 import org.apache.poi.ss.formula.eval.OperandResolver;
 import org.apache.poi.ss.formula.eval.RefEval;
 import org.apache.poi.ss.formula.eval.ValueEval;
@@ -81,6 +82,8 @@ public abstract class BooleanFunction im
 			if (arg instanceof RefEval) {
 				ValueEval ve = ((RefEval) arg).getInnerValueEval();
 				tempVe = OperandResolver.coerceValueToBoolean(ve, true);
+			} else if (arg == MissingArgEval.instance) {
+				tempVe = null;		// you can leave out parameters, they are simply ignored
 			} else {
 				tempVe = OperandResolver.coerceValueToBoolean(arg, false);
 			}

Modified: poi/trunk/src/java/org/apache/poi/ss/formula/functions/CalendarFieldFunction.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/formula/functions/CalendarFieldFunction.java?rev=1371969&r1=1371968&r2=1371969&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/formula/functions/CalendarFieldFunction.java (original)
+++ poi/trunk/src/java/org/apache/poi/ss/formula/functions/CalendarFieldFunction.java Sat Aug 11 16:14:49 2012
@@ -18,8 +18,6 @@
 package org.apache.poi.ss.formula.functions;
 
 import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
 
 import org.apache.poi.ss.formula.eval.ErrorEval;
 import org.apache.poi.ss.formula.eval.EvaluationException;
@@ -32,14 +30,17 @@ import org.apache.poi.ss.usermodel.DateU
  * Implementation of Excel functions Date parsing functions:
  *  Date - DAY, MONTH and YEAR
  *  Time - HOUR, MINUTE and SECOND
+ *
+ * @author Others (not mentioned in code)
+ * @author Thies Wellpott
  */
 public final class CalendarFieldFunction extends Fixed1ArgFunction {
 	public static final Function YEAR = new CalendarFieldFunction(Calendar.YEAR);
 	public static final Function MONTH = new CalendarFieldFunction(Calendar.MONTH);
 	public static final Function DAY = new CalendarFieldFunction(Calendar.DAY_OF_MONTH);
 	public static final Function HOUR = new CalendarFieldFunction(Calendar.HOUR_OF_DAY);
-   public static final Function MINUTE = new CalendarFieldFunction(Calendar.MINUTE);
-   public static final Function SECOND = new CalendarFieldFunction(Calendar.SECOND);
+    public static final Function MINUTE = new CalendarFieldFunction(Calendar.MINUTE);
+    public static final Function SECOND = new CalendarFieldFunction(Calendar.SECOND);
 
 	private final int _dateFieldId;
 
@@ -64,7 +65,7 @@ public final class CalendarFieldFunction
 	private int getCalField(double serialDate) {
 	   // For some reason, a date of 0 in Excel gets shown
 	   //  as the non existant 1900-01-00
-		if(((int)serialDate) == 0) {
+		if (((int)serialDate) == 0) {
 			switch (_dateFieldId) {
 				case Calendar.YEAR: return 1900;
 				case Calendar.MONTH: return 1;
@@ -74,10 +75,9 @@ public final class CalendarFieldFunction
 		}
 
 		// TODO Figure out if we're in 1900 or 1904
-		Date d = DateUtil.getJavaDate(serialDate, false);
-
-		Calendar c = new GregorianCalendar();
-		c.setTime(d);
+		// EXCEL functions round up nearly a half second (probably to prevent floating point
+		// rounding issues); use UTC here to prevent daylight saving issues for HOUR
+		Calendar c = DateUtil.getJavaCalendarUTC(serialDate + 0.4995 / DateUtil.SECONDS_PER_DAY, false);
 		int result = c.get(_dateFieldId);
 		
 		// Month is a special case due to C semantics

Added: poi/trunk/src/java/org/apache/poi/ss/formula/functions/WeekdayFunc.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/formula/functions/WeekdayFunc.java?rev=1371969&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/formula/functions/WeekdayFunc.java (added)
+++ poi/trunk/src/java/org/apache/poi/ss/formula/functions/WeekdayFunc.java Sat Aug 11 16:14:49 2012
@@ -0,0 +1,127 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.ss.formula.functions;
+
+import java.util.Calendar;
+
+import org.apache.poi.ss.formula.eval.BlankEval;
+import org.apache.poi.ss.formula.eval.ErrorEval;
+import org.apache.poi.ss.formula.eval.EvaluationException;
+import org.apache.poi.ss.formula.eval.MissingArgEval;
+import org.apache.poi.ss.formula.eval.NumberEval;
+import org.apache.poi.ss.formula.eval.OperandResolver;
+import org.apache.poi.ss.formula.eval.ValueEval;
+import org.apache.poi.ss.usermodel.DateUtil;
+
+
+/**
+ * Implementation for the Excel function WEEKDAY
+ *
+ * @author Thies Wellpott
+ */
+public final class WeekdayFunc implements Function {
+//or:  extends Var1or2ArgFunction {
+
+	public static final Function instance = new WeekdayFunc();
+
+	private WeekdayFunc() {
+		// no fields to initialise
+	}
+
+	/* for Var1or2ArgFunction:
+	@Override
+	public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
+	}
+
+	@Override
+	public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
+	}
+	*/
+
+
+	/**
+	 * Perform WEEKDAY(date, returnOption) function.
+	 * Note: Parameter texts are from German EXCEL-2010 help.
+	 * Parameters in args[]:
+	 * @param serialDate
+	 * EXCEL-date value
+	 * Standardmaessig ist der 1. Januar 1900 die fortlaufende Zahl 1 und
+	 * der 1. Januar 2008 die fortlaufende Zahl 39.448, da dieser Tag nach 39.448 Tagen
+	 * auf den 01.01.1900 folgt.
+	 * @param returnOption (optional)
+	 * Bestimmt den Rueckgabewert:
+		1	oder nicht angegeben Zahl 1 (Sonntag) bis 7 (Samstag). Verhaelt sich wie fruehere Microsoft Excel-Versionen.
+		2	Zahl 1 (Montag) bis 7 (Sonntag).
+		3	Zahl 0 (Montag) bis 6 (Sonntag).
+		11	Die Zahlen 1 (Montag) bis 7 (Sonntag)
+		12	Die Zahlen 1 (Dienstag) bis 7 (Montag)
+		13	Die Zahlen 1 (Mittwoch) bis 7 (Dienstag)
+		14	Die Zahlen 1 (Donnerstag) bis 7 (Mittwoch)
+		15	Die Zahlen 1 (Freitag) bis 7 (Donnerstag)
+		16	Die Zahlen 1 (Samstag) bis 7 (Freitag)
+		17	Die Zahlen 1 (Sonntag) bis 7 (Samstag)
+	 */
+	@Override
+	public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+		try {
+			if (args.length < 1  ||  args.length > 2) {
+				return ErrorEval.VALUE_INVALID;
+			}
+
+			// extract first parameter
+			ValueEval serialDateVE = OperandResolver.getSingleValue(args[0], srcRowIndex, srcColumnIndex);
+			double serialDate = OperandResolver.coerceValueToDouble(serialDateVE);
+			if (!DateUtil.isValidExcelDate(serialDate)) {
+				return ErrorEval.NUM_ERROR;						// EXCEL uses this and no VALUE_ERROR
+			}
+			Calendar date = DateUtil.getJavaCalendar(serialDate, false);		// (XXX 1904-windowing not respected)
+			int weekday = date.get(Calendar.DAY_OF_WEEK);		// => sunday = 1, monday = 2, ..., saturday = 7
+
+			// extract second parameter
+			int returnOption = 1;					// default value
+			if (args.length == 2) {
+				ValueEval ve = OperandResolver.getSingleValue(args[1], srcRowIndex, srcColumnIndex);
+				if (ve == MissingArgEval.instance  ||  ve == BlankEval.instance) {
+					return ErrorEval.NUM_ERROR;		// EXCEL uses this and no VALUE_ERROR
+				}
+				returnOption = OperandResolver.coerceValueToInt(ve);
+				if (returnOption == 2) {
+					returnOption = 11;				// both mean the same
+				}
+			} // if
+
+			// perform calculation
+			double result;
+			if (returnOption == 1) {
+				result = weekday;
+			// value 2 is handled above (as value 11)
+			} else if (returnOption == 3) {
+				result = (weekday + 6 - 1) % 7;
+			} else if (returnOption >= 11  &&  returnOption <= 17) {
+				result = (weekday + 6 - (returnOption - 10)) % 7 + 1;		// rotate in the value range 1 to 7
+			} else {
+				return ErrorEval.NUM_ERROR;		// EXCEL uses this and no VALUE_ERROR
+			}
+
+			return new NumberEval(result);
+		} catch (EvaluationException e) {
+			return e.getErrorEval();
+		}
+	} // evaluate()
+
+}

Modified: poi/trunk/src/java/org/apache/poi/ss/usermodel/DateUtil.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/usermodel/DateUtil.java?rev=1371969&r1=1371968&r2=1371969&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/usermodel/DateUtil.java (original)
+++ poi/trunk/src/java/org/apache/poi/ss/usermodel/DateUtil.java Sat Aug 11 16:14:49 2012
@@ -33,18 +33,20 @@ import java.util.regex.Pattern;
  * @author  Hack Kampbjorn (hak at 2mba.dk)
  * @author  Alex Jacoby (ajacoby at gmail.com)
  * @author  Pavel Krupets (pkrupets at palmtreebusiness dot com)
+ * @author  Thies Wellpott
  */
 public class DateUtil {
     protected DateUtil() {
         // no instances of this class
     }
-    private static final int SECONDS_PER_MINUTE = 60;
-    private static final int MINUTES_PER_HOUR = 60;
-    private static final int HOURS_PER_DAY = 24;
-    private static final int SECONDS_PER_DAY = (HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
+
+    public static final int SECONDS_PER_MINUTE = 60;
+    public static final int MINUTES_PER_HOUR = 60;
+    public static final int HOURS_PER_DAY = 24;
+    public static final int SECONDS_PER_DAY = (HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE);
 
     private static final int    BAD_DATE         = -1;   // used to specify that date is invalid
-    private static final long   DAY_MILLISECONDS = SECONDS_PER_DAY * 1000L;
+    public static final long   DAY_MILLISECONDS = SECONDS_PER_DAY * 1000L;
 
     private static final Pattern TIME_SEPARATOR_PATTERN = Pattern.compile(":");
 
@@ -57,6 +59,10 @@ public class DateUtil {
     //  elapsed time patterns: [h],[m] and [s]
     private static final Pattern date_ptrn4 = Pattern.compile("^\\[([hH]+|[mM]+|[sS]+)\\]");
 
+    // only get this static info once (because operations are not really cheap)
+    private static final TimeZone TIMEZONE_UTC = TimeZone.getTimeZone("UTC");
+
+
     /**
      * Given a Date, converts it into a double representing its internal Excel representation,
      *   which is the number of days since 1/1/1900. Fractional days represent hours, minutes, and seconds.
@@ -178,19 +184,7 @@ public class DateUtil {
      *  @return Java representation of the date, or null if date is not a valid Excel date
      */
     public static Date getJavaDate(double date, boolean use1904windowing, TimeZone tz) {
-       if (!isValidExcelDate(date)) {
-          return null;
-       }
-       Calendar calendar;
-       if (tz != null)
-          calendar = new GregorianCalendar(tz);
-       else
-          calendar = new GregorianCalendar(); // using default time-zone
-       
-      int wholeDays = (int)Math.floor(date);
-      int millisecondsInDay = (int)((date - wholeDays) * DAY_MILLISECONDS + 0.5);
-      setCalendar(calendar, wholeDays, millisecondsInDay, use1904windowing);
-      return calendar.getTime();
+        return getJavaCalendar(date, use1904windowing, tz).getTime();
     }
     /**
      *  Given an Excel date with either 1900 or 1904 date windowing,
@@ -212,8 +206,10 @@ public class DateUtil {
      *  @see java.util.TimeZone
      */
     public static Date getJavaDate(double date, boolean use1904windowing) {
-       return getJavaDate(date, use1904windowing, (TimeZone)null);
+        return getJavaCalendar(date, use1904windowing).getTime();
     }
+
+
     public static void setCalendar(Calendar calendar, int wholeDays,
             int millisecondsInDay, boolean use1904windowing) {
         int startYear = 1900;
@@ -233,6 +229,54 @@ public class DateUtil {
 
 
     /**
+     * Get EXCEL date as Java Calendar (with default time zone).
+     * This is like {@link #getJavaDate(double, boolean)} but returns a Calendar object.
+     *  @param date  The Excel date.
+     *  @param use1904windowing  true if date uses 1904 windowing,
+     *   or false if using 1900 date windowing.
+     *  @return Java representation of the date, or null if date is not a valid Excel date
+     */
+    public static Calendar getJavaCalendar(double date, boolean use1904windowing) {
+    	return getJavaCalendar(date, use1904windowing, (TimeZone)null);
+    }
+
+    /**
+     * Get EXCEL date as Java Calendar with UTC time zone.
+     * This is similar to {@link #getJavaDate(double, boolean)} but returns a
+     * Calendar object that has UTC as time zone, so no daylight saving hassle.
+     *  @param date  The Excel date.
+     *  @param use1904windowing  true if date uses 1904 windowing,
+     *   or false if using 1900 date windowing.
+     *  @return Java representation of the date in UTC, or null if date is not a valid Excel date
+     */
+    public static Calendar getJavaCalendarUTC(double date, boolean use1904windowing) {
+    	return getJavaCalendar(date, use1904windowing, TIMEZONE_UTC);
+    }
+
+
+    /**
+     * Get EXCEL date as Java Calendar with given time zone.
+     * @see getJavaDate(double, TimeZone)
+     * @return Java representation of the date, or null if date is not a valid Excel date
+     */
+    public static Calendar getJavaCalendar(double date, boolean use1904windowing, TimeZone timeZone) {
+        if (!isValidExcelDate(date)) {
+            return null;
+        }
+        int wholeDays = (int)Math.floor(date);
+        int millisecondsInDay = (int)((date - wholeDays) * DAY_MILLISECONDS + 0.5);
+        Calendar calendar;
+        if (timeZone != null) {
+            calendar = new GregorianCalendar(timeZone);
+        } else {
+            calendar = new GregorianCalendar();     // using default time-zone
+        }
+        setCalendar(calendar, wholeDays, millisecondsInDay, use1904windowing);
+        return calendar;
+    }
+
+
+    /**
      * Given a format ID and its format String, will check to see if the
      *  format represents a date format or not.
      * Firstly, it will check to see if the format ID corresponds to an
@@ -257,7 +301,7 @@ public class DateUtil {
         }
 
         String fs = formatString;
-        if (false) {
+        /*if (false) {
             // Normalize the format string. The code below is equivalent
             // to the following consecutive regexp replacements:
 
@@ -276,7 +320,7 @@ public class DateUtil {
 
              // The code above was reworked as suggested in bug 48425:
              // simple loop is more efficient than consecutive regexp replacements.
-        }
+        }*/
         StringBuilder sb = new StringBuilder(fs.length());
         for (int i = 0; i < fs.length(); i++) {
             char c = fs.charAt(i);

Modified: poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestAddress.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestAddress.java?rev=1371969&r1=1371968&r2=1371969&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestAddress.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestAddress.java Sat Aug 11 16:14:49 2012
@@ -33,6 +33,9 @@ public final class TestAddress extends T
         String formulaText = "ADDRESS(1,2)";
         confirmResult(fe, cell, formulaText, "$B$1");
 
+        formulaText = "ADDRESS(1,2,)";					// with explicitly empty third parameter
+        confirmResult(fe, cell, formulaText, "$B$1");
+
         formulaText = "ADDRESS(22,44)";
         confirmResult(fe, cell, formulaText, "$AR$22");
 

Modified: poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestCalendarFieldFunction.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestCalendarFieldFunction.java?rev=1371969&r1=1371968&r2=1371969&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestCalendarFieldFunction.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestCalendarFieldFunction.java Sat Aug 11 16:14:49 2012
@@ -59,6 +59,33 @@ public final class TestCalendarFieldFunc
         confirm("SECOND(40627.4860417)", 54);
     }
 
+    public void testRounding() {
+		// 41484.999994200 = 23:59:59,499
+		// 41484.9999942129 = 23:59:59,500  (but sub-milliseconds are below 0.5 (0.49999453965575), XLS-second results in 59)
+		// 41484.9999942130 = 23:59:59,500  (sub-milliseconds are 0.50000334065408, XLS-second results in 00)
+
+        confirm("DAY(41484.999994200)", 29);
+        confirm("SECOND(41484.999994200)", 59);
+
+        confirm("DAY(41484.9999942129)", 29);
+        confirm("HOUR(41484.9999942129)", 23);
+        confirm("MINUTE(41484.9999942129)", 59);
+        confirm("SECOND(41484.9999942129)", 59);
+		
+        confirm("DAY(41484.9999942130)", 30);
+        confirm("HOUR(41484.9999942130)", 0);
+        confirm("MINUTE(41484.9999942130)", 0);
+        confirm("SECOND(41484.9999942130)", 0);
+	}
+
+    public void testDaylightSaving() {
+        confirm("HOUR(41364.08263888890000)", 1);		// 31.03.2013 01:59:00,000
+        confirm("HOUR(41364.08333333330000)", 2);		// 31.03.2013 02:00:00,000 (this time does not exist in TZ CET, but EXCEL does not care)
+        confirm("HOUR(41364.08402777780000)", 2);		// 31.03.2013 02:01:00,000
+        confirm("HOUR(41364.12430555560000)", 2);		// 31.03.2013 02:59:00,000
+        confirm("HOUR(41364.12500000000000)", 3);		// 31.03.2013 03:00:00,000
+	}
+
     public void testBugDate() {
         confirm("YEAR(0.0)", 1900);
         confirm("MONTH(0.0)", 1);



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org