Apache POI Customformat(#.##0,00) does not work - java

We are using the apache poi 4.1.2 in our project. I am using the Excel 2013. I'm trying to format the number with Apache poi but this Format(#.##0,00) is not working. My requirement is if the cDecimalSepString is DOT(.), the number should be in Format(#,##0.00). if the cDecimalSepString is Comma(,), the number format should be in Format(#.##0,00). Format(#,##0.00) works for me, but the Format(#.##0,00) is not working. My Excel default Decimal separator(.) and thousand separator is Comma(,). When the if the cDecimalSepString is Comma(,) If I generate the Excel with Format(#,##0.00) and Change my Excel Decimal separator(,) and thousand separator is Comma(.), then it works. so my question is we always need to use this Format(#.##0,00) when generate the Excel fie with Apache POI?
CellStyle numStyle = null;
if (cDecimalSepString != null && cDecimalSepString.equals("."))
{
numStyle = workbook.createCellStyle();
short format = (short)BuiltinFormats.getBuiltinFormat("#,##0.00");
numStyle.setDataFormat(format);
}
else
{
DataFormat dataFormat = workbook.createDataFormat();
numStyle = workbook.createCellStyle();
numStyle.setDataFormat(dataFormat.getFormat("#.##0,00"));
}
string value= "1000.43";
double dValue = Double.parseDouble(value);
Cell cell = workbook.createSheet().createRow(0).createCell(0);
cell.setCellValue(dValue);
cell.setCellStyle(numStyle);

solution will be always export the number in the Format(#,##0.00) and the generated Excel file will display the number as per the Excel default settings on the user Machine.

Related

Date cell mask doesn't come correctly

I'm reading an .xlsx file with Apache POI that has a cell with the following value: Jan/17.
But when I do check the cell variable with
String pattern = cell.getCellStyle().getDataFormatString()
pattern return wrong mask: mmm-yy and wrong value Jan-17.
I tried to use DataFormatter, but return the same error
I tried to use CellDateFormatter, but return the same error too
Replace the character "-" to "/" is not an option because it can be used "-" in file.
This is not an error but is how Microsoft Excel localizes the date formats. Excel files always store formats in en_US locale. That is mmm-yy for this format. It is the Excel built-in format with ID 17 (0x11, "mmm-yy"). See BuiltinFormats. It gets applied when user inputs only month and year in a cell. For example: 1/17, which is month 1 in year 17.
In my German Excel this looks like so using German Windows locale:
The Excel GUI then interprets that format different dependent on the Excel and/or Windows locale settings. For example, if I change the Windows locale settings to Portuguese (Brasil) in Control Panel - Time and Region:
then it looks like so:
Note, nothing has changed in Excel file. Only Windows locale settings have changed.
Unfortunately Apache POI DataFormatter fails to interpret locale settings exactly like Excel does.
Following code interprets the Excel built-in format with ID 17 (0x11, "mmm-yy") as mmm-yy = Jan-17 using en_US locale. This is correct. But it interprets it as mmm.-yy = Jan.-17 using de_DE locale. This is wrong, should be mmm yy = Jan 17 like in Excel. And using pt_BR locale it interprets it as mmm.-yy= jan.-17. This is wrong too, should be mmm/yy = jan/17 like in Excel.
import org.apache.poi.ss.usermodel.*;
import java.io.FileInputStream;
class ReadExcel {
public static void main(String[] args) throws Exception {
Workbook workbook = WorkbookFactory.create(new FileInputStream("./ExcelExampleIn.xlsx"));
// up to apache poi 5.1.0 a FormulaEvaluator is needed to evaluate the formulas while using DataFormatter
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
//DataFormatter dataFormatter = new DataFormatter(new java.util.Locale("en", "US"));
//DataFormatter dataFormatter = new DataFormatter(new java.util.Locale("de", "DE"));
DataFormatter dataFormatter = new DataFormatter(new java.util.Locale("pt", "BR"));
// from 5.2.0 on the DataFormatter can set to use cached values for formula cells
dataFormatter.setUseCachedValuesForFormulaCells(true);
Sheet sheet = workbook.getSheetAt(0);
for (Row row : sheet) {
for (Cell cell : row) {
String pattern = cell.getCellStyle().getDataFormatString();
System.out.println(pattern);
//String value = dataFormatter.formatCellValue(cell, evaluator); // up to apache poi 5.1.0
String value = dataFormatter.formatCellValue(cell); // from apache poi 5.2.0 on
System.out.println(value);
}
}
workbook.close();
}
}
To overcome this incorrectness in Apache POI, one could add a special data format for the mmm-yy to the DataFormatter dependent on used locale. This can be achieved using public void addFormat(java.lang.String excelFormatStr, java.text.Format format).
Complete example again:
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.util.LocaleUtil;
import java.io.FileInputStream;
class ReadExcel {
public static void main(String[] args) throws Exception {
Workbook workbook = WorkbookFactory.create(new FileInputStream("./ExcelExampleIn.xlsx"));
// up to apache poi 5.1.0 a FormulaEvaluator is needed to evaluate the formulas while using DataFormatter
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
//LocaleUtil.setUserLocale(new java.util.Locale("en", "US"));
//LocaleUtil.setUserLocale(new java.util.Locale("de", "DE"));
LocaleUtil.setUserLocale(new java.util.Locale("pt", "BR"));
DataFormatter dataFormatter = new DataFormatter(); // uses user locale set
// from 5.2.0 on the DataFormatter can set to use cached values for formula cells
dataFormatter.setUseCachedValuesForFormulaCells(true);
if (LocaleUtil.getUserLocale().equals(new java.util.Locale("de", "DE"))) {
dataFormatter.addFormat("mmm-yy", new java.text.SimpleDateFormat("MMM yy", new java.util.Locale("en", "US")));
} else if (LocaleUtil.getUserLocale().equals(new java.util.Locale("en", "US"))) {
dataFormatter.addFormat("mmm-yy", new java.text.SimpleDateFormat("MMM-yy", new java.util.Locale("en", "US")));
} else if (LocaleUtil.getUserLocale().equals(new java.util.Locale("pt", "BR"))) {
dataFormatter.addFormat("mmm-yy", new java.text.SimpleDateFormat("MMM/yy", new java.util.Locale("en", "US")));
}
Sheet sheet = workbook.getSheetAt(0);
for (Row row : sheet) {
for (Cell cell : row) {
String pattern = cell.getCellStyle().getDataFormatString();
System.out.println(pattern);
//String value = dataFormatter.formatCellValue(cell, evaluator); // up to apache poi 5.1.0
String value = dataFormatter.formatCellValue(cell); // from apache poi 5.2.0 on
System.out.println(value);
}
}
workbook.close();
}
}
Note, the java.text.SimpleDateFormat always gets created usig en_US locale. Else, month abbreviations may be followed by a dot. For example: Jan. 17 or Jan./17.

Apache-poi template leading zeros disappear on editing cells

I'm creating a .xlsx template using apache-poi, the user have to insert an id that has fixed length.
i've already tried the setDataFormat(workbook.createDataFormat().getFormat("#")) trick, but when the cell is edited it seems to forget that, and leading zeros disappear.
//this is the code snippet i found here on stackoverflow and tried out
DataFormat fmt = workbook.createDataFormat();
CellStyle textStyle = workbook.createCellStyle();
textStyle.setDataFormat(fmt.getFormat("#"));
worksheet.setDefaultColumnStyle(0, textStyle);
It would be great finding a true solution, because adding leading zeros to get the expected length can cause errors. Ex: user means 0000111 but forgets a 1 , new id will be 0000011 and unfortunately ids aren't sequential.
Thanks for your time, and forgive me for my bad english XD
Cannot reproduce your issue.
Following code creates a Excel sheet having Ids in column A which are not losing their text format and leading zeros even if edited in Excels GUI.
import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
class CreateExcelNumberFormatText {
public static void main(String[] args) throws Exception {
try (Workbook workbook = new XSSFWorkbook();
FileOutputStream fileout = new FileOutputStream("Excel.xlsx") ) {
DataFormat format = workbook.createDataFormat();
CellStyle textStyle = workbook.createCellStyle();
textStyle.setDataFormat(format.getFormat("#"));
Sheet sheet = workbook.createSheet();
sheet.setDefaultColumnStyle(0, textStyle);
Cell cell = sheet.createRow(0).createCell(0);
cell.setCellStyle(textStyle);
cell.setCellValue("Id");
cell = sheet.createRow(1).createCell(0);
cell.setCellStyle(textStyle);
cell.setCellValue("0000111");
cell = sheet.createRow(2).createCell(0);
cell.setCellStyle(textStyle);
cell.setCellValue("0001111");
workbook.write(fileout);
}
}
}
What you probably not expected is that apache poi does not applying the column style to new created cells in that column. This you needs doing in code else the cell style will be General. Setting the column style is nevertheless necessary since else Excels GUI will not use the text style while adding cell contents there.
My code is complete, tested and works for me. Simply editing the cells in Excel cannot lead to lost of parts of cell contents (the leading zeros) because of using the number format # = Text.
Of course, if someone changes the column number format from Text to General, then 0000111 will be the number 111 after editing. But this is cannot be prevented when the sheet is editable by the user.
Maybe one could set CellStyle.setQuotePrefixed additionally. As:
...
textStyle.setDataFormat(format.getFormat("#"));
textStyle.setQuotePrefixed(true);
...
Then all content will be prefixed with a quote prefix apostrophe ' additionally. But this too can be changed by a user editing the sheet.
This was the solution for me :
cell = row.createCell(col, CellType.STRING);
cell.setCellValue(val);

How to set a cell format to Text

I am using Apache-POI 3.14. I have a need to lock-down a cell to a "Text" format. The data in my cell might be all digits, but it is still considered a string. When I write the cell, I do it like this:
cell.setCellValue("001");
cell.setCellType(Cell.CELL_TYPE_STRING);
When I open the output workbook in Excel, the cell contains the correct value ("001") and it displays with a small green triangle in the corner. Hovering over the exclamation point displays the hover text The number in this cell is formatted as text or preceded by an apostrophe. When I look at the cell formatting (Right-click -> Format cells), the "Category" is displayed as "General". I expected this to be "Text".
The problem arises when a user modifies the value in the cell by entering only digits. Because the "Category" is "General", the value is entered and displayed as a number, removing leading zeroes and right-justified.
How can I achieve the same result as Excel's "Format cells" dialog?
You can try to set the cell-format to text via
DataFormat fmt = wb.createDataFormat();
CellStyle cellStyle = wb.createCellStyle();
cellStyle.setDataFormat(
fmt.getFormat("#"));
cell.setCellStyle(cellStyle);
Note: CellStyles shoudl be re-used for all applicable cells, do not create new ones for every cell.
You could also try to use the "Ignore errors" feature in the .xlsx format, however support for it is not fully done yet, see Issue 46136 and Issue 58641 for some ongoing discussion.
See also this MSDN page for some additional information
For HSSF,
DataFormat fmt = workbook.createDataFormat();
CellStyle textStyle = workbook.createCellStyle();
textStyle.setDataFormat(fmt.getFormat("#"));
sheet.setDefaultColumnStyle(0, textStyle);
It just sets the whole column style as Text and set category as Text .
However, if you are using XSSF format, it doesn't work(I am using Apache Poi 3.15 and didn't work for me).
In this case you have set style to each cell you want to treat as text in addition to above code using:
cell.setCellStyle(textStyle);
Regarding error, you could use
sheet.addIgnoredErrors(new CellRangeAddress(0,9999,0,9999),IgnoredErrorType.NUMBER_STORED_AS_TEXT );
It ignores the NUMBER_STORED_AS_TEXT error for row 0 till 9999 and column 0 till 9999 and you wont see it.
Look like OP was asking for Apache solution. After some searching I found this answer:
HSSFCellStyle style = book.createCellStyle();
style.setDataFormat(BuiltInFormats.getBuiltInFormat("text"));
In this case, I'm using Apache-POI 3.15, and I had the same problem, so I validated the data in my style, I need numbers >0 and strings:
try {
if (Integer.parseInt(field + "") >= 0) {
int valor = Integer.parseInt(field + "");
cell.setCellValue(valor); //Int
}
} catch (NumberFormatException nfe) {
// no int
try {
if (Double.parseDouble(field + "") >= 0) {
double valor = Double.parseDouble(field + ""); //double
cell.setCellValue(valor);
}
} catch (NumberFormatException nfe2) {
cell.setCellValue(field + ""); //String
}
}
For Apache POI 4.0.1 :
XSSFSheet sheet = workbook.createSheet("MySheetName");
sheet.addIgnoredErrors(new CellRangeAddress(0, 9999, 0, 9999), IgnoredErrorType.NUMBER_STORED_AS_TEXT);
Be careful to cast your sheet to org.apache.poi.xssf.usermodel.XSSFSheet and not to org.apache.poi.ss.usermodel.Sheet, otherwise the method addIgnoredErrors wil be unknown.

How to do Excel's "Convert to Number" in Java

I am reading data from Excel using Apache POI. I want to convert some cells to number while reading in Java as following:
Input 01.0234500
Output 1.02345
Input 412206362371
Output 4.12206E+11
Input 1234.201400002345
Output 1234.2014
When I am using "Convert to Number" in Excel, it works fine. But I want the same output while reading Excel cells in Java.
It can also be achieved using =VALUE() function in Excel. But how do I implement the same functionality in Java?
I think there are a number of ways to accomplish what you stipulate, but the most direct method is just to use the VALUE() function and then evaluate it. This certainly is not the most efficient method, but it works.
Essentially we just read in the value of the input cell, then create a new cell formula cell which contains the VALUE() function with the original value as the parameter. After that we call evalutateInCell to evaluate the VALUE() function and replace the cell value with the results.
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet sheet = wb.createSheet("test");
Row row = sheet.createRow(0);
Cell inCell = row.createCell(0);
inCell.setCellValue("01.0234500");
Cell outCell = row.createCell(1);
FormulaEvaluator fev = wb.getCreationHelper().createFormulaEvaluator();
String value = inCell.getStringCellValue();
outCell.setCellFormula("VALUE(" + value + ")");
fev.evaluateInCell(outCell);
You can use the same method to replace the contents of the original cell if that is your preference.
This worked for me
new BigDecimal(cell.getNumericCellValue()).toPlainString()

Calculating the value of a recursion formula in EXCEL using POI

I have an EXCEL Spreadsheet that has many computations some including recursive formula's (perfectly fine in excel which computes these with no problem).
I'm using version 3.8 of the Apache Poi API to open the existing spreadsheet, add updated values for the computations, save the spreadsheet and then read the results into my program.
All of this works except the in memory poi version of the spreadsheet does not perform the recursive calculation.
I'm calling the POI code to compute the entire workbook, each sheet and then each formula cell, but the cell formula never computes.
If I open the saved spreadsheet and compute it the formula computes the value accurately. I need to avoid having the user manually open the saved spreadsheet if possible.
Any insight in to this problem would be greatly appreciated.
Here is the code I have tried. It all runs with no error but does not compute the formula.
The formula is already in the spreadsheet an works fine so I'm trying to force the formula to re-compute.
I have tried all these variations. The code runs and executes but does not compute the formula
wb.getCreationHelper().createFormulaEvaluator().evaluateAll();
/*
//wb.getCreationHelper().createFormulaEvaluator().evaluateAll();
System.out.println(wb.getSheet("Rate Report").getRow(16).getCell(0).getStringCellValue());
System.out.println(wb.getSheet("Rate Report").getRow(16).getCell(1).getNumericCellValue());
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
//String wbsheets[] = {"Original","Main_DB","Parameters","Translator","Workers Comp.","Rate Report","Notes Fields"};
String wbsheets[] = {"Notes Fields","Translator","Parameters","Rate Report"};
for(String sheetName : wbsheets) {
Sheet sheet = wb.getSheet(sheetName);
System.out.println("processing sheet: " + sheet.getSheetName());
for(Row r : sheet) {
for(Cell c : r) {
if(c.getCellType() == Cell.CELL_TYPE_FORMULA) {
System.out.println("Recalcing: "+r.getRowNum()+c.getColumnIndex() + "in "+ sheet.getSheetName());
evaluator.evaluateFormulaCell(c);
}
}
}
}
XSSFFormulaEvaluator.evaluateAllFormulaCells((XSSFWorkbook) wb);

Categories