From 70bd85fda41f885427e3db8d5b32eb71656f8eb0 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Fri, 15 Jul 2022 21:31:35 +0000 Subject: [PATCH] [github-358] improve locking in CellDateFormatter. Thanks to XenoAmess. This closes #358 git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1902754 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/ss/format/CellDateFormatter.java | 142 +++++++++--------- 1 file changed, 73 insertions(+), 69 deletions(-) diff --git a/poi/src/main/java/org/apache/poi/ss/format/CellDateFormatter.java b/poi/src/main/java/org/apache/poi/ss/format/CellDateFormatter.java index 3644c84780..f408450b48 100644 --- a/poi/src/main/java/org/apache/poi/ss/format/CellDateFormatter.java +++ b/poi/src/main/java/org/apache/poi/ss/format/CellDateFormatter.java @@ -40,11 +40,11 @@ public class CellDateFormatter extends CellFormatter { private String sFmt; private static final Calendar EXCEL_EPOCH_CAL = - LocaleUtil.getLocaleCalendar(1904, 0, 1); + LocaleUtil.getLocaleCalendar(1904, 0, 1); private static final int NUM_MILLISECONDS_IN_DAY = 1000 * 60 * 60 * 24; - private static /* final */ CellDateFormatter SIMPLE_DATE; + private static /* final */ volatile CellDateFormatter SIMPLE_DATE; class DatePartHandler implements CellFormatPart.PartHandler { private int mStart = -1; @@ -54,79 +54,79 @@ public class CellDateFormatter extends CellFormatter { @Override public String handlePart(Matcher m, String part, CellFormatType type, - StringBuffer desc) { + StringBuffer desc) { int pos = desc.length(); char firstCh = part.charAt(0); switch (firstCh) { - case 's': - case 'S': - if (mStart >= 0) { - for (int i = 0; i < mLen; i++) - desc.setCharAt(mStart + i, 'm'); + case 's': + case 'S': + if (mStart >= 0) { + for (int i = 0; i < mLen; i++) + desc.setCharAt(mStart + i, 'm'); + mStart = -1; + } + return part.toLowerCase(Locale.ROOT); + + case 'h': + case 'H': mStart = -1; - } - return part.toLowerCase(Locale.ROOT); - - case 'h': - case 'H': - mStart = -1; - hStart = pos; - hLen = part.length(); - return part.toLowerCase(Locale.ROOT); - - case 'd': - case 'D': - mStart = -1; - if (part.length() <= 2) + hStart = pos; + hLen = part.length(); return part.toLowerCase(Locale.ROOT); - else - return part.toLowerCase(Locale.ROOT).replace('d', 'E'); - - case 'm': - case 'M': - mStart = pos; - mLen = part.length(); - // For 'm' after 'h', output minutes ('m') not month ('M') - if (hStart >= 0) + + case 'd': + case 'D': + mStart = -1; + if (part.length() <= 2) + return part.toLowerCase(Locale.ROOT); + else + return part.toLowerCase(Locale.ROOT).replace('d', 'E'); + + case 'm': + case 'M': + mStart = pos; + mLen = part.length(); + // For 'm' after 'h', output minutes ('m') not month ('M') + if (hStart >= 0) + return part.toLowerCase(Locale.ROOT); + else + return part.toUpperCase(Locale.ROOT); + + case 'y': + case 'Y': + mStart = -1; + // See https://issues.apache.org/bugzilla/show_bug.cgi?id=53369 + if (part.length() == 1) + part = "yy"; + else if (part.length() == 3) + part = "yyyy"; return part.toLowerCase(Locale.ROOT); - else - return part.toUpperCase(Locale.ROOT); - - case 'y': - case 'Y': - mStart = -1; - // See https://issues.apache.org/bugzilla/show_bug.cgi?id=53369 - if (part.length() == 1) - part = "yy"; - else if (part.length() == 3) - part = "yyyy"; - return part.toLowerCase(Locale.ROOT); - - case '0': - mStart = -1; - int sLen = part.length(); - sFmt = "%0" + (sLen + 2) + "." + sLen + "f"; - return part.replace('0', 'S'); - - case 'a': - case 'A': - case 'p': - case 'P': - if (part.length() > 1) { - // am/pm marker + + case '0': mStart = -1; - showAmPm = true; - showM = StringUtil.toLowerCase(part.charAt(1)).equals("m"); - // For some reason "am/pm" becomes AM or PM, but "a/p" becomes a or p - amPmUpper = showM || StringUtil.isUpperCase(part.charAt(0)); + int sLen = part.length(); + sFmt = "%0" + (sLen + 2) + "." + sLen + "f"; + return part.replace('0', 'S'); - return "a"; - } - //noinspection fallthrough + case 'a': + case 'A': + case 'p': + case 'P': + if (part.length() > 1) { + // am/pm marker + mStart = -1; + showAmPm = true; + showM = StringUtil.toLowerCase(part.charAt(1)).equals("m"); + // For some reason "am/pm" becomes AM or PM, but "a/p" becomes a or p + amPmUpper = showM || StringUtil.isUpperCase(part.charAt(0)); - default: - return null; + return "a"; + } + //noinspection fallthrough + + default: + return null; } } @@ -242,11 +242,15 @@ public class CellDateFormatter extends CellFormatter { */ @Override public void simpleValue(StringBuffer toAppendTo, Object value) { - synchronized (CellDateFormatter.class) { - if (SIMPLE_DATE == null || !SIMPLE_DATE.EXCEL_EPOCH_CAL.equals(EXCEL_EPOCH_CAL)) { - SIMPLE_DATE = new CellDateFormatter("mm/d/y"); + CellDateFormatter cellDateFormatter = SIMPLE_DATE; + if (cellDateFormatter == null) { + synchronized (CellDateFormatter.class) { + cellDateFormatter = SIMPLE_DATE; + if (cellDateFormatter == null) { + SIMPLE_DATE = cellDateFormatter = new CellDateFormatter("mm/d/y"); + } } } - SIMPLE_DATE.formatValue(toAppendTo, value); + cellDateFormatter.formatValue(toAppendTo, value); } } -- 2.39.5