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 25feda75f2..089b4606f8 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 @@ -54,15 +54,20 @@ public class TbDate implements Serializable, Cloneable { this.instant = Instant.now(); } - public TbDate(String s, String... options) { - if (options.length <= 2) { - this.instant = parseInstant(s, options); - } else { - String pattern = options[0]; - String localeStr = options[1]; - String zoneIdStr = options[2]; - instant = parseInstant(s, pattern, Locale.forLanguageTag(localeStr), ZoneId.of(zoneIdStr)); - } + public TbDate(String s) { + this.instant = parseInstant(s); + } + + public TbDate(String s, String pattern) { + this.instant = parseInstant(s, pattern); + } + + public TbDate(String s, String pattern, String locale) { + this.instant = parseInstant(s, pattern, locale); + } + + public TbDate(String s, String pattern, String locale, String zoneId) { + this.instant = parseInstant(s, pattern, locale, zoneId); } public TbDate(long dateMilliSecond) { @@ -505,7 +510,8 @@ public class TbDate implements Serializable, Cloneable { } catch (Exception ex) { try { if (options.length > 0) { - return parseInstant(s, options[0], locale, ZoneId.systemDefault()); + String zoneIdStr = options.length > 3 ? options[2] : ZoneId.systemDefault().getId(); + return parseInstant(s, options[0], locale.getLanguage(), zoneIdStr); } else if (s.length() > 0 && Character.isDigit(s.charAt(0))) { long timeMS = parse(s); if (timeMS != -1) { @@ -531,10 +537,10 @@ public class TbDate implements Serializable, Cloneable { ZonedDateTime zonedDateTime = ZonedDateTime.of(year, month, date, hrs, min, second, secondMilli*1000000, zoneId); return zonedDateTime.toInstant(); } - private static Instant parseInstant(String s, String pattern, Locale locale, ZoneId zoneId) { - DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern, locale); + private static Instant parseInstant(String s, String pattern, String localeStr, String zoneIdStr) { + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern, Locale.forLanguageTag(localeStr)); LocalDateTime localDateTime = LocalDateTime.parse(s, dateTimeFormatter); - ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId); + ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of(zoneIdStr)); return zonedDateTime.toInstant(); } diff --git a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateConstructorTest.java b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateConstructorTest.java new file mode 100644 index 0000000000..2dadf6adee --- /dev/null +++ b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateConstructorTest.java @@ -0,0 +1,103 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.script.api.tbel; + +import org.junit.Assert; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mvel2.CompileException; +import org.mvel2.ExecutionContext; +import org.mvel2.ParserContext; +import org.mvel2.SandboxedParserConfiguration; + +import java.io.Serializable; +import java.util.HashMap; + +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.mvel2.MVEL.compileExpression; +import static org.mvel2.MVEL.executeTbExpression; + +public class TbDateConstructorTest { + + private static ExecutionContext executionContext; + + @BeforeAll + public static void setup() { + SandboxedParserConfiguration parserConfig = ParserContext.enableSandboxedMode(); + parserConfig.addImport("JSON", TbJson.class); + parserConfig.registerDataType("Date", TbDate.class, date -> 8L); + executionContext = new ExecutionContext(parserConfig, 5 * 1024 * 1024); + } + + + @AfterAll + public static void tearDown() { + ParserContext.disableSandboxedMode(); + } + + + @Test + void TestTbDateConstructorWithStringParameters () { + // one: date in String + String body = "var d = new Date(\"2023-08-06T04:04:05.123Z\"); \n" + + "d.toISOString()"; + Object res = executeScript(body); + Assert.assertNotEquals("2023-08-06T04:04:05.123Z".length(), res); + + // two: date in String + pattern + body = "var pattern = \"yyyy-MM-dd HH:mm:ss.SSSXXX\";\n" + + "var d = new Date(\"2023-08-06 04:04:05.000Z\", pattern);\n" + + "d.toISOString()"; + res = executeScript(body); + Assert.assertNotEquals("2023-08-06T04:04:05Z".length(), res); + + + // three: date in String + pattern + locale + body = "var pattern = \"hh:mm:ss a, EEE M/d/uuuu\";\n" + + "var d = new Date(\"02:15:30 PM, Sun 10/09/2022\", pattern, \"en-US\");" + + "d.toISOString()"; + res = executeScript(body); + Assert.assertNotEquals("2023-08-06T04:04:05Z".length(), res); + + // four: date in String + pattern + locale + TimeZone + body = "var pattern = \"hh:mm:ss a, EEE M/d/uuuu\";\n" + + "var d = new Date(\"02:15:30 PM, Sun 10/09/2022\", pattern, \"en-US\", \"America/New_York\");" + + "d.toISOString()"; + res = executeScript(body); + Assert.assertNotEquals("22022-10-09T18:15:30Z".length(), res); + } + + @Test + void TbDateConstructorWithStringParameters_PatternNotMatchLocale_Error () { + String expectedMessage = "could not create constructor: null"; + + String body = "var pattern = \"hh:mm:ss a, EEE M/d/uuuu\";\n" + + "var d = new Date(\"02:15:30 PM, Sun 10/09/2022\", pattern, \"de\");" + + "d.toISOString()"; + Exception actual = assertThrows(CompileException.class, () -> { + executeScript(body); + }); + assertTrue(actual.getMessage().contains(expectedMessage)); + + } + + private Object executeScript(String ex) { + Serializable compiled = compileExpression(ex, new ParserContext()); + return executeTbExpression(compiled, executionContext, new HashMap()); + } +}