I need to detect, whether cell format is Date, Time or Datetime.
My code is:
if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
if (DateUtil.isCellDateFormatted(cell)) {
if ( ??? )
return "Time";
else if ( ??? )
return "Date";
else
return "Datetime";
}
}
I use ApachePOI 3.6
I don't see a built-in way to do this easily in POI. First, there doesn't seem to be a clear distinction between "Time", "Date", and "Datetime". The values are just stored as numbers and a format is applied to display it.
One thing you could do is get the style of the cell (HSSFCellStyle), then write your own method that reads either style.getDataFormatString() or style.getDataFormat() and tells you whether the format falls in the "Time", "Date", or "Datetime" category depending on how you define them. The second method returns an int so it might be easier to work with.
For example, the format highlighted below has a String data format of "[$-F400]h:mm:ss\ AM/PM" and an int value of 166.
I'm assuming this is what you mean by "Datetime" format, as it's one of Excel's built-in formats that displays both the date and the time.
The drawback of this approach is that I wouldn't expect it to work with cells that have custom date/time formats.
It seems to me that the only good thing we can do here is - to see if time part has value other than zero.
I have tried to use style.getDataFormatString() and style.getDataFormat() to detect this, but they behave very wrongly for my test cases. Here's my code :
private boolean dateIncludesTime() // this method only tries to detect does time part exist, but it is not sure it will succeeed
{
Date javaDate= (Date)getValue();
if (javaDate.getHours() > 0 || javaDate.getMinutes() > 0)
return true;
int formatID = apacheCell.getCellStyle().getDataFormat();
if(formatID >= 18 && formatID <=22) // https://poi.apache.org/apidocs/org/apache/poi/ss/usermodel/BuiltinFormats.html
return true;
dateFormat = apacheCell.getCellStyle().getDataFormatString();
if(dateFormat.toLowerCase().contains("h")) // format mentions hours
return true;
return false;
}
Here's what I get for some test cases :
input 03/21/2015 21:30 getDataFormatString() returns MM/DD/YY formatID = 165
input 03/21/2016 getDataFormatString() returns MM/DD/YY formatID = 165
input 2017-04-21 10:20 getDataFormatString() returns YYYY-MM-DD formatID = 166
input 2017-05-21 getDataFormatString() returns YYYY-MM-DD formatID = 166
Related
I am trying to obtain a date from 3 separate combo boxes that I then convert to ints and make a Date object. However, when I compare this date string to an already existing string, it doesnt match even though in the debugger it appears to be the same. I have setup a simple if statement to check what the problem is however I am not sure why it does not match.
int apptDay, apptMonth, apptYear;
apptDay = Integer.parseInt(consultationDay.getSelectedItem().toString());
apptMonth = Integer.parseInt(consultationMonth.getSelectedItem().toString());
apptYear = Integer.parseInt(consultationYear.getSelectedItem().toString());
consultationDate = new Date(apptDay, apptMonth, apptYear);
if (appointmentList.get(0).getDate() == consultationDate) {
sopl("Working");
}
I am quite sure that there is some issue with my code related to combo boxes as that is the only place where I face problems. The if statement is never satisfied so "Working" is never printed.
Any help would be appreciated.
You should use .equlas() instead of the == operator.
int apptDay = 5, apptMonth = 12, apptYear = 2000;
Date testDate = new Date(apptDay, apptMonth, apptYear);
Date consultationDate = new Date(apptDay, apptMonth, apptYear);
if (testDate == consultationDate) {
System.out.println("Success for ==");
} else if (testDate.equals(consultationDate)) {
System.out.println("Success for equals");
}
I'm currently developing some functionality that needs to either subtract or add time to a Calendar class instance. The time I need to add/sub is in a properties file and could be any of these formats:
30,sec
90,sec
1.5,min
2,day
2.333,day
Let's assume addition for simplicity. I would read those values in a String array:
String[] propertyValues = "30,sec".split(",");
I would read the second value in that comma-separated pair, and map that to the relevant int in the Calendar class (so for example, "sec" becomes Calendar.SECOND, "min" becomes Calendar.MINUTE):
int calendarMajorModifier = mapToCalendarClassIntValues(propertyValues[1]);
To then do the actual operation I would do it as simple as:
cal.add(calendarMajorModifier, Integer.parseInt(propertyValues[0]));
This works and it's not overly complicated. The issue is now floating values (so 2.333,day for eaxmple) - how would you deal with it?
String[] propertyValues = "2.333,day".split(",");
As you can imagine the code becomes quite hairy (I haven't actually written it yet, so please ignore syntax mistakes)
float timeComponent = Float.parseFloat(propertyValues[0]);
if (calendarMajorModifier == Calendar.DATE) {
int dayValue = Integer.parseFloat(timeComponent);
cal.add(calendarMajorModifier, dayValue);
timeComponent = (timeComponent - dayValue) * 24; //Need to convert a fraction of a day to hours
if (timeComponent != 0) {
calendarMajorModifier = Calendar.HOUR;
}
}
if (calendarMajorModifier == Calendar.HOUR) {
int hourValue = Integer.parseFloat(timeComponent);
cal.add(calendarMajorModifier, hourValue);
timeComponent = (timeComponent - hourValue) * 60; //Need to convert a fraction of an hour to minutes
if (timeComponent != 0) {
calendarMajorModifier = Calendar.MINUTE;
}
}
... etc
Granted, I can see how there may be a refactoring opportunity, but still seems like a very brute-forceish solution.
I am using the Calendar class to do the operations on but could technically be any class. As long as I can convert between them (i.e. by getting the long value and using that), as the function needs to return a Calendar class. Ideally the class also has to be Java native to avoid third party licensing issues :).
Side note: I suggested changing the format to something like yy:MM:ww:dd:hh:mm:ss to avoid floating values but that didn't pan out. I also suggested something like 2,day,5,hour, but again, ideally needs to be format above.
I'd transform the value into the smallest unit and add that:
float timeComponent = Float.parseFloat(propertyValues[0]);
int unitFactor = mapUnitToFactor(propertyValues[1]);
cal.add(Calendar.SECOND, (int)(timeComponent * unitFactor));
and mapUnitToFactor would be something like:
int mapUnitToFactor(String unit)
{
if ("sec".equals(unit))
return 1;
if ("min".equals(unit))
return 60;
if ("hour".equals(unit))
return 3600;
if ("day".equals(unit))
return 24*3600;
throw new InvalidParameterException("Unknown unit: " + unit);
}
So for example 2.333 days would be turned into 201571 seconds.
I have built a method which takes two datasets: dataset1 and retirementSimpleData.
It matches the two datasets based on a primary key/number, defined as cnum, in the code below.
I wanted to return the value of the difference between the getAssets value and the getSums value, and this is working, except for one little problem.
Some of the cnums that exist in dataset1 don't exist in retirementSimpleData. Similarly, some cnums which may exist in retirementSimpleData may not exist in
dataset1. This is resulting in no data being returned for that cnum.
I would like to implement two passes at the end which check in one direction to see if I missed anything. The second pass would check in the opposite direction.
However, not sure how I would go about implementing this.
public void getReportData(int index) {
String date1 = Util.dateTimeToShortString(reportDate);
String date2 = reportDao.getPreviousRetirementDate(date1);
List<SurveyCompareAssetsCheckData> dataset1 = reportDao.getSurveyCheckCompareAssetsData(date1);
List<RetSurveyAssets> retirementSimpleData = reportDao.findRetSurveyByDate(date1);
for (SurveyCompareAssetsCheckData surveyCompareAssetsCheckData : dataset1) {
for (RetSurveyAssets surveyCompareAssetsCheckData2 : retirementSimpleData) {
if (surveyCompareAssetsCheckData.getCnum() == surveyCompareAssetsCheckData2.getCnum()) {
surveyCompareAssetsCheckData.setRetirementsimple(surveyCompareAssetsCheckData2.getSums());
surveyCompareAssetsCheckData.setDifference(surveyCompareAssetsCheckData.getAssets() - surveyCompareAssetsCheckData2.getSums());
Caveat: dataset1 and retirementSimpledata both use existing SQL pulls which I am not allowed to touch, otherwise I would have simply defined new SQL for these methods in my "DAOImpl." Therefore, I have to work with the data I am getting, and programmatically check for this.
Below, is the report which is being generated with my code. As you can see, I am ending up with zeros, which is showing the difference (incorrectly) as zeros, because Cnum #45, in this example simply doesn't exist in the second dataset (retirementSimpleData)
What is the datatype of Cnum, if it is int then default value is Zero.
You have to add else-if condition to check for example:
else if (surveyCompareAssetsCheckData2.getCnum()== 0){
-------- logic here --------------------
}
else if (surveyCompareAssetsCheckData.getCnum() ==0){
----------logic here -----------
}
I am a begginer at jess rules so i can't understand how i could use it. I had read a lot of tutorials but i am confused.
So i have this code :
Date choosendate = "2013-05-05";
Date date1 = "2013-05-10";
Date date2 = "2013-05-25";
Date date3 = "2013-05-05";
int var = 0;
if (choosendate.compareTo(date1)==0)
{
var = 1;
}
else if (choosendate.compareTo(date2)==0)
{
var = 2;
}
else if (choosendate.compareTo(date3)==0)
{
var = 3;
}
How i could do it with jess rules?
I would like to make a jess rules who takes the dates , compare them and give me back in java the variable var. Could you make me a simple example to understand it?
This problem isn't a good fit for Jess as written (the Java code is short and efficient as-is) but I can show you a solution that could be adapted to other more complex situations. First, you would need to define a template to hold Date, int pairs:
(deftemplate pair (slot date) (slot score))
Then you could create some facts using the template. These are somewhat equivalent to your date1, date2, etc, except they associate each date with the corresponding var value:
(import java.util.Date)
(assert (pair (date (new Date 113 4 10)) (score 1)))
(assert (pair (date (new Date 113 4 25)) (score 2)))
(assert (pair (date (new Date 113 4 5)) (score 3)))
We can define a global variable to hold the final, computed score (makes it easier to get from Java.) This is the equivalent of your var variable:
(defglobal ?*var* = 0)
Assuming that the "chosen date" is going to be in an ordered fact chosendate, we could write a rule like the following. It replaces your chain of if statements, and will compare your chosen date to all the dates in working memory until it finds a match, then stop:
(defrule score-date
(chosendate ?d)
(pair (date ?d) (score ?s))
=>
(bind ?*var* ?s)
(halt))
OK, now, all the code above goes in a file called dates.clp. The following Java code will make use of it (the call to Rete.watchAll() is included so you can see some interesting trace output; you'd leave that out in a real program):
import jess.*;
// ...
// Get Jess ready
Rete engine = new Rete();
engine.batch("dates.clp");
engine.watchAll();
// Plug in the "chosen date"
Date chosenDate = new Date(113, 4, 5);
Fact fact = new Fact("chosendate", engine);
fact.setSlotValue("__data", new Value(new ValueVector().add(chosenDate), RU.LIST));
engine.assertFact(fact);
// Run the rule and report the result
int count = engine.run();
if (count > 0) {
int score = engine.getGlobalContext().getVariable("*var*").intValue(null);
System.out.println("Score = " + score);
} else {
System.out.println("No matching date found.");
}
As I said, this isn't a great fit, because the resulting code is larger and more complex than your original. Where using a rule engine makes sense is if you've got multiple rules that interact; such a Jess program has no more overhead than this, and so fairly quickly starts to look like a simplification compared to equivalent Java code. Good luck with Jess!
I am trying to read cell values excel sheet using Apache POI. One of my sheet contains percentage type as the cell type. When I read that cell using POI using cell.getNumbericValue(), its returning me the double value. If cell contains 11.24%, it is returning me 0.1124.
My problem is, I want to read the % symbol also from the cell i.e., I want to read the exact data as it is in cell as 11.24%. So, I tried it using the cell.toString(), even then it is returning me the same value as above.
Can anyone please suggest me, how to get rid of this problem.
Thanks in advance
Nandu
You can detect if a cell is formatted as a percentage by testing the cell data format string like this:
if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
if (cell.getCellStyle().getDataFormatString().contains("%")) {
// Detect Percent Values
Double value = cell.getNumericCellValue() * 100;
System.out.println("Percent value found = " + value.toString() +"%");
} else {
Double value = cell.getNumericCellValue();
System.out.println("Non percent value found = " + value.toString());
}
}
This should enable you to distinguish between percentage formatted values and ordinary numeric values.
11.24% is 0.1124, which is why that's what gets stored in the file, and that's what you get when you ask for the numeric value
POI provides a utility for formatting numeric strings based on the format rules applied to the cell, which is DataFormatter. If you use that to format the cell, you'll get back a string with the contents of the cell largely as seen in Excel.
Try this:
String typeCell =cell.getCellStyle().getDataFormatString();
It gives:
"General" value for non formated cells,
"0%" for percentage formats
dd/mm/yy for date , depends of locale
I manage to parse all types in cells (Numbers, Percentage, Date, Text, Currency) I just have to check what value for which cell type it will give me back.
Because I also have to much trouble with HSSFCell.CELL_TYPE_STRING or HSSFCell.CELL_TYPE_NUMERIC.
The answer of #WeeShetland should be the accepted answer.
Instead of cell.getCellStyle().getDataFormatString().contains("%") you can use
// class level
private static final int PERCENTAGE_FORMAT = BuiltinFormats.getBuiltinFormat("0%");
...
// in some method
if (cell.getCellStyle().getDataFormat() == PERCENTAGE_FORMAT) {
...