aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYegor Kozlov <yegor@apache.org>2012-08-11 16:14:49 +0000
committerYegor Kozlov <yegor@apache.org>2012-08-11 16:14:49 +0000
commit3f23441a94d49c8db19571f9438f666ab1e3c4f5 (patch)
tree19793106f72df748eefca833ce9f91dcff3f5524
parent1f2381967a0a9fd2725abf2915eb9ff0a9ce8ab9 (diff)
downloadpoi-3f23441a94d49c8db19571f9438f666ab1e3c4f5.tar.gz
poi-3f23441a94d49c8db19571f9438f666ab1e3c4f5.zip
Bugzilla 53644: XLS formula bugfix (CalFieldFunc) + WeekDay addon
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1371969 13f79535-47bb-0310-9956-ffa450edef68
-rwxr-xr-xpatch.xml4
-rw-r--r--src/documentation/content/xdocs/spreadsheet/eval-devguide.xml5
-rw-r--r--src/documentation/content/xdocs/status.xml1
-rw-r--r--src/java/org/apache/poi/ss/formula/eval/FunctionEval.java1
-rw-r--r--src/java/org/apache/poi/ss/formula/functions/Address.java4
-rw-r--r--src/java/org/apache/poi/ss/formula/functions/BooleanFunction.java3
-rw-r--r--src/java/org/apache/poi/ss/formula/functions/CalendarFieldFunction.java18
-rw-r--r--src/java/org/apache/poi/ss/formula/functions/WeekdayFunc.java127
-rw-r--r--src/java/org/apache/poi/ss/usermodel/DateUtil.java86
-rw-r--r--src/testcases/org/apache/poi/ss/formula/functions/TestAddress.java3
-rw-r--r--src/testcases/org/apache/poi/ss/formula/functions/TestCalendarFieldFunction.java27
11 files changed, 243 insertions, 36 deletions
diff --git a/patch.xml b/patch.xml
index 56852f4b5f..61b3cb7a95 100755
--- a/patch.xml
+++ b/patch.xml
@@ -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/>
diff --git a/src/documentation/content/xdocs/spreadsheet/eval-devguide.xml b/src/documentation/content/xdocs/spreadsheet/eval-devguide.xml
index f7c17650bd..99eecff4e0 100644
--- a/src/documentation/content/xdocs/spreadsheet/eval-devguide.xml
+++ b/src/documentation/content/xdocs/spreadsheet/eval-devguide.xml
@@ -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
diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml
index d3a744b48e..57109eeb9f 100644
--- a/src/documentation/content/xdocs/status.xml
+++ b/src/documentation/content/xdocs/status.xml
@@ -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>
diff --git a/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java b/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java
index fb4f8d7252..c76da52c17 100644
--- a/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java
+++ b/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java
@@ -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;
diff --git a/src/java/org/apache/poi/ss/formula/functions/Address.java b/src/java/org/apache/poi/ss/formula/functions/Address.java
index 288a88edc9..379135f148 100644
--- a/src/java/org/apache/poi/ss/formula/functions/Address.java
+++ b/src/java/org/apache/poi/ss/formula/functions/Address.java
@@ -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:
diff --git a/src/java/org/apache/poi/ss/formula/functions/BooleanFunction.java b/src/java/org/apache/poi/ss/formula/functions/BooleanFunction.java
index b90f929fb9..9e796e7040 100644
--- a/src/java/org/apache/poi/ss/formula/functions/BooleanFunction.java
+++ b/src/java/org/apache/poi/ss/formula/functions/BooleanFunction.java
@@ -20,6 +20,7 @@ package org.apache.poi.ss.formula.functions;
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 implements Function {
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);
}
diff --git a/src/java/org/apache/poi/ss/formula/functions/CalendarFieldFunction.java b/src/java/org/apache/poi/ss/formula/functions/CalendarFieldFunction.java
index 73a4b2341e..28af57a2a5 100644
--- a/src/java/org/apache/poi/ss/formula/functions/CalendarFieldFunction.java
+++ b/src/java/org/apache/poi/ss/formula/functions/CalendarFieldFunction.java
@@ -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.DateUtil;
* 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 extends Fixed1ArgFunction {
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 extends Fixed1ArgFunction {
}
// 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
diff --git a/src/java/org/apache/poi/ss/formula/functions/WeekdayFunc.java b/src/java/org/apache/poi/ss/formula/functions/WeekdayFunc.java
new file mode 100644
index 0000000000..0720b11f16
--- /dev/null
+++ b/src/java/org/apache/poi/ss/formula/functions/WeekdayFunc.java
@@ -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()
+
+}
diff --git a/src/java/org/apache/poi/ss/usermodel/DateUtil.java b/src/java/org/apache/poi/ss/usermodel/DateUtil.java
index 9d1af834dc..31942449ff 100644
--- a/src/java/org/apache/poi/ss/usermodel/DateUtil.java
+++ b/src/java/org/apache/poi/ss/usermodel/DateUtil.java
@@ -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);
diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestAddress.java b/src/testcases/org/apache/poi/ss/formula/functions/TestAddress.java
index 07fb6aa895..013b15806c 100644
--- a/src/testcases/org/apache/poi/ss/formula/functions/TestAddress.java
+++ b/src/testcases/org/apache/poi/ss/formula/functions/TestAddress.java
@@ -33,6 +33,9 @@ public final class TestAddress extends TestCase {
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");
diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestCalendarFieldFunction.java b/src/testcases/org/apache/poi/ss/formula/functions/TestCalendarFieldFunction.java
index ede20de393..636c72a427 100644
--- a/src/testcases/org/apache/poi/ss/formula/functions/TestCalendarFieldFunction.java
+++ b/src/testcases/org/apache/poi/ss/formula/functions/TestCalendarFieldFunction.java
@@ -59,6 +59,33 @@ public final class TestCalendarFieldFunction extends TestCase {
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);