diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbDate.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbDate.java index d8c5fb2265..c22e2c329d 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbDate.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbDate.java @@ -35,7 +35,8 @@ public class TbDate extends Date { private static final DateTimeFormatter isoDateFormatter = DateTimeFormatter.ofPattern( "yyyy-MM-dd[[ ]['T']HH:mm[:ss[.SSS]][ ][XXX][Z][z][VV][O]]").withZone(ZoneId.systemDefault()); - private static final DateFormat isoDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); + private static final ThreadLocal isoDateFormat = ThreadLocal.withInitial(() -> + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")); public TbDate() { super(); @@ -73,9 +74,7 @@ public class TbDate extends Date { } public String toISOString() { - synchronized (TbDate.class) { - return isoDateFormat.format(this); - } + return isoDateFormat.get().format(this); } public String toLocaleString(String locale) { diff --git a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateTest.java b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateTest.java index 11d65e0ba7..88f1f825c1 100644 --- a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateTest.java +++ b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateTest.java @@ -25,6 +25,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import java.util.ArrayList; +import java.util.Calendar; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; @@ -32,6 +33,8 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import static org.assertj.core.api.Assertions.assertThat; + @Slf4j class TbDateTest { @@ -99,4 +102,26 @@ class TbDateTest { future.get(30, TimeUnit.SECONDS); } } -} \ No newline at end of file + + @Test + void testToISOStringThreadLocalStaticFormatter() throws ExecutionException, InterruptedException, TimeoutException { + executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1)); + long ts = 1709217342987L; //Thu Feb 29 2024 14:35:42.987 GMT+0000 + int offset = Calendar.getInstance().get(Calendar.ZONE_OFFSET); // for example 3600000 for GMT + 1 + TbDate tbDate = new TbDate(ts - offset); + String datePrefix = "2024-02-29T14:35:42.987"; //without time zone + assertThat(tbDate.toISOString()) + .as("format in main thread") + .startsWith(datePrefix); + assertThat(executor.submit(tbDate::toISOString).get(30, TimeUnit.SECONDS)) + .as("format in executor thread") + .startsWith(datePrefix); + assertThat(new TbDate(ts - offset).toISOString()) + .as("new instance format in main thread") + .startsWith(datePrefix); + assertThat(executor.submit(() -> new TbDate(ts - offset).toISOString()).get(30, TimeUnit.SECONDS)) + .as("new instance format in executor thread") + .startsWith(datePrefix); + } + +}