Author: fanningpj
Date: Tue Jun 17 17:18:12 2025
New Revision: 1926508
URL: http://svn.apache.org/viewvc?rev=1926508&view=rev
Log:
[bug-69681] allow 1 optional space in date formats before the AM/PM part
Modified:
poi/trunk/poi/src/main/java/org/apache/poi/ss/usermodel/DateUtil.java
poi/trunk/poi/src/test/java/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java
Modified: poi/trunk/poi/src/main/java/org/apache/poi/ss/usermodel/DateUtil.java
URL:
http://svn.apache.org/viewvc/poi/trunk/poi/src/main/java/org/apache/poi/ss/usermodel/DateUtil.java?rev=1926508&r1=1926507&r2=1926508&view=diff
==============================================================================
--- poi/trunk/poi/src/main/java/org/apache/poi/ss/usermodel/DateUtil.java
[UTF-8] (original)
+++ poi/trunk/poi/src/main/java/org/apache/poi/ss/usermodel/DateUtil.java
[UTF-8] Tue Jun 17 17:18:12 2025
@@ -70,7 +70,7 @@ public class DateUtil {
private static final Pattern date_ptrn2 =
Pattern.compile("^\\[[a-zA-Z]+]");
private static final Pattern date_ptrn3a = Pattern.compile("[yYmMdDhHsS]");
// add "\u5e74 \u6708 \u65e5" for Chinese/Japanese date format:2017 \u5e74
2 \u6708 7 \u65e5
- private static final Pattern date_ptrn3b =
Pattern.compile("^[\\[\\]yYmMdDhHsS\\-T/\u5e74\u6708\u65e5,.
:\"\\\\]+0*[ampAMP/]*$");
+ private static final Pattern date_ptrn3b =
Pattern.compile("^[\\[\\]yYmMdDhHsS\\-T/\u5e74\u6708\u65e5,. :\"\\\\]+0*
?[ampAMP/]*$");
// elapsed time patterns: [h],[m] and [s]
private static final Pattern date_ptrn4 =
Pattern.compile("^\\[([hH]+|[mM]+|[sS]+)]");
@@ -548,6 +548,7 @@ public class DateUtil {
// avoid re-checking DateUtil.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 boolean maintainCache = true;
private static final ThreadLocal<Integer> lastFormatIndex =
ThreadLocal.withInitial(() -> -1);
private static final ThreadLocal<String> lastFormatString = new
ThreadLocal<>();
private static final ThreadLocal<Boolean> lastCachedResult = new
ThreadLocal<>();
@@ -561,22 +562,24 @@ public class DateUtil {
}
private static boolean isCached(String formatString, int formatIndex) {
- return formatIndex == lastFormatIndex.get()
+ return maintainCache && formatIndex == lastFormatIndex.get()
&& formatString.equals(lastFormatString.get());
}
private static void cache(String formatString, int formatIndex, boolean
cached) {
- if (formatString == null || "".equals(formatString)) {
- lastFormatString.remove();
- } else {
- lastFormatString.set(formatString);
- }
- if (formatIndex == -1) {
- lastFormatIndex.remove();
- } else {
- lastFormatIndex.set(formatIndex);
+ if (maintainCache) {
+ if (formatString == null || "".equals(formatString)) {
+ lastFormatString.remove();
+ } else {
+ lastFormatString.set(formatString);
+ }
+ if (formatIndex == -1) {
+ lastFormatIndex.remove();
+ } else {
+ lastFormatIndex.set(formatIndex);
+ }
+ lastCachedResult.set(cached);
}
- lastCachedResult.set(cached);
}
/**
@@ -997,4 +1000,18 @@ public class DateUtil {
return tm;
}
+
+ /**
+ * Enable or disable the thread-local cache for date format checking.
+ * If enabled, the date format checking will be cached per thread,
+ * which can improve performance when checking the same format multiple
times.
+ * If disabled, the cache will not be used and each check will be
performed independently.
+ *
+ * @param enable true to enable the cache, false to disable it (enabled,
by default)
+ * @since POI 5.4.2
+ */
+ public static void enableThreadLocalCache(final boolean enable) {
+ // enable thread-local cache for date format checking
+ maintainCache = enable;
+ }
}
Modified:
poi/trunk/poi/src/test/java/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java
URL:
http://svn.apache.org/viewvc/poi/trunk/poi/src/test/java/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java?rev=1926508&r1=1926507&r2=1926508&view=diff
==============================================================================
---
poi/trunk/poi/src/test/java/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java
(original)
+++
poi/trunk/poi/src/test/java/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java
Tue Jun 17 17:18:12 2025
@@ -27,6 +27,7 @@ import java.util.TimeZone;
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.model.InternalWorkbook;
+import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.util.LocaleUtil;
import org.junit.jupiter.api.AfterAll;
@@ -60,7 +61,7 @@ class TestHSSFDateUtil {
HSSFWorkbook workbook =
HSSFTestDataSamples.openSampleWorkbook("DateFormats.xls");
HSSFSheet sheet = workbook.getSheetAt(0);
- InternalWorkbook wb = workbook.getWorkbook();
+ InternalWorkbook wb = workbook.getWorkbook();
assertNotNull(wb);
HSSFRow row;
@@ -115,4 +116,27 @@ class TestHSSFDateUtil {
workbook.close();
}
+
+ @Test
+ void testIsADateFormat() throws IOException {
+ try (HSSFWorkbook workbook = new HSSFWorkbook()) {
+ HSSFSheet sheet = workbook.createSheet();
+ HSSFRow row = sheet.createRow(0);
+ HSSFCell cell = row.createCell(0);
+ cell.setCellValue(45825.5); // 2025-06-17 (midday)
+ HSSFCellStyle style = workbook.createCellStyle();
+ style.setDataFormat(workbook.createDataFormat().getFormat("DD
MMMM, YYYY hh:mm:ss.000 AM/PM"));
+ cell.setCellStyle(style);
+ DateUtil.enableThreadLocalCache(false);
+ try {
+ assertTrue(DateUtil.isCellDateFormatted(cell), "cell is date
formatted?");
+ DataFormatter formatter = new DataFormatter();
+ String formattedValue = formatter.formatCellValue(cell);
+ assertEquals("17 June, 2025 12:00:00.000 PM", formattedValue);
+ } finally {
+ DateUtil.enableThreadLocalCache(true);
+ }
+ }
+ }
+
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]