Fix inspired by bug #48494 - detect and support time formats like HH:MM;HH:MM

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@950665 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2010-06-02 17:17:42 +00:00
parent 53f8d4561f
commit 5cd9ac0ccf
4 changed files with 67 additions and 17 deletions

View File

@ -34,6 +34,7 @@
<changes> <changes>
<release version="3.7-SNAPSHOT" date="2010-??-??"> <release version="3.7-SNAPSHOT" date="2010-??-??">
<action dev="POI-DEVELOPERS" type="fix">48494 - detect and support time formats like HH:MM;HH:MM</action>
<action dev="POI-DEVELOPERS" type="fix">48494 - have ExcelExtractor make use of HSSFDataFormatter, so that numbers and dates come out closer to how Excel would render them</action> <action dev="POI-DEVELOPERS" type="fix">48494 - have ExcelExtractor make use of HSSFDataFormatter, so that numbers and dates come out closer to how Excel would render them</action>
<action dev="POI-DEVELOPERS" type="fix">48494 - have EventBasedExcelExtractor make use of HSSFDataFormatter, so that numbers and dates come out closer to how Excel would render them</action> <action dev="POI-DEVELOPERS" type="fix">48494 - have EventBasedExcelExtractor make use of HSSFDataFormatter, so that numbers and dates come out closer to how Excel would render them</action>
<action dev="POI-DEVELOPERS" type="fix">49096 - add clone support to Chart begin and end records, to allow cloning of more Chart containing sheets</action> <action dev="POI-DEVELOPERS" type="fix">49096 - add clone support to Chart begin and end records, to allow cloning of more Chart containing sheets</action>

View File

