POI reconoce celdas con formato de hora y fecha en chino en tablas de Excel

POI reconoce celdas con formato de hora y fecha en chino en tablas de Excel

El enfoque de este artículo es abordar dos preguntas:

1. El tiempo de reconocimiento de PDI Excel contiene chino, por ejemplo: 22 de enero de 2021

2. POI reconoce datos de tiempo cuyas celdas en Excel son de tipo de fecha o de tipo de hora

Prefacio:

Este artículo utiliza principalmente ejemplos para resolver los dos problemas anteriores. Para resaltar el código que resuelve principalmente el problema, se toma como ejemplo el método de reconocimiento de la tabla de tipo xlsx.

1. El reconocimiento de puntos de interés contiene la hora china

Prólogo:
tome principalmente el tipo de tiempo de xx, xx, xxxx como ejemplo para la demostración

Antecedentes:
desde la versión POI 3.X, poi no puede reconocer la hora china en Excel. Sin embargo, cuando el chino aparece en nuestro Excel, aún debemos reconocerlo.

analizar:

Para la identificación de tipos de datos en poi, se utiliza principalmente el método DateUtil.isCellDateFormatted(Cell cell) del paquete org.apache.poi.ss.usermodel.DateUtil. Al observar el código fuente del método isCellDateFormatted, encontramos que el método isADateFormat para analizar datos de tiempo solo analiza los símbolos y no analiza los datos chinos correspondientes, como 'año', 'mes', 'día', etc. Caracteres chinos clave.

//以下 isADateFormat 方法中对于时间数据的分析源码
if (separatorIndex < length - 1) {
	char nc = fs.charAt(separatorIndex + 1);
	if (c == '\\') {
        switch(nc) {
            case ' ':
            case ',':
            case '-':
            case '.':
            case '\\':
            continue;
        }
    } else if (c == ';' && nc == '@') {
    	++separatorIndex;
    	continue;
	}
}

solución:

Para darnos cuenta de que isCellDateFormatted en POI puede analizar la hora china, necesitamos reescribir este método. El siguiente es el método modificado, que se puede copiar y usar directamente

//直接创建一个DateFormatUtil的工具类,当我们需要对时间类型进行判断时,直接使用DateFormatUtil.isCellDateFormatted (Cell cell)方法即可
public class DateFormatUtil{
    public static boolean isCellDateFormatted(Cell cell)
    {
        if (cell == null) {
            return false;
        }
        boolean bDate = false;

        double d = cell.getNumericCellValue();
        if (isValidExcelDate(d)) {
            CellStyle style = cell.getCellStyle();
            if (style == null) {
                return false;
            }
            int i = style.getDataFormat();
            String f = style.getDataFormatString();
            bDate = isADateFormat(i, f);
        }
        return bDate;
    }

    public static boolean isADateFormat(int formatIndex, String formatString)
    {
        if (isInternalDateFormat(formatIndex)) {
            return true;
        }

        if ((formatString == null) || (formatString.length() == 0)) {
            return false;
        }

        String fs = formatString;
        //下面这一行是自己手动添加的 以支持汉字格式wingzing
        fs = fs.replaceAll("[\"|\']","").replaceAll("[年|月|日|时|分|秒|毫秒|微秒]", "");
        fs = fs.replaceAll("\\\\-", "-");
        fs = fs.replaceAll("\\\\,", ",");
        fs = fs.replaceAll("\\\\.", ".");
        fs = fs.replaceAll("\\\\ ", " ");
        fs = fs.replaceAll(";@", "");
        fs = fs.replaceAll("^\\[\\$\\-.*?\\]", "");
        fs = fs.replaceAll("^\\[[a-zA-Z]+\\]", "");
        return (fs.matches("^[yYmMdDhHsS\\-/,. :]+[ampAMP/]*$"));
    }

    public static boolean isInternalDateFormat(int format)
    {
        switch (format) { case 14:
            case 15:
            case 16:
            case 17:
            case 18:
            case 19:
            case 20:
            case 21:
            case 22:
            case 45:
            case 46:
            case 47:
            case 57:
            case 58:
                return true;
            case 23:
            case 24:
            case 25:
            case 26:
            case 27:
            case 28:
            case 29:
            case 30:
            case 31:
            case 32:
            case 33:
            case 34:
            case 35:
            case 36:
            case 37:
            case 38:
            case 39:
            case 40:
            case 41:
            case 42:
            case 43:
            case 44: } return false;
    }

