我在Excel工作表中使用了一个公式:=DATEDIF(TODAY(),E2,"y") & " years " & DATEDIF(TODAY(),E2,"ym") & " months " & DATEDIF(TODAY(),E2,"md") & " days" where E2 = 14-Aug-2015
执行HSSFFormulaEvaluator.evaluateAllFormulaCells(wb)
我得到<异常
org.apache.poi.ss.formula.eval.NotImplementedFunctionException:DATEDIF
请帮忙。
答案 0 :(得分:2)
自Apache POI 3.12版起,不支持DATEDIF()。您可以通过运行来检查支持哪些功能:
Collection<String> supportedFuncs = WorkbookEvaluator.getSupportedFunctionNames();
这个link描述了如何编写用户定义的函数并将其注册到公式赋值器中:
Two base interfaces to start your implementation
所有Excel公式函数类都实现org.apache.poi.hssf.record.formula.functions.Function或org.apache.poi.hssf.record.formula.functions.FreeRefFunction接口。函数是以二进制Excel格式(BIFF8)定义的函数的通用接口:这些是“经典”Excel函数,如SUM,COUNT,LOOKUP等.FreeRefFunction是Excel Analysis Toolpack和User中函数的通用接口。 - 定义的函数。在未来,这两个接口应该统一为一个,但是现在你必须从两个略有不同的根开始实现。
Which interface to start from?
您将要实现一个函数XXX,并且不知道从哪个接口开始:Function或FreeRefFunction。使用以下代码检查您的函数是否来自excel Analysis Toolpack:
if(AnalysisToolPack.isATPFunction(functionName)){ // the function implements org.apache.poi.hssf.record.formula.functions.Function } else { // the function implements org.apache.poi.hssf.record.formula.functions.FreeRefFunction }
Walkthrough of an "evaluate()" implementation.
以下是有趣的部分:让我们逐步介绍excel函数的实现 SQRT()
AnalysisToolPack.isATPFunction(“SQRTPI”)返回false,因此基接口为Function。在实现具有固定数量的参数的数字函数或函数时,有一些子接口可以使生活更轻松,1-arg,2-arg和3-arg函数:
- org.apache.poi.hssf.record.formula.functions.NumericFunction
- org.apache.poi.hssf.record.formula.functions.Fixed1ArgFunction
- org.apache.poi.hssf.record.formula.functions.Fixed2ArgFunction
- org.apache.poi.hssf.record.formula.functions.Fixed3ArgFunction
- org.apache.poi.hssf.record.formula.functions.Fixed4ArgFunction
由于SQRTPI只接受一个参数,我们从org.apache.poi.hssf.record.formula.functions.Fixed1ArgFunction开始实现:
Function SQRTPI = new Fixed1ArgFunction() { public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) { try { // Retrieves a single value from a variety of different argument types according to standard // Excel rules. Does not perform any type conversion. ValueEval ve = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex); // Applies some conversion rules if the supplied value is not already a number. // Throws EvaluationException(#VALUE!) if the supplied parameter is not a number double arg = OperandResolver.coerceValueToDouble(ve); // this where all the heavy-lifting happens double result = Math.sqrt(arg*Math.PI); // Excel uses the error code #NUM! instead of IEEE _NaN_ and _Infinity_, // so when a numeric function evaluates to Double.NaN or Double.Infinity, // be sure to translate the result to the appropriate error code if (Double.isNaN(result) || Double.isInfinite(result)) { throw new EvaluationException(ErrorEval.NUM_ERROR); } return new NumberEval(result); } catch (EvaluationException e){ return e.getErrorEval(); } } }
现在,当实现准备就绪时,我们需要在公式评估器中注册它:
WorkbookEvaluator.registerFunction("SQRTPI", SQRTPI);
瞧!公式评估器现在识别SQRTPI!
- https://poi.apache.org/components/spreadsheet/eval-devguide.html