From 5cd9ac0ccf6a0e2d0ba630cf94268e0637a57a23 Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Wed, 2 Jun 2010 17:17:42 +0000 Subject: [PATCH] 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 --- src/documentation/content/xdocs/status.xml | 1 + .../poi/ss/usermodel/DataFormatter.java | 4 +- .../org/apache/poi/ss/usermodel/DateUtil.java | 8 ++- .../hssf/usermodel/TestHSSFDataFormatter.java | 71 +++++++++++++++---- 4 files changed, 67 insertions(+), 17 deletions(-) diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index b5c016472..795d23d3e 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + 48494 - detect and support time formats like HH:MM;HH:MM 48494 - have ExcelExtractor make use of HSSFDataFormatter, so that numbers and dates come out closer to how Excel would render them 48494 - have EventBasedExcelExtractor make use of HSSFDataFormatter, so that numbers and dates come out closer to how Excel would render them 49096 - add clone support to Chart begin and end records, to allow cloning of more Chart containing sheets diff --git a/src/java/org/apache/poi/ss/usermodel/DataFormatter.java b/src/java/org/apache/poi/ss/usermodel/DataFormatter.java index d0d07c0a3..69e1f2ae0 100644 --- a/src/java/org/apache/poi/ss/usermodel/DataFormatter.java +++ b/src/java/org/apache/poi/ss/usermodel/DataFormatter.java @@ -297,7 +297,7 @@ public class DataFormatter { } // 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: /* The "m" or "mm" code must appear immediately after the "h" or"hh" @@ -319,7 +319,7 @@ public class DataFormatter { sb.append('H'); } } - else if (c == 'm') { + else if (c == 'm' || c == 'M') { if(mIsMonth) { sb.append('M'); ms.add( diff --git a/src/java/org/apache/poi/ss/usermodel/DateUtil.java b/src/java/org/apache/poi/ss/usermodel/DateUtil.java index fb2bfd94d..787d8d0ec 100644 --- a/src/java/org/apache/poi/ss/usermodel/DateUtil.java +++ b/src/java/org/apache/poi/ss/usermodel/DateUtil.java @@ -258,13 +258,19 @@ public class DateUtil { sb.append(c); } fs = sb.toString(); - + // If it starts with [$-...], then could be a date, but // who knows what that starting bit is all about fs = date_ptrn1.matcher(fs).replaceAll(""); // If it starts with something like [Black] or [Yellow], // then it could be a date 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: // y m d h s - \ / , . : diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDataFormatter.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDataFormatter.java index c0e4150b4..e5f1f8129 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDataFormatter.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDataFormatter.java @@ -28,6 +28,7 @@ import java.util.Locale; import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.DateUtil; import junit.framework.TestCase; @@ -56,9 +57,11 @@ public final class TestHSSFDataFormatter extends TestCase { // date value for July 8 1901 1:19 PM 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 - String[] goodDatePatterns ={ + String[] goodDatePatterns = { "[$-F800]dddd\\,\\ mmmm\\ dd\\,\\ yyyy", "mmm/d/yy\\ h:mm PM;@", "mmmm/d/yy\\ h:mm;@", @@ -78,6 +81,18 @@ public final class TestHSSFDataFormatter extends TestCase { "mmmm/d/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 String[] goodNumPatterns = { @@ -111,6 +126,16 @@ public final class TestHSSFDataFormatter extends TestCase { cell.setCellStyle(cellStyle); } 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 for (int i = 0; i < goodNumPatterns.length; i++) { @@ -120,7 +145,7 @@ public final class TestHSSFDataFormatter extends TestCase { cellStyle.setDataFormat(format.getFormat(goodNumPatterns[i])); cell.setCellStyle(cellStyle); } - row = sheet.createRow(2); + row = sheet.createRow(3); // create cells with bad num patterns for (int i = 0; i < badNumPatterns.length; i++) { @@ -134,7 +159,7 @@ public final class TestHSSFDataFormatter extends TestCase { // Built in formats { // Zip + 4 format - row = sheet.createRow(3); + row = sheet.createRow(4); HSSFCell cell = row.createCell(0); cell.setCellValue(123456789); HSSFCellStyle cellStyle = wb.createCellStyle(); @@ -143,7 +168,7 @@ public final class TestHSSFDataFormatter extends TestCase { } { // Phone number format - row = sheet.createRow(4); + row = sheet.createRow(5); HSSFCell cell = row.createCell(0); cell.setCellValue(5551234567D); HSSFCellStyle cellStyle = wb.createCellStyle(); @@ -152,7 +177,7 @@ public final class TestHSSFDataFormatter extends TestCase { } { // SSN format - row = sheet.createRow(5); + row = sheet.createRow(6); HSSFCell cell = row.createCell(0); cell.setCellValue(444551234); HSSFCellStyle cellStyle = wb.createCellStyle(); @@ -161,7 +186,7 @@ public final class TestHSSFDataFormatter extends TestCase { } { // formula cell - row = sheet.createRow(6); + row = sheet.createRow(7); HSSFCell cell = row.createCell(0); cell.setCellType(HSSFCell.CELL_TYPE_FORMULA); cell.setCellFormula("SUM(12.25,12.25)/100"); @@ -184,8 +209,9 @@ public final class TestHSSFDataFormatter extends TestCase { String fmtval = formatter.formatCellValue(cell); log(fmtval); - // should not be equal to "555.555" - assertTrue( ! "555.555".equals(fmtval)); + // should not be equal to "555.555" + assertTrue( DateUtil.isCellDateFormatted(cell) ); + assertTrue( ! "555.555".equals(fmtval)); 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); } + 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 row = wb.getSheetAt(0).getRow(1); it = row.cellIterator(); @@ -214,7 +257,7 @@ public final class TestHSSFDataFormatter extends TestCase { } // test bad number formats - row = wb.getSheetAt(0).getRow(2); + row = wb.getSheetAt(0).getRow(3); it = row.cellIterator(); log("\n==== INVALID NUMBER FORMATS ===="); while (it.hasNext()) { @@ -227,21 +270,21 @@ public final class TestHSSFDataFormatter extends TestCase { } // test Zip+4 format - row = wb.getSheetAt(0).getRow(3); + row = wb.getSheetAt(0).getRow(4); HSSFCell cell = row.getCell(0); log("\n==== ZIP FORMAT ===="); log(formatter.formatCellValue(cell)); assertEquals("12345-6789", formatter.formatCellValue(cell)); // test phone number format - row = wb.getSheetAt(0).getRow(4); + row = wb.getSheetAt(0).getRow(5); cell = row.getCell(0); log("\n==== PHONE FORMAT ===="); log(formatter.formatCellValue(cell)); assertEquals("(555) 123-4567", formatter.formatCellValue(cell)); // test SSN format - row = wb.getSheetAt(0).getRow(5); + row = wb.getSheetAt(0).getRow(6); cell = row.getCell(0); log("\n==== SSN FORMAT ===="); log(formatter.formatCellValue(cell)); @@ -256,7 +299,7 @@ public final class TestHSSFDataFormatter extends TestCase { public void testGetFormattedCellValueHSSFCellHSSFFormulaEvaluator() { // test formula format - HSSFRow row = wb.getSheetAt(0).getRow(6); + HSSFRow row = wb.getSheetAt(0).getRow(7); HSSFCell cell = row.getCell(0); log("\n==== FORMULA CELL ===="); @@ -277,7 +320,7 @@ public final class TestHSSFDataFormatter extends TestCase { * format pattern cannot be parsed by DecimalFormat. */ public void testSetDefaultNumberFormat() { - HSSFRow row = wb.getSheetAt(0).getRow(2); + HSSFRow row = wb.getSheetAt(0).getRow(3); Iterator it = row.cellIterator(); Format defaultFormat = new DecimalFormat("Balance $#,#00.00 USD;Balance -$#,#00.00 USD"); formatter.setDefaultNumberFormat(defaultFormat);