    public static boolean isValidExcelDate(double value)
    {
        return (value > -4.940656458412465E-324D);
    }
}

2. POI reconoce datos de tiempo cuyas celdas en Excel son de tipo de fecha o de tipo de hora

2.1 Tipo de celda

Antes de explicar el problema de los puntos de interés que identifican los datos de tiempo en la tabla de Excel, primero debemos entender que hay varias formas de definir las celdas de los datos de tiempo en la tabla de Excel.

No es mucha tontería, solo ve a la imagen:

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

inserte la descripción de la imagen aquí

Como se muestra en la figura, hay tres tipos de celdas que representan el tiempo en la tabla de Excel, que son tipo de fecha, tipo de hora y tipo personalizado.

2.2 Celda de tipo personalizado: procesamiento de tiempo

Entre los tres tipos de celdas anteriores, los datos de tiempo almacenados en celdas de tipo personalizado se pueden juzgar directamente por el valor de getDataFormat (). Los tipos de tiempo de uso común y sus valores de formato correspondientes son los siguientes:

tipo de tiempo valor de formato
aaaa-MM-dd 14
m mes d día aaaa 31
aaaa m mes 57
m mes d 58
HH:mm 20
h hora mm minuto 32

A continuación se muestra mi código para manejar varios tipos de tiempo comunes

//先获取对应的format值
short format = row.getCell(j).getCellStyle().getDataFormat();
SimpleDateFormat sdf = null;
//根据format值,将其转换成对应的时间样式
if (format == 20 || format == 32){
	sdf = new SimpleDateFormat("HH:mm");
}else if (format == 14 || format == 31 || format == 57 || format == 58){
	sdf = new SimpleDateFormat("yyyy-MM-dd");
}else {
	sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}

2.3 Celda tipo fecha u hora – juicio y procesamiento

analizar:

A diferencia de la hora de las celdas de tipo personalizado, los datos de hora de las celdas de tipo fecha y hora no pueden juzgarse por el valor del formato. Por lo tanto, en el código anterior, la hora de los tipos "yyyy-MM-dd" y "HH:mm" se convertirá directamente al formato "yyyy-MM-dd HH:mm:ss", que no es ni hermoso ni Cumple con nuestras necesidades por su formato.

Solución: (La siguiente solución es solo mi método de procesamiento personal, que puede no ser riguroso y es solo para referencia)
Pasos:

  1. Primero convierta los datos al formato "yyyy-MM-dd HH:mm:ss"
  2. Convierta la hora del tipo SimpleDateFormat a tipo String, elimine los tres símbolos de espacios, : y -, y guárdelo en una matriz de tipo String
  3. Juzgar el estilo de tiempo final que se mostrará a través de los datos de horas, minutos y segundos en progreso en la matriz, por ejemplo: cuando la hora se juzga como 0, la hora, el minuto y el segundo no se mostrarán; cuando el el segundo se considera 0, el año, el mes y el día no se mostrarán

Ir directamente al código:

//先获取对应的format值
short format = row.getCell(j).getCellStyle().getDataFormat();
SimpleDateFormat sdf = null;
//根据format值,将其转换成对应的时间样式
if (format == 20 || format == 32){
	sdf = new SimpleDateFormat("HH:mm");
}else if (format == 14 || format == 31 || format == 57 || format == 58){
	sdf = new SimpleDateFormat("yyyy-MM-dd");
}else {
    /**
    * 上面处理的时间,单元格格式都是自定义格式中时间格式,而下面解决的是单元格格式为日期格式的问题
    * 单元格格式为日期格式时,没办法通过format进行判断,所以进行如下操作:
    * 1、先将数据转换成 "yyyy-MM-dd HH:mm:ss"的格式
    * 2、将SimpleDateFormat类型的时间转换成String类型,并去除其中的空格、:和-三个符号,存进String类型数组中
    * 3、通过数组进行中时分秒的数据进行判断最终要展示的时间样式
    * 判断小时为0时,则不显示时分秒;判断秒钟为0时,则不显示年月日
    */
    sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    // split方法去除多个符号,使用 | 分隔符进行简单的配置
    // 转化为String类型数组后,我们数组中存储的数据依次为0-年、1-月、2-日、3-时、4-分、5-秒(数组下标-存放的数据)
    String[] str = sdf.format(DateUtil.getJavaDate(row.getCell(j).getNumericCellValue())).toString().split("-|:| ");
    if (Integer.parseInt(str[3]) == 0 && Integer.parseInt(str[4]) == 0 && Integer.parseInt(str[5]) == 0){
        //根据表格,当时分秒都为0时,说明此单元格存储的数据为“yyyy/MM/dd”,此处只显示年月日
        sdf = new SimpleDateFormat("yyyy-MM-dd");
	}else if (Integer.parseInt(str[3]) != 0 && Integer.parseInt(str[4]) != 0 && Integer.parseInt(str[5]) == 0){
        //根据表格,当小时和分钟不为0的情况,说明此单元格存储的数据为“HH:mm”,年月日是不需要的
        sdf = new SimpleDateFormat("HH:mm");
	}else{
		break;
	}
}

