Java Apache POI Excel Numeric Cell value with Locale pt-BR - java

I want to set the XSSFCell in Excel to display the CellType as numeric, and need it to diplay the value as pt-BR Locale (with . for separator instead of , (not decimal/fractional - but still double). I managed to diplay the correct cell value, but the CellTyle only gets String. I know that double have the US configuration 0.000,00, and a simple NumberFormat with Locale do the trick, but the CellType gets to text, not number.
The number already comes configured with Locale, which comes straight from Database. (Eg: 412.000), but double converts it to US (412,000).
So, how can I format the cell to my Locale and still set the CellType as Numeric ?
This is what I got so far:
XSSFCell cell = row.createCell(anyCellNumber);
double value = 412.000; //valueThatComesFromDataBaseWithLocaleFormatted
cell.setCellType(CellType.NUMERIC);
//At this point, double has already converted the cell value to 412,000 - So, What I did was:
cell.setCellValue(String.format("%.3f", value).replace(",", ".")); // Replaced the , to . to match Locale
So, this is the point, the CellType is set, but NumberFormat, DecimalFormat, Locale, String.format, etc, gets the cellvalue to String, and thus the CellType is text.
Can´t use Double.parseDouble(valueFormatted.toString()) because it throws Exception, if the String is Locale formatted.
So, how (if it is possible), can I have a CellType.NUMERIC AND the cell value formatted for my Locale (pt-BR)???
Thanks in advance!

As far as I understand you specifically want your Cell to be of type numeric and your display to be something "not Date" ? The only approach that I clould think of would be to define your own cellStyle. This is possible in excel with custom functions. In apache-poi it could be possible when tinkering around with cell Styles:
...
Cell cell = row.createCell(cellIndex);
CellStyle cellStyle = workbook.createCellStyle();
CreationHelper createHelper = workbook.getCreationHelper();
createHelper.createDataFormat("some specific custom data format").
cell.setCellStyle(cellStyle);
I am however not sure that there is a way. I am not sure but these cellStyles seem to be limited to the default excel styles https://www.roseindia.net/java/poi/setdataformat.shtml
The simplest approach would be to make your cell of Type "Date". Even if your result from the Database is a number, it can be converted to Date, since Date is only a layer upon a timestamp. I would highly suggest to look at this approch instead of "hacking" your way around number fromats looking similar to Dates.

Related

Cannot get boolean value from excel cell

I am getting an error when trying to access a boolean value from an Excel file.
final Cell enabledCell = row.getCell(6);
enabledCell.getBooleanCellValue() // this throws an exception
java.lang.IllegalStateException: Cannot get a BOOLEAN value from a STRING cell
In the Excel file, I have just written "TRUE" and "FALSE" as values in the 6th column, but somehow they are perceived as strings and not booleans.
Boolean values in localized Excel applications also are localized. For example in my German Excel boolean values are WAHR and FALSCH. If I put TRUE or FALSE into cells using my German Excel GUI, then this are not boolean values but text strings.
So there is always the need to check CellType before getting the cell value. Or to use DataFormatter to always get string values independent of cell type.
Both is shown in Busy Developers' Guide to HSSF and XSSF Features->Getting the cell contents.
Moreover you might get the wrong cell. In Row.getCell the int cellnum is 0-based. Column A is cellnum 0. So cellnum 6 is column G, which is the 7th column and not the 6th. But that's secondary. Primary is the need to check CellType before getting the cell value or to use DataFormatter.

Change cell format (Length?) in Java Poi (Excel)

I have been searching for a way to do this but only found a few methods to resize columns, and wasn´t enough.
It´s simple:
When I´m writting into an excel file, I get to a point where numbers get higher than 10.000.000, and the format changes, example:
row 11: 9.800.000
row 12: 9.900.000
row 13: 1.0E7
row 14: 1.01E7
How can I prevent this from happening? I need the whole number, as I later access this information again from my code.
(I can´t edit excel manually, as I create it dinamically, I guess (and hope) there is a variable in some Java POI class that I can assign a value for this to change?)
Thank you all.
It's a cell formatting case, by default Excel use exponential format for numbers below a certain value, for the 2013 version it's below 1E10. And for older versions I guess it's arround 1E7.
To solve this you need to format the cell in your Java code before creating the xls file, using HSSFCellStyle, check the following code:
HSSFCellStyle style = workbook.createCellStyle();
style.setDataFormat(workbook.createDataFormat().getFormat("#"));
Double d = 10000000000.0;
thecell.setCellValue(d);
thecell.setCellType(Cell.CELL_TYPE_NUMERIC);
thecell.setCellStyle(style);
You may also need to re-size the column the fit the number by adding
sheet.autoSizeColumn(0);
Here's an output exemple with the cell formatting (A1) and without it (B1):
Dont forget to import the necessary classes.
The easiest way would probably be to just convert the value when you extract it from the excel file.
BigDecimal bigNumber = new BigDecimal(cell.getNumericCellValue());
//Use bigNumber when doing the calculations
According to your example, you have to set DataFormat as "#.000":
DataFormat format = workbook.createDataFormat();
CellStyle cellStyle = workbook.createCellStyle();
cellStyle.setDataFormat(format.getFormat("#.000"));
cell.setCellStyle(cellStyle);
Where:
0 - Digit placeholder. For example, if you type 8.9 and you want it to display as 8.90, then use the format #.00
# - Digit placeholder. Follows the same rules as the 0 symbol except Excel does not display extra zeros when the number you type has fewer digits on either side of the decimal than there are # symbols in the format. For example, if the custom format is #.## and you type 8.9 in the cell, the number 8.9 is displayed.
More excel formats: How to control and understand settings in the Format Cells dialog box in Excel

Apache POI - Generated Date Not Sortable Accordingly

Using Apache POI API, I have been able to generate correctly integers and floats on Excel. I can verify they are correct especially when I use the Sort function.
I simply cast values to their respective type, and the API takes care of the rest.
However, this technique didn't work with dates (I convert them to java.util.Date), they are correctly formatted, but the sorting is not accurate.
Any suggestions?
I tried two alternatives:
The first one: cell.setCellValue(new Date(value));
The second one: cell.setCellValue(new SimpleDateFormat("dd/MM/yyyy").format(new Date(value)));
Taking your code in reverse order:
cell.setCellValue(new SimpleDateFormat("dd/MM/yyyy").format(new Date(value)));
Don't do this. It converts the date to a string, much as if in Excel you went into a cell and typed '01/01/2010 - with the ' on the front forcing to a string
cell.setCellValue(new Date(value));
This is nearly there. You need to follow the POI instructions on creating a date cell, and also format the cell to be a Date Cell in your desired date format
eg for dd/mm/yyyy, once near the top of your file do this:
CreationHelper createHelper = wb.getCreationHelper();
CellStyle dateCellStyle = wb.createCellStyle();
dateCellStyle.setDataFormat(
createHelper.createDataFormat().getFormat("dd/MM/yyyy"));
Then for your cell set + style it with
cell.setCellValue(new Date(value));
cell.setCellStyle(dateCellStyle);

apache poi get default column type

I'm using POI to create a new row of cells in an existing spreadsheet. POI allows you to get the column default style, but there's no equivalent (as near as I can tell) to getting a default type. I'm getting a String from my user interface and I don't know how to set the cell type. If the string is a double, then fine, it's NUMERIC. But if the String specifies a date, how would I best detect it so that it is also set to NUMERIC? There are some many formatting types for a date that it is impractical to detect the type from the cell style format. Does POI support a way to parse based on a format?
To set the cell type you use:
setCellType()
as outlined in the docs:
https://poi.apache.org/apidocs/
setCellType void setCellType(int cellType) Set the cells type (numeric, formula or string). If the cell currently contains a value,
the value will be converted to match the new type, if possible.
Formatting is generally lost in the process however.
If what you want to do is get a String value for your numeric cell,
stop!. This is not the way to do it. Instead, for fetching the string
value of a numeric or boolean or date cell, use DataFormatter instead.
Throws: java.lang.IllegalArgumentException - if the specified cell
type is invalid java.lang.IllegalStateException - if the current value
cannot be converted to the new type See Also: CELL_TYPE_NUMERIC,
CELL_TYPE_STRING, CELL_TYPE_FORMULA, CELL_TYPE_BLANK,
CELL_TYPE_BOOLEAN, CELL_TYPE_ERROR

Reading string value from Excel with HSSF but it's double

I'm using HSSF-POI for reading excel data. The problem is I have values in a cell that look like a number but really are strings. If I look at the format cell in Excel, it says the type is "text". Still the HSSF Cell thinks it's numeric. How can I get the value as a string?
If I try to use cell.getRichStringValue, I get exception; if cell.toString, it's not the exact same value as in Excel sheet.
Edit: until this gets resolved, I'll use
new BigDecimal(cell.getNumericCellValue()).toString()
The class you're looking for in POI is DataFormatter
When Excel writes the file, some cells are stored as literal Strings, while others are stored as numbers. For the latter, a floating point value representing the cell is stored in the file, so when you ask POI for the value of the cell that's what it actually has.
Sometimes though, especially when doing Text Extraction (but not always), you want to make the cell value look like it does in Excel. It isn't always possible to get that exactly in a String (non full space padding for example), but the DataFormatter class will get you close.
If you're after a String of the cell, looking much as you had it looking in Excel, just do:
// Create a formatter, do this once
DataFormatter formatter = new DataFormatter(Locale.US);
.....
for(Cell cell : row) {
CellReference ref = new CellReference(cell);
// eg "The value of B12 is 12.4%"
System.out.println("The value of " + ref.formatAsString() + " is " + formatter.formatCellValue(cell));
}
The formatter will return String cells as-is, and for Numeric cells will apply the formatting rules on the style to the number of the cell
If the documents you are parsing are always in a specific layout, you can change the cell type to "string" on the fly and then retrieve the value. For example, if column 2 should always be string data, set its cell type to string and then read it with the string-type get methods.
cell.setCellType(Cell.CELL_TYPE_STRING);
In my testing, changing the cell type did not modify the contents of the cell, but did allow it to be retrieved with either of the following approaches:
cell.getStringCellValue();
cell.getRichStringCellValue().getString();
Without an example of a value that is not converting properly, it is difficult to know if this will behave any differently than the cell.toString() approach you described in the description.
You mean HSSF-POI says
cell.getCellType() == Cell.CELL_TYPE_NUMERIC
NOT
Cell.CELL_TYPE_STRING as it should be?
I would think it's a bug in POI, but every cell contains a Variant, and Variant has a type. It's kind of hard to make a bug there, so instead I think Excel uses some extra data or heuristic to report the field as text. Usual MS way, alas.
P.S. You cannot use any getString() on a Variant containing numeric, as the binary representation of the Variant data depends on it's type, and trying to get a string from what is actually a number would result in garbage -- hence the exception.
This below code works fine to read any celltype but that cell should contain numeric value
new BigDecimal(cell.getNumericCellValue()));
e.g.
ase.setGss(new BigDecimal(hssfRow.getCell(3).getNumericCellValue()));
where variable gss is of BigDecimal type.
Excel will convert anything that looks like a number or date or time from a string. See MS Knowledge base article, which basically suggests to enter the number with an extra character that makes it a string.
You are probably dealing with an Excel problem. When you create the spreadsheet, the default cell type is Generic. With this type, Excel guesses the type based on the input and this type is saved with each cell.
When you later change the cell format to Text, you are just changing the default. Excel doesn't change every cell's type automatically. I haven't found a way to do this automatically.
To confirm this, you can go to Excel and retype one of the numbers and see if it's text in HSSF.
You can also look at the real cell type by using this function,
#Cell("type", A1)
A1 is the cell for the number. It shows "l" for text, "v" for numbers.
The problem with Excel is that the default format is generic. With this format Excel stores numbers entered in the cell as numeric. You have to change the format to text before entering the values. Reentering the values after changing the format will also work.
That will lead to little green triangles in the left upper corner of the cells if the content looks like a number to Excel. If this is the case the value is really stored as text.
With new BigDecimal(cell.getNumericCellValue()).toString() you will still have a lot of problems. For example if you have identifying numbers (e.g. part numbers or classification numbers) you probably have cases that have leading zeros which will be a problem with the getNumericCellValue() approach.
I try to thoroughly explain how to correctly create the Excel to the party creating the files I have to handle with POI. If the files are uploaded by end users I even have created a validation program to check for expected cell types if I know the columns in advance. As a by-product you can also check various other things of the supplied files (e.g. are the right columns provided or mandatory values).
"The problem is I have values in a cell that look like a number" => look like number when viewed in Excel?
"but really are strings" => what does that mean? How do you KNOW that they really are strings?
"If I look at the format cell" => what's "the format cell"???
'... in Excel, it says the type is "text"' => Please explain.
"Still the HSSF Cell thinks it's numeric." => do you mean that the_cell.getCellType() returns Cell.CELL_TYPE_NUMERIC?
"How can I get the value as a string?" => if it's NUMERIC, get the numeric value using the_cell.getNumericCellValue(), then format it as a string any way you want to.
"If I try to use cell.getRichStringValue, I get exception;" => so it's not a string.
"if cell.toString, it's not the exact same value as in Excel sheet." => so cell.toString() doesn't format it the way that Excel formats it.
Whatever heuristic Excel uses to determine type is irrelevant to you. It's the RESULT of that decision as stored in the file and revealed by getCellType() that matters.

Categories