add basic implementation of TIMEVALUE function

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1892044 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
PJ Fanning 2021-08-06 16:53:27 +00:00
parent 828cf12f08
commit 5bcde4ceaf
4 changed files with 183 additions and 2 deletions

View File

@ -181,7 +181,7 @@ public final class FunctionEval {
retval[130] = new T();
// 131: N
retval[140] = new DateValue();
// 141: TIMEVALUE
retval[141] = new TimeValue();
// 142: SLN
// 143: SYD
// 144: DDB

View File

@ -33,7 +33,8 @@ import java.time.DateTimeException;
* <p>
* The <b>DATEVALUE</b> function converts a date that is stored as text to a serial number that Excel
* recognizes as a date. For example, the formula <b>=DATEVALUE("1/1/2008")</b> returns 39448, the
* serial number of the date 1/1/2008. Remember, though, that your computer's system date setting may
* serial number of the date 1/1/2008. Any time element is ignored (see {@link TimeValue}).
* Remember, though, that your computer's system date setting may
* cause the results of a <b>DATEVALUE</b> function to vary from this example
* <p>
* The <b>DATEVALUE</b> function is helpful in cases where a worksheet contains dates in a text format

View File

@ -0,0 +1,84 @@
/* ====================================================================
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 org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.ss.formula.eval.*;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.util.DateParser;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.util.Date;
/**
* Implementation for the TIMEVALUE() Excel function.<p>
*
* <b>Syntax:</b><br>
* <b>TIMEVALUE</b>(<b>date_text</b>)
* <p>
* The <b>TIMEVALUE</b> function converts a time that is stored as text to a serial number that Excel
* recognizes as a date/time. For example, the formula <b>=TIMEVALUE("1/1/2008 12:00")</b> returns 0.5, the
* serial number of the time 12:00. The date element is ignored (see {@link DateValue}).
* Remember, though, that your computer's system date setting may
* cause the results of a <b>TIMEVALUE</b> function to vary from this example.
* <p>
* The <b>TIMEVALUE</b> function is helpful in cases where a worksheet contains dates/times in a text format
* that you want to filter, sort, or format as times, or use in time calculations.
* <p>
* To view a date serial number as a time, you must apply a times format to the cell.
*/
public class TimeValue extends Fixed1ArgFunction {
private static final Logger LOG = LogManager.getLogger(TimeValue.class);
@Override
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval dateTimeTextArg) {
try {
String dateTimeText = OperandResolver.coerceValueToString(
OperandResolver.getSingleValue(dateTimeTextArg, srcRowIndex, srcColumnIndex));
if (dateTimeText == null || dateTimeText.isEmpty()) {
return BlankEval.instance;
}
try {
return parseTime(dateTimeText);
} catch (Exception e) {
try {
return parseTime("1/01/2000 " + dateTimeText);
} catch (Exception e2) {
LocalDate ld = DateParser.parseLocalDate(dateTimeText);
//return 0 as this is a pure date with no time element
return new NumberEval(0);
}
}
} catch (DateTimeException dte) {
LOG.atInfo().log("Failed to parse date/time", dte);
return ErrorEval.VALUE_INVALID;
} catch (EvaluationException e) {
return e.getErrorEval();
}
}
private NumberEval parseTime(String dateTimeText) throws EvaluationException {
double dateTimeValue = DateUtil.parseDateTime(dateTimeText);
return new NumberEval(dateTimeValue - DateUtil.getExcelDate(DateParser.parseLocalDate(dateTimeText)));
}
}

View File

@ -0,0 +1,96 @@
/* ====================================================================
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 org.apache.poi.ss.formula.eval.*;
import org.apache.poi.util.LocaleUtil;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.util.Locale;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* Tests for Excel function TIMEVALUE()
*/
final class TestTimeValue {
@BeforeAll
public static void init() {
LocaleUtil.setUserLocale(Locale.US);
}
@AfterAll
public static void clear() {
LocaleUtil.setUserLocale(null);
}
@Test
void testTimeValue() {
LocaleUtil.setUserLocale(Locale.ENGLISH);
try {
confirmTimeValue(new StringEval(""));
confirmTimeValue(BlankEval.instance);
confirmTimeValueError(new StringEval("non-date text"));
// // EXCEL
confirmTimeValue(new StringEval("8/22/2011"), 0); // Serial number of a time entered as text.
confirmTimeValue(new StringEval("8/22/2011 12:00"), 0.5); // Serial number of a time entered as text.
confirmTimeValue(new StringEval("1/01/2000 06:00"), 0.25); // Serial number of a time entered as text.
confirmTimeValue(new StringEval("1/01/2000 6:00 PM"), 0.75); // Serial number of a time entered as text.
confirmTimeValue(new StringEval("12:00"), 0.5); // Serial number of a time entered as text.
confirmTimeValue(new StringEval("6:00 PM"), 0.75); // Serial number of a time entered as text.
} finally {
LocaleUtil.setUserLocale(null);
}
}
@Test
void testInvalidTimeValue() {
assertEquals(ErrorEval.VALUE_INVALID, invokeTimeValue(new StringEval("not-date")),
"not-date evals to invalid");
assertEquals(ErrorEval.VALUE_INVALID, invokeTimeValue(BoolEval.FALSE),
"false evals to invalid");
assertEquals(ErrorEval.VALUE_INVALID, invokeTimeValue(new NumberEval(Math.E)),
"Math.E evals to invalid");
}
private ValueEval invokeTimeValue(ValueEval text) {
return new TimeValue().evaluate(0, 0, text);
}
private void confirmTimeValue(ValueEval text, double expected) {
ValueEval result = invokeTimeValue(text);
assertEquals(NumberEval.class, result.getClass());
assertEquals(expected, ((NumberEval) result).getNumberValue(), 0.0001);
}
private void confirmTimeValue(ValueEval text) {
ValueEval result = invokeTimeValue(text);
assertEquals(BlankEval.class, result.getClass());
}
private void confirmTimeValueError(ValueEval text) {
ValueEval result = invokeTimeValue(text);
assertEquals(ErrorEval.class, result.getClass());
assertEquals(ErrorEval.VALUE_INVALID.getErrorCode(), ((ErrorEval) result).getErrorCode());
}
}