org.apache.poi.ss.formula.eval.NotImplementedException:DATEDIF

时间:2015-06-30 04:59:42

标签: apache apache-poi

我在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

请帮忙。

1 个答案:

答案 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