diff options
-rw-r--r-- | src/java/org/apache/poi/ss/usermodel/DateUtil.java | 51 | ||||
-rw-r--r-- | src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java | 48 |
2 files changed, 66 insertions, 33 deletions
diff --git a/src/java/org/apache/poi/ss/usermodel/DateUtil.java b/src/java/org/apache/poi/ss/usermodel/DateUtil.java index 2bc9f01713..79512ef102 100644 --- a/src/java/org/apache/poi/ss/usermodel/DateUtil.java +++ b/src/java/org/apache/poi/ss/usermodel/DateUtil.java @@ -327,15 +327,30 @@ public class DateUtil { return calendar; } - // variables for performance optimization: // avoid re-checking DataUtil.isADateFormat(int, String) if a given format // string represents a date format if the same string is passed multiple times. // see https://issues.apache.org/bugzilla/show_bug.cgi?id=55611 - private static int lastFormatIndex = -1; - private static String lastFormatString = null; - private static boolean cached = false; + private static ThreadLocal<Integer> lastFormatIndex = new ThreadLocal<Integer>() { + protected Integer initialValue() { + return -1; + } + }; + private static ThreadLocal<String> lastFormatString = new ThreadLocal<String>(); + private static ThreadLocal<Boolean> lastCachedResult = new ThreadLocal<Boolean>(); + + private static boolean isCached(String formatString, int formatIndex) { + String cachedFormatString = lastFormatString.get(); + return cachedFormatString != null && formatIndex == lastFormatIndex.get() + && formatString.equals(cachedFormatString); + } + private static void cache(String formatString, int formatIndex, boolean cached) { + lastFormatIndex.set(formatIndex); + lastFormatString.set(formatString); + lastCachedResult.set(Boolean.valueOf(cached)); + } + /** * Given a format ID and its format String, will check to see if the * format represents a date format or not. @@ -350,27 +365,23 @@ public class DateUtil { * @see #isInternalDateFormat(int) */ - public static synchronized boolean isADateFormat(int formatIndex, String formatString) { - - if (formatString != null && formatIndex == lastFormatIndex && formatString.equals(lastFormatString)) { - return cached; - } + public static boolean isADateFormat(int formatIndex, String formatString) { // First up, is this an internal date format? if(isInternalDateFormat(formatIndex)) { - lastFormatIndex = formatIndex; - lastFormatString = formatString; - cached = true; + cache(formatString, formatIndex, true); return true; } - // If we didn't get a real string, it can't be + // If we didn't get a real string, don't even cache it as we can always find this out quickly if(formatString == null || formatString.length() == 0) { - lastFormatIndex = formatIndex; - lastFormatString = formatString; - cached = false; return false; } + // check the cache first + if (isCached(formatString, formatIndex)) { + return lastCachedResult.get(); + } + String fs = formatString; /*if (false) { // Normalize the format string. The code below is equivalent @@ -419,9 +430,7 @@ public class DateUtil { // short-circuit if it indicates elapsed time: [h], [m] or [s] if(date_ptrn4.matcher(fs).matches()){ - lastFormatIndex = formatIndex; - lastFormatString = formatString; - cached = true; + cache(formatString, formatIndex, true); return true; } @@ -449,9 +458,7 @@ public class DateUtil { // optionally followed by AM/PM boolean result = date_ptrn3b.matcher(fs).matches(); - lastFormatIndex = formatIndex; - lastFormatString = formatString; - cached = result; + cache(formatString, formatIndex, result); return result; } diff --git a/src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java b/src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java index 06ad051a38..08f21a5900 100644 --- a/src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java +++ b/src/testcases/org/apache/poi/ss/usermodel/TestDataFormatter.java @@ -21,6 +21,7 @@ package org.apache.poi.ss.usermodel; +import java.io.IOException; import java.text.DateFormat; import java.util.Calendar; import java.util.Date; @@ -158,7 +159,7 @@ public class TestDataFormatter extends TestCase { String p2dp_n1dp_z0 = "00.00;(00.0);0"; String all2dpTSP = "00.00_x"; String p2dp_n2dpTSP = "00.00_x;(00.00)_x"; - String p2dp_n1dpTSP = "00.00_x;(00.0)_x"; + //String p2dp_n1dpTSP = "00.00_x;(00.0)_x"; assertEquals("12.34", dfUS.formatRawCellContents(12.343, -1, all2dp)); assertEquals("12.34", dfUS.formatRawCellContents(12.343, -1, p2dp_n1dp)); @@ -493,20 +494,24 @@ public class TestDataFormatter extends TestCase { assertEquals(" $- ", dfUS.formatRawCellContents(0.0, -1, "_-$* #,##0.00_-;-$* #,##0.00_-;_-$* \"-\"??_-;_-@_-")); } - public void testErrors() { + public void testErrors() throws IOException { DataFormatter dfUS = new DataFormatter(Locale.US, true); // Create a spreadsheet with some formula errors in it Workbook wb = new HSSFWorkbook(); - Sheet s = wb.createSheet(); - Row r = s.createRow(0); - Cell c = r.createCell(0, Cell.CELL_TYPE_ERROR); - - c.setCellErrorValue(FormulaError.DIV0.getCode()); - assertEquals(FormulaError.DIV0.getString(), dfUS.formatCellValue(c)); - - c.setCellErrorValue(FormulaError.REF.getCode()); - assertEquals(FormulaError.REF.getString(), dfUS.formatCellValue(c)); + try { + Sheet s = wb.createSheet(); + Row r = s.createRow(0); + Cell c = r.createCell(0, Cell.CELL_TYPE_ERROR); + + c.setCellErrorValue(FormulaError.DIV0.getCode()); + assertEquals(FormulaError.DIV0.getString(), dfUS.formatCellValue(c)); + + c.setCellErrorValue(FormulaError.REF.getCode()); + assertEquals(FormulaError.REF.getString(), dfUS.formatCellValue(c)); + } finally { + wb.close(); + } } /** @@ -607,4 +612,25 @@ public class TestDataFormatter extends TestCase { assertTrue(e.getMessage().contains("Cannot format given Object as a Number")); } } + + public void testIsADateFormat() { + // first check some cases that should not be a date, also call multiple times to ensure the cache is used + assertFalse(DateUtil.isADateFormat(-1, null)); + assertFalse(DateUtil.isADateFormat(-1, null)); + assertFalse(DateUtil.isADateFormat(123, null)); + assertFalse(DateUtil.isADateFormat(123, "")); + assertFalse(DateUtil.isADateFormat(124, "")); + assertFalse(DateUtil.isADateFormat(-1, "")); + assertFalse(DateUtil.isADateFormat(-1, "")); + assertFalse(DateUtil.isADateFormat(-1, "nodateformat")); + + // then also do the same for some valid date formats + assertTrue(DateUtil.isADateFormat(0x0e, null)); + assertTrue(DateUtil.isADateFormat(0x2f, null)); + assertTrue(DateUtil.isADateFormat(-1, "yyyy")); + assertTrue(DateUtil.isADateFormat(-1, "yyyy")); + assertTrue(DateUtil.isADateFormat(-1, "dd/mm/yy;[red]dd/mm/yy")); + assertTrue(DateUtil.isADateFormat(-1, "dd/mm/yy;[red]dd/mm/yy")); + assertTrue(DateUtil.isADateFormat(-1, "[h]")); + } } |