Todas las explicaciones se explican en el código. Los ejemplos en el código tienen un alcance limitado y son solo para referencia. Aún debe analizarlos en función de sus propios datos.

Código completo:

Por ultimo adjunto el codigo completo para identificar la tabla tipo xlsx

//  1.根据传入的文件路径获取工作簿
XSSFWorkbook xssfworkbook = new XSSFWorkbook(path);

//  2.根据脚标获取工作表,index从0开始
XSSFSheet sheet = xssfworkbook.getSheetAt(1);
int lastRowNum = sheet.getLastRowNum();
for (int i = 2;i <= lastRowNum; i++) {
    XSSFRow row = sheet.getRow(i);

    if (row != null){
        List<String> list =new ArrayList();
        for (int j = 0; j < 13;j++){
            if (row.getCell(j) != null || !row.getCell(j).toString().trim().equals("")) {
                String value = null;
                //判断获取到的数据是否为数字类型数据
                if (row.getCell(j).getCellType() == CellType.NUMERIC){
                    //是数字类型数据,进行类型转换
                    //获取日期类型
                    short format = row.getCell(j).getCellStyle().getDataFormat();
                    //此处运用了重写的isCellDateFormatted方法,在DateFormatUtil工具类中
                    if (DateFormatUtil.isCellDateFormatted(row.getCell(j))){
                        SimpleDateFormat sdf =null;
                        if (format == 20 || format == 32){
                        	sdf = new SimpleDateFormat("HH:mm");
                        }else if (format == 14 || format == 31 || format == 57 || format == 58){
                        	sdf = new SimpleDateFormat("yyyy-MM-dd");
                        }else {
                            /**
                            * 上面处理的时间,单元格格式都是自定义格式中时间格式,而下面解决的是单元格格式为日期格式的问题
                            * 单元格格式为日期格式时,没办法通过format进行判断,所以进行如下操作:
                            * 1、现将数据转换成 "yyyy-MM-dd HH:mm:ss"的格式
                            * 2、将SimpleDateFormat类型的时间转换成String类型,并去除其中的空格、:和-三个符号,存进String类型数组中
                            * 3、通过数组进行中时分秒的数据进行判断最终要展示的时间样式
                            * 判断小时为0时,则不显示时分秒;判断秒钟为0时,则不显示年月日
                            */
                            sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                            String[] str = sdf.format(DateUtil.getJavaDate(row.getCell(j).getNumericCellValue())).toString().split("-|:| ");
                        	if (Integer.parseInt(str[3]) == 0 && Integer.parseInt(str[4]) == 0 && Integer.parseInt(str[5]) == 0){
                        	//根据表格,当时分秒都为0时,说明此单元格为生产日期,此处只显示年月日
                        	sdf = new SimpleDateFormat("yyyy-MM-dd");
                            }else if (Integer.parseInt(str[3]) != 0 && Integer.parseInt(str[4]) != 0 && Integer.parseInt(str[5]) == 0){
                                //根据表格,当小时和分钟不为0的情况,说明此单元格为初凝和终凝,年月日是不需要的
                                sdf = new SimpleDateFormat("HH:mm");
                            }else{
                                break;
                        	}
                        }
                        double value1 = row.getCell(j).getNumericCellValue();
                        Date date = DateUtil.getJavaDate(value1);
                        value = sdf.format(date);
                    }else{
                   		value = String.valueOf(row.getCell(j));
                    }
                }else {
                	value = String.valueOf(row.getCell(j));
                }
                list.add(value);
            }
        }
        //使用for循环list中的数据存储到对应的bean对象中
    }
}
//最后根据自己方法体中需要返回的数据进行封装并返回即可

Supongo que te gusta

Origin blog.csdn.net/xiri_/article/details/112986449
Recomendado
Clasificación