Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix the rounding issue for numeric type formatting #650

Open
wants to merge 1 commit into
base: trunk
Choose a base branch
from

Conversation

YUFEIFUT
Copy link

@YUFEIFUT YUFEIFUT commented Jul 1, 2024

Resolve the current issue with the DecimalFormat class when the incoming obj is of type Double or Float. For example, if a Double type value of 1.005 is passed in, and the corresponding cell in Excel is of numeric type and set to keep two decimal places. Formatting the Double value 1.005 will be problematic; it will be formatted as 1.00, which is inconsistent with the behavior of Excel and does not perform rounding correctly

Resolve the current issue with the DecimalFormat class when the incoming obj is of type Double or Float. For example, if a Double type value of 1.005 is passed in, and the corresponding cell in Excel is of numeric type and set to keep two decimal places.  Formatting the Double value 1.005 will be problematic; it will be formatted as 1.00, which is inconsistent with the behavior of Excel and does not perform rounding correctly
@pjfanning
Copy link
Contributor

Can you provide test cases that prove there is an issue?

I added 648a2e5 and these tests seem fine.

@pjfanning
Copy link
Contributor

I disabled the float test because it is actually failing.

@YUFEIFUT I would still be interested in getting more background as to what is failing for you - a code sample would be ideal. A unit test, even better.

@YUFEIFUT
Copy link
Author

YUFEIFUT commented Jul 2, 2024

Here are my test Excel file and the corresponding Java test code that can reproduce the issue I mentioned:

test_decimal.xlsx

package org.example;

import org.apache.poi.hssf.usermodel.HSSFDataFormatter;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class ReadExcelFile {

    public static void main(String[] args) {
        try {
            // Create a File object pointing to the Excel file to be read
            File file = new File("E:\\MyFile\\OpenSource\\test_poi_deciaml\\test_poi_deciaml\\src\\test\\test_files\\test_decimal.xlsx");
            FileInputStream fis = new FileInputStream(file);

            // Select the corresponding Workbook object based on the file extension
            Workbook workbook = null;
            if (file.getName().endsWith(".xls")) {
                workbook = new HSSFWorkbook(fis);
            } else if (file.getName().endsWith(".xlsx")) {
                workbook = new XSSFWorkbook(fis);
            }

            // Get the first sheet
            assert workbook != null;
            Sheet sheet = workbook.getSheetAt(0);

            // Create an object for formatting cell content
            HSSFDataFormatter dataFormatter = new HSSFDataFormatter();

            // Iterate over each row
            for (Row row : sheet) {
                // Iterate over each column
                for (Cell cell : row) {
                    // Format the cell content using HSSFDataFormatter
                    String cellValue = dataFormatter.formatCellValue(cell);
                    System.out.print(cellValue + "\t");
                }
                System.out.println();
            }

            // Close the workbook and input stream
            workbook.close();
            fis.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

pic1

As shown in the image pic1.png, the original content of the cell at position A1 is 1.005. I have set the cell's format to numeric with two decimal places, so the value displayed in the Excel software is 1.01. I believe that the value obtained using HSSFDataFormatter to format the cell should also be 1.01, not 1.00, so I think this is incorrect. After my debugging, I found that the issue lies in the format method of the InternalDecimalFormatWithScale class within the DataFormatter class. It seems to have made a mistake when using DecimalFormat. Specifically, when it formats the incoming Double type value, it directly uses the method public DecimalFormat.format(Object number, StringBuffer toAppendTo, FieldPosition pos) with the original Double parameter. Since Double is an imprecise type, I tried replacing the original first parameter with new BigDecimal(obj.toString()). And then,it get 1.01 for A1 cell.

@pjfanning
Copy link
Contributor

I added 6e07ce5 based on your test case. But it passes without your code change.

@YUFEIFUT
Copy link
Author

YUFEIFUT commented Jul 2, 2024

Sorry, I haven't used the test cases in the test class you added to the source code. Since I haven't cloned the source code, I only discovered this formatting issue during actual use, which led me to debug and investigate further. Cloning the code and running it might take me some time. Could you try reproducing the issue using the test code I provided? I have tested it on both POI version 4.1.2 and 5.2.1, and the results are as follows:
QQ截图20240702195139

@pjfanning
Copy link
Contributor

I cannot reproduce the issue. I will not change the runtime code.

@pjfanning
Copy link
Contributor

POI 5.2.5 is released and POI 5.3.0 is being released right now.

@YUFEIFUT
Copy link
Author

YUFEIFUT commented Jul 2, 2024

ok

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants