Java POI XSSF和SAX(事件API)的日期格式问题

Java POI XSSF和SAX(事件API)的日期格式问题,java,apache-poi,Java,Apache Poi,我正在使用POI的事件API来处理大量记录,而没有任何内存问题。这是它的参考 在处理XLSX工作表时,我得到的日期值格式与excel工作表中指定的格式不同。excel工作表中某列的日期格式为“dd-mm-yyy”,其中我得到的值为“mm/dd/yy”格式 有人能告诉我如何得到excel表格中给出的实际格式吗。下面给出了代码段的参考 ContentHandler handler = new XSSFSheetXMLHandler(styles, strings, new She

我正在使用POI的事件API来处理大量记录,而没有任何内存问题。这是它的参考

在处理XLSX工作表时,我得到的日期值格式与excel工作表中指定的格式不同。excel工作表中某列的日期格式为“dd-mm-yyy”,其中我得到的值为“mm/dd/yy”格式

有人能告诉我如何得到excel表格中给出的实际格式吗。下面给出了代码段的参考

ContentHandler handler = new XSSFSheetXMLHandler(styles, strings,
          new SheetContentsHandler() {
            public void startRow(int rowNum) {
            }
            public void endRow() {
            }
            public void cell(String cellReference, String formattedValue) {
                  System.out.println(formattedValue);
                } catch (IOException e) {
                    System.out.println(
                      "Exception during file writing");
                }
              }

为日期列获取单元格中的formmatedValue方法类似于“mm/dd/yy”,因此我无法在pl/sql程序中正确执行验证

Excel使用区域设置存储某些日期。例如,在Excel中的“数字格式”对话框中,您将看到如下警告:

根据指定的类型和区域设置(位置),将日期和时间序列号显示为日期值。以星号(*)开头的日期格式响应“控制面板”中指定的区域日期和时间设置的更改。不带星号的格式不受控制面板设置的影响

您正在读取的Excel文件可能正在使用其中一个*日期。在这种情况下,POI可能使用美国默认值

您可能需要添加一些变通代码来将日期格式字符串映射到所需的格式


另请参见下面的讨论。

我也有同样的问题。经过几天的谷歌搜索和研究,我想出了一个解决方案。不幸的是,这并不好,但它是有效的:

  • 在项目中复制一个
    org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler
  • 在类中找到接口
    SheetContentsHandler
  • 添加新的方法定义:
    stringoverridedenformat(stringcellref、int-formatIndex、stringformatstring)
  • 在类中找到此方法:
    public void endElement(字符串uri、字符串localName、字符串name)抛出SAXException
  • 它有一个很长的切换单元类型
  • NUMBER
    的情况下,有这样一个if语句:
    if(this.formatString!=null){…
  • 在此之前,请粘贴以下代码:

    String overriddenFormat = output.overriddenFormat(cellRef, formatIndex, formatString);
    if (overriddenFormat != null) {
        this.formatIndex = -1;
        this.formatString = overriddenFormat;
    }
    
  • 遵循本文/答案:但是使用新的类和接口

  • 现在,如果需要,您可以使用独特的日期格式
  • 我的用例是: 在给定的工作表中,我在G、H和I列中有日期值,因此我对
    SheetContentsHandler.overridedenformat
    的实现是:

    @Override
    public String overriddenFormat(String cellRef, int formatIndex, String formatString) {
        if (cellRef.matches("(G|H|I)\\d+")) { //matches all cells in G, H, and I columns
            return "yyyy-mm-dd;@"; //this is the hungarian date format in excel
        }
        return null;
    }
    

    如您所见,在
    endElement
    方法中,我覆盖了formatIndex和formatString。formatIndex的可能值在
    org.apache.poi.ss.usermodel.DateUtil.isInternalDateFormat(int format)
    中描述。如果给定值不适合这些值(并且-1不适合),formatString将通过格式化时间戳值来使用。(时间戳值从大约1900.01.01开始计数,并具有日分辨率。)

    要记住两点:

  • 原始Excel单元格的格式可能不适合您 或者可以格式化为一般文本
  • 您可能希望精确地控制日期、时间或数值的方式 已格式化
  • 控制日期和其他数值格式的另一种方法是提供您自己的自定义数据格式化程序,扩展org.apache.poi.ss.usermodel.DataFormatter

    只需重写formatRawCellContents()方法(或根据需要重写其他方法):

    构造解析器/处理程序的示例代码:

    public void processSheet(Styles styles, SharedStrings strings,
            SheetContentsHandler sheetHandler, InputStream sheetInputStream)
            throws IOException, SAXException {
        DataFormatter formatter = new CustomDataFormatter();
        InputSource sheetSource = new InputSource(sheetInputStream);
        try {
            XMLReader sheetParser = SAXHelper.newXMLReader();
            ContentHandler handler = new XSSFSheetXMLHandler(styles, null, strings, sheetHandler,
                    formatter, false);
            sheetParser.setContentHandler(handler);
            sheetParser.parse(sheetSource);
        } catch (ParserConfigurationException e) {
            throw new RuntimeException("SAX parser appears to be broken - " + e.getMessage());
        }
    }
    
    private class CustomDataFormatter extends DataFormatter {
    
        @Override
        public String formatRawCellContents(double value, int formatIndex, String formatString,
                boolean use1904Windowing) {
    
            // Is it a date?
            if (DateUtil.isADateFormat(formatIndex, formatString)) {
                if (DateUtil.isValidExcelDate(value)) {
                    Date d = DateUtil.getJavaDate(value, use1904Windowing);
                    try {
                        return new SimpleDateFormat("yyyyMMdd").format(d);
                    } catch (Exception e) {
                        logger.log(Level.SEVERE, "Bad date value in Excel: " + d, e);
                    }
                }
            }
            return new DecimalFormat("##0.#####").format(value);
        }
    }
    

    好吧,这绝对没问题。当我手动将区域设置更改为UK时,我得到了预期的值(dd-mm-yyy)。但是我想用宏更改区域设置,因为我的工作表是用另一个宏工作表生成的。你知道吗?