@ -297,7 +297,7 @@ public class DataFormatter {
} }
// Convert excel date format to SimpleDateFormat. // Convert excel date format to SimpleDateFormat.
// Excel uses lower case 'm' for both minutes and months. // Excel uses lower and upper case 'm' for both minutes and months.
// From Excel help: // From Excel help:
/* /*
The "m" or "mm" code must appear immediately after the "h" or"hh" The "m" or "mm" code must appear immediately after the "h" or"hh"
@ -319,7 +319,7 @@ public class DataFormatter {
sb.append('H'); sb.append('H');
} }
} }
else if (c == 'm') { else if (c == 'm' || c == 'M') {
if(mIsMonth) { if(mIsMonth) {
sb.append('M'); sb.append('M');
ms.add( ms.add(

View File

@ -258,13 +258,19 @@ public class DateUtil {
sb.append(c); sb.append(c);
} }
fs = sb.toString(); fs = sb.toString();
// If it starts with [$-...], then could be a date, but // If it starts with [$-...], then could be a date, but
// who knows what that starting bit is all about // who knows what that starting bit is all about
fs = date_ptrn1.matcher(fs).replaceAll(""); fs = date_ptrn1.matcher(fs).replaceAll("");
// If it starts with something like [Black] or [Yellow], // If it starts with something like [Black] or [Yellow],
// then it could be a date // then it could be a date
fs = date_ptrn2.matcher(fs).replaceAll(""); fs = date_ptrn2.matcher(fs).replaceAll("");
// You're allowed something like dd/mm/yy;[red]dd/mm/yy
// which would place dates before 1900/1904 in red
// For now, only consider the first one
if(fs.indexOf(';') > 0 && fs.indexOf(';') < fs.length()-1) {
fs = fs.substring(0, fs.indexOf(';'));
}
// Otherwise, check it's only made up, in any case, of: // Otherwise, check it's only made up, in any case, of:
// y m d h s - \ / , . : // y m d h s - \ / , . :

View File

@ -28,6 +28,7 @@ import java.util.Locale;
import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DateUtil;
import junit.framework.TestCase; import junit.framework.TestCase;
@ -56,9 +57,11 @@ public final class TestHSSFDataFormatter extends TestCase {
// date value for July 8 1901 1:19 PM // date value for July 8 1901 1:19 PM
double dateNum = 555.555; double dateNum = 555.555;
// date value for July 8 1901 11:23 AM
double timeNum = 555.47431;
//valid date formats -- all should have "Jul" in output //valid date formats -- all should have "Jul" in output
String[] goodDatePatterns ={ String[] goodDatePatterns = {
"[$-F800]dddd\\,\\ mmmm\\ dd\\,\\ yyyy", "[$-F800]dddd\\,\\ mmmm\\ dd\\,\\ yyyy",
"mmm/d/yy\\ h:mm PM;@", "mmm/d/yy\\ h:mm PM;@",
"mmmm/d/yy\\ h:mm;@", "mmmm/d/yy\\ h:mm;@",
@ -78,6 +81,18 @@ public final class TestHSSFDataFormatter extends TestCase {
"mmmm/d/yyyy;@", "mmmm/d/yyyy;@",
"[$-409]d\\-mmm\\-yyyy;@" "[$-409]d\\-mmm\\-yyyy;@"
}; };
//valid time formats - all should have 11:23 in output
String[] goodTimePatterns = {
"HH:MM",
"HH:MM:SS",
"HH:MM;HH:MM;HH:MM",
// This is fun - blue if positive time,
// red if negative time or green for zero!
"[BLUE]HH:MM;[RED]HH:MM;[GREEN]HH:MM",
"yyyy-mm-dd hh:mm",
"yyyy-mm-dd hh:mm:ss",
};
// valid number formats // valid number formats
String[] goodNumPatterns = { String[] goodNumPatterns = {
@ -111,6 +126,16 @@ public final class TestHSSFDataFormatter extends TestCase {
cell.setCellStyle(cellStyle); cell.setCellStyle(cellStyle);
} }
row = sheet.createRow(1); row = sheet.createRow(1);
// create cells with time patterns
for (int i = 0; i < goodTimePatterns.length; i++) {
HSSFCell cell = row.createCell(i);
cell.setCellValue(timeNum);
HSSFCellStyle cellStyle = wb.createCellStyle();
cellStyle.setDataFormat(format.getFormat(goodTimePatterns[i]));
cell.setCellStyle(cellStyle);
}
row = sheet.createRow(2);
// create cells with num patterns // create cells with num patterns
for (int i = 0; i < goodNumPatterns.length; i++) { for (int i = 0; i < goodNumPatterns.length; i++) {
@ -120,7 +145,7 @@ public final class TestHSSFDataFormatter extends TestCase {
cellStyle.setDataFormat(format.getFormat(goodNumPatterns[i])); cellStyle.setDataFormat(format.getFormat(goodNumPatterns[i]));
cell.setCellStyle(cellStyle); cell.setCellStyle(cellStyle);
} }
row = sheet.createRow(2); row = sheet.createRow(3);
// create cells with bad num patterns // create cells with bad num patterns
for (int i = 0; i < badNumPatterns.length; i++) { for (int i = 0; i < badNumPatterns.length; i++) {
@ -134,7 +159,7 @@ public final class TestHSSFDataFormatter extends TestCase {
// Built in formats // Built in formats
{ // Zip + 4 format { // Zip + 4 format
row = sheet.createRow(3); row = sheet.createRow(4);
HSSFCell cell = row.createCell(0); HSSFCell cell = row.createCell(0);
cell.setCellValue(123456789); cell.setCellValue(123456789);
HSSFCellStyle cellStyle = wb.createCellStyle(); HSSFCellStyle cellStyle = wb.createCellStyle();
@ -143,7 +168,7 @@ public final class TestHSSFDataFormatter extends TestCase {
} }
{ // Phone number format { // Phone number format
row = sheet.createRow(4); row = sheet.createRow(5);
HSSFCell cell = row.createCell(0); HSSFCell cell = row.createCell(0);
cell.setCellValue(5551234567D); cell.setCellValue(5551234567D);
HSSFCellStyle cellStyle = wb.createCellStyle(); HSSFCellStyle cellStyle = wb.createCellStyle();
@ -152,7 +177,7 @@ public final class TestHSSFDataFormatter extends TestCase {
} }
{ // SSN format { // SSN format
row = sheet.createRow(5); row = sheet.createRow(6);
HSSFCell cell = row.createCell(0); HSSFCell cell = row.createCell(0);
cell.setCellValue(444551234); cell.setCellValue(444551234);
HSSFCellStyle cellStyle = wb.createCellStyle(); HSSFCellStyle cellStyle = wb.createCellStyle();
@ -161,7 +186,7 @@ public final class TestHSSFDataFormatter extends TestCase {
} }
{ // formula cell { // formula cell
row = sheet.createRow(6); row = sheet.createRow(7);
HSSFCell cell = row.createCell(0); HSSFCell cell = row.createCell(0);
cell.setCellType(HSSFCell.CELL_TYPE_FORMULA); cell.setCellType(HSSFCell.CELL_TYPE_FORMULA);
cell.setCellFormula("SUM(12.25,12.25)/100"); cell.setCellFormula("SUM(12.25,12.25)/100");
@ -184,8 +209,9 @@ public final class TestHSSFDataFormatter extends TestCase {
String fmtval = formatter.formatCellValue(cell); String fmtval = formatter.formatCellValue(cell);
log(fmtval); log(fmtval);
// should not be equal to "555.555" // should not be equal to "555.555"
assertTrue( ! "555.555".equals(fmtval)); assertTrue( DateUtil.isCellDateFormatted(cell) );
assertTrue( ! "555.555".equals(fmtval));
String fmt = cell.getCellStyle().getDataFormatString(); String fmt = cell.getCellStyle().getDataFormatString();
@ -201,6 +227,23 @@ public final class TestHSSFDataFormatter extends TestCase {
assertTrue("Format came out incorrect - " + fmt, fmtval.indexOf(jul) > -1); assertTrue("Format came out incorrect - " + fmt, fmtval.indexOf(jul) > -1);
} }
row = wb.getSheetAt(0).getRow(1);
it = row.cellIterator();
log("==== VALID TIME FORMATS ====");
while (it.hasNext()) {
Cell cell = it.next();
String fmt = cell.getCellStyle().getDataFormatString();
String fmtval = formatter.formatCellValue(cell);
log(fmtval);
// should not be equal to "555.47431"
assertTrue( DateUtil.isCellDateFormatted(cell) );
assertTrue( ! "555.47431".equals(fmtval));
// check we found the time properly
assertTrue("Format came out incorrect - " + fmt, fmtval.indexOf("11:23") > -1);
}
// test number formats // test number formats
row = wb.getSheetAt(0).getRow(1); row = wb.getSheetAt(0).getRow(1);
it = row.cellIterator(); it = row.cellIterator();
@ -214,7 +257,7 @@ public final class TestHSSFDataFormatter extends TestCase {
} }
// test bad number formats // test bad number formats
row = wb.getSheetAt(0).getRow(2); row = wb.getSheetAt(0).getRow(3);
it = row.cellIterator(); it = row.cellIterator();
log("\n==== INVALID NUMBER FORMATS ===="); log("\n==== INVALID NUMBER FORMATS ====");
while (it.hasNext()) { while (it.hasNext()) {
@ -227,21 +270,21 @@ public final class TestHSSFDataFormatter extends TestCase {
} }
// test Zip+4 format // test Zip+4 format
row = wb.getSheetAt(0).getRow(3); row = wb.getSheetAt(0).getRow(4);
HSSFCell cell = row.getCell(0); HSSFCell cell = row.getCell(0);
log("\n==== ZIP FORMAT ===="); log("\n==== ZIP FORMAT ====");
log(formatter.formatCellValue(cell)); log(formatter.formatCellValue(cell));
assertEquals("12345-6789", formatter.formatCellValue(cell)); assertEquals("12345-6789", formatter.formatCellValue(cell));
// test phone number format // test phone number format
row = wb.getSheetAt(0).getRow(4); row = wb.getSheetAt(0).getRow(5);
cell = row.getCell(0); cell = row.getCell(0);
log("\n==== PHONE FORMAT ===="); log("\n==== PHONE FORMAT ====");
log(formatter.formatCellValue(cell)); log(formatter.formatCellValue(cell));
assertEquals("(555) 123-4567", formatter.formatCellValue(cell)); assertEquals("(555) 123-4567", formatter.formatCellValue(cell));
// test SSN format // test SSN format
row = wb.getSheetAt(0).getRow(5); row = wb.getSheetAt(0).getRow(6);
cell = row.getCell(0); cell = row.getCell(0);
log("\n==== SSN FORMAT ===="); log("\n==== SSN FORMAT ====");
log(formatter.formatCellValue(cell)); log(formatter.formatCellValue(cell));
@ -256,7 +299,7 @@ public final class TestHSSFDataFormatter extends TestCase {
public void testGetFormattedCellValueHSSFCellHSSFFormulaEvaluator() { public void testGetFormattedCellValueHSSFCellHSSFFormulaEvaluator() {
// test formula format // test formula format
HSSFRow row = wb.getSheetAt(0).getRow(6); HSSFRow row = wb.getSheetAt(0).getRow(7);
HSSFCell cell = row.getCell(0); HSSFCell cell = row.getCell(0);
log("\n==== FORMULA CELL ===="); log("\n==== FORMULA CELL ====");
@ -277,7 +320,7 @@ public final class TestHSSFDataFormatter extends TestCase {
* format pattern cannot be parsed by DecimalFormat. * format pattern cannot be parsed by DecimalFormat.
*/ */
public void testSetDefaultNumberFormat() { public void testSetDefaultNumberFormat() {
HSSFRow row = wb.getSheetAt(0).getRow(2); HSSFRow row = wb.getSheetAt(0).getRow(3);
Iterator<Cell> it = row.cellIterator(); Iterator<Cell> it = row.cellIterator();
Format defaultFormat = new DecimalFormat("Balance $#,#00.00 USD;Balance -$#,#00.00 USD"); Format defaultFormat = new DecimalFormat("Balance $#,#00.00 USD;Balance -$#,#00.00 USD");
formatter.setDefaultNumberFormat(defaultFormat); formatter.setDefaultNumberFormat(defaultFormat);