diff --git a/persistit/core/src/main/java/com/persistit/Key.java b/persistit/core/src/main/java/com/persistit/Key.java index 219c03275..440f627ab 100644 --- a/persistit/core/src/main/java/com/persistit/Key.java +++ b/persistit/core/src/main/java/com/persistit/Key.java @@ -1,5 +1,6 @@ /** * Copyright 2005-2012 Akiban Technologies, Inc. + * Portions Copyrighted 2026 3A Systems, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -504,14 +505,19 @@ public enum Direction { public final static EdgeValue AFTER = new EdgeValue(true); /** - * The java.text.SimpleDateFormat used in formatting + * A thread-local java.text.SimpleDateFormat used in formatting * Date- valued keys in the {@link #decodeDisplayable} methods. * This format also governs the conversion of dates for the * toString method. This format provides millisecond resolution * so that the precise stored representation of a date used as a key can be * represented exactly, but readably, in the displayable version. + *

+ * SimpleDateFormat is not thread-safe, so the instance is held + * in a {@link ThreadLocal}; call {@link ThreadLocal#get()} to obtain the + * per-thread formatter, e.g. SDF.get().format(date). */ - public final static SimpleDateFormat SDF = new SimpleDateFormat("yyyyMMddHHmmss.SSSZ"); + public final static ThreadLocal SDF = ThreadLocal + .withInitial(() -> new SimpleDateFormat("yyyyMMddHHmmss.SSSZ")); /** * Displayable prefix for boolean values (optional for input, implied and @@ -3139,7 +3145,7 @@ else if (cl == Boolean.class) { else if (cl == Date.class) { Util.append(sb, PREFIX_DATE); - Util.append(sb, SDF.format(decodeDate())); + Util.append(sb, SDF.get().format(decodeDate())); } else if (cl == byte[].class) { diff --git a/persistit/core/src/main/java/com/persistit/KeyParser.java b/persistit/core/src/main/java/com/persistit/KeyParser.java index 3fc768a06..13c6561be 100644 --- a/persistit/core/src/main/java/com/persistit/KeyParser.java +++ b/persistit/core/src/main/java/com/persistit/KeyParser.java @@ -1,5 +1,6 @@ /** * Copyright 2005-2012 Akiban Technologies, Inc. + * Portions Copyrighted 2026 3A Systems, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -293,7 +294,7 @@ else if (matchExactString("false")) } } else if (matchExactString(Key.PREFIX_DATE) || matchExactString(Key.PREFIX_DATE0)) { if (matchNumber(true, true)) { - key.append(Key.SDF.parse(_sb.toString())); + key.append(Key.SDF.get().parse(_sb.toString())); result = true; } } else if (matchExactString(Key.PREFIX_BYTE_ARRAY)) { diff --git a/persistit/core/src/main/java/com/persistit/Value.java b/persistit/core/src/main/java/com/persistit/Value.java index 7e7cdb172..5a5d05d2a 100644 --- a/persistit/core/src/main/java/com/persistit/Value.java +++ b/persistit/core/src/main/java/com/persistit/Value.java @@ -1,5 +1,6 @@ /** * Copyright 2005-2012 Akiban Technologies, Inc. + * Portions Copyrighted 2026 3A Systems, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -1566,7 +1567,7 @@ private void appendDisplayable(final StringBuilder sb, final Object value, final sb.append("..."); } else if (cl == Date.class) { appendParenthesizedFriendlyClassName(sb, cl); - sb.append(Key.SDF.format((Date) value)); + sb.append(Key.SDF.get().format((Date) value)); } else if (value instanceof Number) { sb.append('('); sb.append(className.startsWith("java.lang.") ? className.substring(10) : className); diff --git a/persistit/ui/src/main/java/com/persistit/ui/ValueInspectorTreeNode.java b/persistit/ui/src/main/java/com/persistit/ui/ValueInspectorTreeNode.java index 3eb835090..906f9d41a 100644 --- a/persistit/ui/src/main/java/com/persistit/ui/ValueInspectorTreeNode.java +++ b/persistit/ui/src/main/java/com/persistit/ui/ValueInspectorTreeNode.java @@ -1,5 +1,6 @@ /** * Copyright 2005-2012 Akiban Technologies, Inc. + * Portions Copyrighted 2026 3A Systems, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -156,7 +157,7 @@ String displayable(final String fieldName, final Class type, final Object object sb.append('\"'); } else if (object instanceof Date) { sb.append(" = "); - sb.append(Key.SDF.format((Date) object)); + sb.append(Key.SDF.get().format((Date) object)); } else if (type == Boolean.class || type == Byte.class || type == Short.class || type == Character.class || type == Integer.class || type == Long.class || type == Float.class || type == Double.class || type == BigInteger.class || type == BigDecimal.class) {