diff --git a/hugegraph-loader/src/main/java/org/apache/hugegraph/loader/util/DateUtil.java b/hugegraph-loader/src/main/java/org/apache/hugegraph/loader/util/DateUtil.java index 670c70a01..caeada15a 100644 --- a/hugegraph-loader/src/main/java/org/apache/hugegraph/loader/util/DateUtil.java +++ b/hugegraph-loader/src/main/java/org/apache/hugegraph/loader/util/DateUtil.java @@ -18,16 +18,16 @@ package org.apache.hugegraph.loader.util; import java.util.Date; -import java.util.Map; +import java.util.HashMap; import java.util.TimeZone; -import java.util.concurrent.ConcurrentHashMap; import org.apache.hugegraph.date.SafeDateFormat; import org.apache.hugegraph.loader.constant.Constants; public final class DateUtil { - private static final Map DATE_FORMATS = new ConcurrentHashMap<>(); + private static final ThreadLocal> DATE_FORMATS = + ThreadLocal.withInitial(HashMap::new); public static Date parse(String source, String df) { return parse(source, df, Constants.TIME_ZONE); @@ -35,19 +35,16 @@ public static Date parse(String source, String df) { public static Date parse(String source, String df, String timeZone) { SafeDateFormat dateFormat = getDateFormat(df); - // parse date with specified timezone dateFormat.setTimeZone(timeZone); return dateFormat.parse(source); } private static SafeDateFormat getDateFormat(String df) { - SafeDateFormat dateFormat = DATE_FORMATS.get(df); + HashMap formats = DATE_FORMATS.get(); + SafeDateFormat dateFormat = formats.get(df); if (dateFormat == null) { dateFormat = new SafeDateFormat(df); - SafeDateFormat previous = DATE_FORMATS.putIfAbsent(df, dateFormat); - if (previous != null) { - dateFormat = previous; - } + formats.put(df, dateFormat); } return dateFormat; } @@ -58,7 +55,9 @@ public static Object toPattern(String df) { } public static String now(String df) { - return getDateFormat(df).format(new Date()); + SafeDateFormat dateFormat = getDateFormat(df); + dateFormat.setTimeZone(Constants.TIME_ZONE); + return dateFormat.format(new Date()); } public static boolean checkTimeZone(String timeZone) { diff --git a/hugegraph-loader/src/test/java/org/apache/hugegraph/loader/test/unit/DateUtilTest.java b/hugegraph-loader/src/test/java/org/apache/hugegraph/loader/test/unit/DateUtilTest.java index 6370c8977..08d2ab2ab 100644 --- a/hugegraph-loader/src/test/java/org/apache/hugegraph/loader/test/unit/DateUtilTest.java +++ b/hugegraph-loader/src/test/java/org/apache/hugegraph/loader/test/unit/DateUtilTest.java @@ -17,6 +17,12 @@ package org.apache.hugegraph.loader.test.unit; +import java.util.Date; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; + import org.apache.hugegraph.loader.util.DateUtil; import org.junit.Test; @@ -24,6 +30,13 @@ public class DateUtilTest { + @Test + public void testNowUsesDefaultTimeZone() { + String pattern = "Z"; + DateUtil.parse("+0000", pattern, "GMT"); + Assert.assertEquals("+0800", DateUtil.now(pattern)); + } + @Test public void testCheckTimeZone() { Assert.assertTrue(DateUtil.checkTimeZone("JST")); @@ -70,4 +83,45 @@ public void testCheckTimeZone() { // minutes 00-59 only Assert.assertFalse(DateUtil.checkTimeZone("GMT+13:60")); } + + @Test + public void testConcurrentParseDateWithDifferentTimeZones() throws InterruptedException { + int threads = 10; + int iterations = 100; + ExecutorService executor = Executors.newFixedThreadPool(threads); + CountDownLatch latch = new CountDownLatch(threads); + AtomicInteger errors = new AtomicInteger(0); + + String dateStr = "2024-01-15 12:00:00"; + String pattern = "yyyy-MM-dd HH:mm:ss"; + long expectedEpochGMT8 = DateUtil.parse(dateStr, pattern, "GMT+8").getTime(); + long expectedEpochGMT0 = DateUtil.parse(dateStr, pattern, "GMT+0").getTime(); + long expectedDiff = 8 * 60 * 60 * 1000; + + for (int i = 0; i < threads; i++) { + final int threadId = i; + executor.submit(() -> { + try { + String timeZone = threadId % 2 == 0 ? "GMT+8" : "GMT+0"; + long expectedEpoch = threadId % 2 == 0 ? expectedEpochGMT8 : expectedEpochGMT0; + for (int j = 0; j < iterations; j++) { + Date result = DateUtil.parse(dateStr, pattern, timeZone); + if (result == null || result.getTime() != expectedEpoch) { + errors.incrementAndGet(); + } + } + } catch (Exception e) { + errors.incrementAndGet(); + } finally { + latch.countDown(); + } + }); + } + + latch.await(); + executor.shutdown(); + + Assert.assertEquals(0, errors.get()); + Assert.assertEquals(expectedDiff, expectedEpochGMT0 - expectedEpochGMT8); + } }