From db4ce97621f26ebb630977e1243050d64a115263 Mon Sep 17 00:00:00 2001 From: nick Date: Fri, 29 Sep 2023 11:49:35 +0300 Subject: [PATCH 01/11] tbDate: TbDate implements InstantSource --- .../thingsboard/script/api/tbel/TbDate.java | 152 +++++++++++------- .../script/api/tbel/TbDateTest.java | 129 +++++++++++---- 2 files changed, 192 insertions(+), 89 deletions(-) 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 3f79dc2cf7..64ab9a1c76 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 @@ -15,71 +15,91 @@ */ package org.thingsboard.script.api.tbel; +import org.mvel2.ConversionException; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.StringUtils; -import java.text.DateFormat; -import java.text.SimpleDateFormat; import java.time.Instant; -import java.time.LocalDate; +import java.time.InstantSource; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.chrono.IsoChronology; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; -import java.time.temporal.ChronoUnit; -import java.time.temporal.TemporalAccessor; +import java.time.format.DateTimeParseException; +import java.util.Arrays; import java.util.Date; -import java.util.GregorianCalendar; import java.util.Locale; import java.util.function.BiFunction; -public class TbDate extends Date { +public class TbDate implements InstantSource { - 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 Instant instant; - private static final ThreadLocal isoDateFormat = ThreadLocal.withInitial(() -> - new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")); + private static String patternDefault = "%s-%s-%sT%s:%s:%s.%d%s"; + +// 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 ThreadLocal isoDateFormat = ThreadLocal.withInitial(() -> +// new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")); public TbDate() { - super(); + instant = Instant.now(); } public TbDate(String s) { - super(parse(s)); + try{ + if (s.length() > 0 && Character.isDigit(s.charAt(0))) { + // assuming UTC instant a la "2007-12-03T10:15:30.00Z" + instant = Instant.parse(s); + } + else { + // assuming RFC-1123 value a la "Tue, 3 Jun 2008 11:05:30 GMT" + instant = Instant.from(DateTimeFormatter.RFC_1123_DATE_TIME.parse(s)); + } + } catch (final DateTimeParseException ex) { + final ConversionException exception = new ConversionException("Cannot parse value [" + s + "] as instant", ex); + throw exception; + } + } + + public TbDate(long dateMilliSecond) { + instant = Instant.ofEpochMilli(dateMilliSecond); } - public TbDate(long date) { - super(date); + public TbDate(int year, int month, int date, String... tz) { + this(year, month, date, 0, 0, 0, 0, tz); } - public TbDate(int year, int month, int date) { - this(year, month, date, 0, 0, 0); + public TbDate(int year, int month, int date, int hrs, int min, String... tz) { + this(year, month, date, hrs, min, 0, 0, tz); } - public TbDate(int year, int month, int date, int hrs, int min) { - this(year, month, date, hrs, min, 0); + public TbDate(int year, int month, int date, int hrs, int min, int second, String... tz) { + this(year, month, date, hrs, min, second, 0, tz); } - public TbDate(int year, int month, int date, - int hrs, int min, int second) { - super(new GregorianCalendar(year, month, date, hrs, min, second).getTimeInMillis()); + public TbDate(int year, int month, int date, int hrs, int min, int second, int secondMilli, String... tz) { + this(createDateTimeFromPattern (year, month, date, hrs, min, second, secondMilli, tz)); + } + + @Override + public Instant instant() { + return instant; } public String toDateString() { - DateFormat formatter = DateFormat.getDateInstance(); - return formatter.format(this); + return toLocaleDateString(); } public String toTimeString() { - DateFormat formatter = DateFormat.getTimeInstance(DateFormat.LONG); - return formatter.format(this); + return toLocaleTimeString(); } public String toISOString() { - return isoDateFormat.get().format(this); + return instant.toString(); } public String toLocaleDateString() { @@ -106,9 +126,13 @@ public class TbDate extends Date { return toLocaleString(localeStr, optionsStr, (locale, options) -> DateTimeFormatter.ofLocalizedTime(options.getTimeStyle()).withLocale(locale)); } - @Override public String toLocaleString() { - return toLocaleString(null, null); + LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); + return localDateTime.toString(); + } + + public LocalDateTime getLocalDateTime() { + return LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); } public String toLocaleString(String locale) { @@ -130,7 +154,7 @@ public class TbDate extends Date { public String toLocaleString(String localeStr, String optionsStr, BiFunction formatterBuilder) { Locale locale = StringUtils.isNotEmpty(localeStr) ? Locale.forLanguageTag(localeStr) : Locale.getDefault(); DateTimeFormatOptions options = getDateFormattingOptions(optionsStr); - ZonedDateTime zdt = this.toInstant().atZone(options.getTimeZone().toZoneId()); + ZonedDateTime zdt = this.instant().atZone(options.getTimeZone().toZoneId()); DateTimeFormatter formatter; if (StringUtils.isNotEmpty(options.getPattern())) { formatter = new DateTimeFormatterBuilder().appendPattern(options.getPattern()).toFormatter(locale); @@ -159,35 +183,53 @@ public class TbDate extends Date { return System.currentTimeMillis(); } - public static long parse(String value, String format) { - try { - DateFormat dateFormat = new SimpleDateFormat(format); - return dateFormat.parse(value).getTime(); - } catch (Exception e) { - return -1; - } - } - - public static long parse(String value) { - try { - TemporalAccessor accessor = isoDateFormatter.parseBest(value, - ZonedDateTime::from, - LocalDateTime::from, - LocalDate::from); - Instant instant = Instant.from(accessor); - return Instant.EPOCH.until(instant, ChronoUnit.MILLIS); - } catch (Exception e) { - try { - return Date.parse(value); - } catch (IllegalArgumentException e2) { - return -1; - } - } - } +// public static long parse(String value, String format) { +// try { +// DateFormat dateFormat = new SimpleDateFormat(format); +// return dateFormat.parse(value).getTime(); +// } catch (Exception e) { +// return -1; +// } +// } + public static long parseSecond() { + return instant.getEpochSecond(); + } + + public static long parseSecondMilli() { + return instant.toEpochMilli(); + } + +// public static long parse(String value) { +// try { +// TemporalAccessor accessor = isoDateFormatter.parseBest(value, +// ZonedDateTime::from, +// LocalDateTime::from, +// LocalDate::from); +// Instant instant = Instant.from(accessor); +// return Instant.EPOCH.until(instant, ChronoUnit.MILLIS); +// } catch (Exception e) { +// try { +// return Date.parse(value); +// } catch (IllegalArgumentException e2) { +// return -1; +// } +// } +// } public static long UTC(int year, int month, int date, int hrs, int min, int sec) { return Date.UTC(year - 1900, month, date, hrs, min, sec); } + private static String createDateTimeFromPattern (int year, int month, int date, int hrs, int min, int second, int secondMilli, String... tz) { + String yearStr = String.format("%04d", year); + if (yearStr.substring(0, 2).equals("00")) yearStr = "20" + yearStr.substring(2,4); + String monthStr = String.format("%02d", month); + String dateStr = String.format("%02d", date); + String hrsStr = String.format("%02d", hrs); + String minStr = String.format("%02d", min); + String secondStr = String.format("%02d", second); + String tzStr = tz.length > 0 ? Arrays.stream(tz).findFirst().get() : "Z"; + return String.format(patternDefault, yearStr, monthStr, dateStr, hrsStr, minStr, secondStr, secondMilli, tzStr); + } } 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 e31641a4fe..34643a2f86 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 @@ -24,10 +24,13 @@ import lombok.extern.slf4j.Slf4j; import org.junit.Assert; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; +import org.mvel2.ConversionException; import org.thingsboard.common.util.JacksonUtil; import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.InstantSource; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.chrono.IsoChronology; @@ -46,6 +49,8 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; @Slf4j class TbDateTest { @@ -121,7 +126,7 @@ class TbDateTest { 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 + String datePrefix = "2024-02-29T12:35:42.987Z"; //without time zone assertThat(tbDate.toISOString()) .as("format in main thread") .startsWith(datePrefix); @@ -140,59 +145,63 @@ class TbDateTest { void testToLocaleDateString() { TbDate d = new TbDate(1693962245000L); + Assert.assertEquals("2023-09-06T01:04:05Z", d.instant().toString()); + Assert.assertEquals("06.09.23", d.toDateString()); + // Depends on time zone, so we just check it works; Assert.assertNotNull(d.toLocaleDateString()); Assert.assertNotNull(d.toLocaleDateString("en-US")); - Assert.assertEquals("9/5/23", d.toLocaleDateString("en-US", "America/New_York")); - Assert.assertEquals("23. 9. 5.", d.toLocaleDateString("ko-KR", "America/New_York")); - Assert.assertEquals("06.09.23", d.toLocaleDateString( "uk-UA", "Europe/Kiev")); - Assert.assertEquals("5\u200F/9\u200F/2023", d.toLocaleDateString( "ar-EG", "America/New_York")); + Assert.assertEquals("9/5/23", d.toLocaleDateString("en-US", "America/New_York")); + Assert.assertEquals("23. 9. 5.", d.toLocaleDateString("ko-KR", "America/New_York")); + Assert.assertEquals("06.09.23", d.toLocaleDateString( "uk-UA", "Europe/Kiev")); + Assert.assertEquals("5\u200F/9\u200F/2023", d.toLocaleDateString( "ar-EG", "America/New_York")); Assert.assertEquals("Tuesday, September 5, 2023", d.toLocaleDateString("en-US", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("dateStyle", "full") - .toString())); + .toString())); Assert.assertEquals("2023년 9월 5일 화요일", d.toLocaleDateString("ko-KR", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("dateStyle", "full") - .toString())); + .toString())); Assert.assertEquals("середа, 6 вересня 2023 р.", d.toLocaleDateString("uk-UA", JacksonUtil.newObjectNode() .put("timeZone", "Europe/Kiev") .put("dateStyle", "full") - .toString())); + .toString())); Assert.assertEquals("الثلاثاء، 5 سبتمبر 2023", d.toLocaleDateString("ar-EG", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("dateStyle", "full") - .toString())); + .toString())); Assert.assertEquals("Tuesday 9/5/2023", d.toLocaleDateString("en-US", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("pattern", "EEEE M/d/yyyy") - .toString())); + .toString())); Assert.assertEquals("화요일 9/5/2023", d.toLocaleDateString("ko-KR", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("pattern", "EEEE M/d/yyyy") - .toString())); + .toString())); Assert.assertEquals("середа 9/6/2023", d.toLocaleDateString("uk-UA", JacksonUtil.newObjectNode() .put("timeZone", "Europe/Kiev") .put("pattern", "EEEE M/d/yyyy") - .toString())); + .toString())); Assert.assertEquals("الثلاثاء 9/5/2023", d.toLocaleDateString("ar-EG", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("pattern", "EEEE M/d/yyyy") - .toString())); + .toString())); } @Test void testToLocaleTimeString() { TbDate d = new TbDate(1693962245000L); + Assert.assertEquals("04:04:05", d.toTimeString()); + // Depends on time zone, so we just check it works; Assert.assertNotNull(d.toLocaleTimeString()); Assert.assertNotNull(d.toLocaleTimeString("en-US")); - Assert.assertEquals("9:04:05 PM", d.toLocaleTimeString("en-US", "America/New_York")); Assert.assertEquals("오후 9:04:05", d.toLocaleTimeString("ko-KR", "America/New_York")); Assert.assertEquals("04:04:05", d.toLocaleTimeString( "uk-UA", "Europe/Kiev")); @@ -201,36 +210,36 @@ class TbDateTest { Assert.assertEquals("9:04:05 PM Eastern Daylight Time", d.toLocaleTimeString("en-US", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("timeStyle", "full") - .toString())); + .toString())); Assert.assertEquals("오후 9시 4분 5초 미 동부 하계 표준시", d.toLocaleTimeString("ko-KR", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("timeStyle", "full") - .toString())); + .toString())); Assert.assertEquals("04:04:05 за східноєвропейським літнім часом", d.toLocaleTimeString("uk-UA", JacksonUtil.newObjectNode() .put("timeZone", "Europe/Kiev") .put("timeStyle", "full") - .toString())); + .toString())); Assert.assertEquals("9:04:05 م التوقيت الصيفي الشرقي لأمريكا الشمالية", d.toLocaleTimeString("ar-EG", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("timeStyle", "full") - .toString())); + .toString())); Assert.assertEquals("9:04:05 PM", d.toLocaleTimeString("en-US", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("pattern", "h:mm:ss a") - .toString())); + .toString())); Assert.assertEquals("9:04:05 오후", d.toLocaleTimeString("ko-KR", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("pattern", "h:mm:ss a") - .toString())); + .toString())); Assert.assertEquals("4:04:05 дп", d.toLocaleTimeString("uk-UA", JacksonUtil.newObjectNode() .put("timeZone", "Europe/Kiev") .put("pattern", "h:mm:ss a") - .toString())); + .toString())); Assert.assertEquals("9:04:05 م", d.toLocaleTimeString("ar-EG", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("pattern", "h:mm:ss a") - .toString())); + .toString())); } @Test @@ -241,52 +250,104 @@ class TbDateTest { Assert.assertNotNull(d.toLocaleString()); Assert.assertNotNull(d.toLocaleString("en-US")); - Assert.assertEquals("9/5/23, 9:04:05 PM", d.toLocaleString("en-US", "America/New_York")); - Assert.assertEquals("23. 9. 5. 오후 9:04:05", d.toLocaleString("ko-KR", "America/New_York")); - Assert.assertEquals("06.09.23, 04:04:05", d.toLocaleString( "uk-UA", "Europe/Kiev")); + Assert.assertEquals("9/5/23, 9:04:05 PM", d.toLocaleString("en-US", "America/New_York")); + Assert.assertEquals("23. 9. 5. 오후 9:04:05", d.toLocaleString("ko-KR", "America/New_York")); + Assert.assertEquals("06.09.23, 04:04:05", d.toLocaleString( "uk-UA", "Europe/Kiev")); Assert.assertEquals("5\u200F/9\u200F/2023, 9:04:05 م", d.toLocaleString( "ar-EG", "America/New_York")); Assert.assertEquals("Tuesday, September 5, 2023 at 9:04:05 PM Eastern Daylight Time", d.toLocaleString("en-US", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("dateStyle", "full") .put("timeStyle", "full") - .toString())); + .toString())); Assert.assertEquals("2023년 9월 5일 화요일 오후 9시 4분 5초 미 동부 하계 표준시", d.toLocaleString("ko-KR", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("dateStyle", "full") .put("timeStyle", "full") - .toString())); + .toString())); Assert.assertEquals("середа, 6 вересня 2023 р. о 04:04:05 за східноєвропейським літнім часом", d.toLocaleString("uk-UA", JacksonUtil.newObjectNode() .put("timeZone", "Europe/Kiev") .put("dateStyle", "full") .put("timeStyle", "full") - .toString())); + .toString())); Assert.assertEquals("الثلاثاء، 5 سبتمبر 2023 في 9:04:05 م التوقيت الصيفي الشرقي لأمريكا الشمالية", d.toLocaleString("ar-EG", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("dateStyle", "full") .put("timeStyle", "full") - .toString())); + .toString())); Assert.assertEquals("9/5/2023, 9:04:05 PM", d.toLocaleString("en-US", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("pattern", "M/d/yyyy, h:mm:ss a") - .toString())); + .toString())); Assert.assertEquals("9/5/2023, 9:04:05 오후", d.toLocaleString("ko-KR", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("pattern", "M/d/yyyy, h:mm:ss a") - .toString())); + .toString())); Assert.assertEquals("9/6/2023, 4:04:05 дп", d.toLocaleString("uk-UA", JacksonUtil.newObjectNode() .put("timeZone", "Europe/Kiev") .put("pattern", "M/d/yyyy, h:mm:ss a") - .toString())); + .toString())); Assert.assertEquals("9/5/2023, 9:04:05 م", d.toLocaleString("ar-EG", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("pattern", "M/d/yyyy, h:mm:ss a") - .toString())); + .toString())); + } + + @Test + void TestFromString () { + String stringDateUTC = "2023-09-06T01:04:05.00Z"; + TbDate d = new TbDate(stringDateUTC); + Assert.assertEquals("2023-09-06T01:04:05Z", d.instant().toString()); + String stringDateTZ = "2023-09-06T01:04:05.00+04:00"; + d = new TbDate(stringDateTZ); + Assert.assertEquals("2023-09-05T21:04:05Z", d.instant().toString()); + stringDateTZ = "2023-09-06T01:04:05.00-02:00"; + d = new TbDate(stringDateTZ); + Assert.assertEquals("2023-09-06T03:04:05Z", d.instant().toString()); + String stringDateRFC_1123 = "Sat, 3 Jun 2023 11:05:30 GMT"; + d = new TbDate(stringDateRFC_1123); + Assert.assertEquals("2023-06-03T11:05:30Z", d.instant().toString()); + + String stringDateRFC_1123_error = "Tue, 3 Jun 2023 11:05:30 GMT"; + Exception exception = assertThrows(ConversionException.class, () -> { + new TbDate(stringDateRFC_1123_error); + }); + String expectedMessage = "Cannot parse value [Tue, 3 Jun 2023 11:05:30 GMT] as instant"; + String actualMessage = exception.getMessage(); + assertTrue(actualMessage.contains(expectedMessage)); + } + + @Test + void TestParse () { + String stringDateUTC = "2023-09-06T01:04:05.345Z"; + TbDate d = new TbDate(stringDateUTC); + Assert.assertEquals(1693962245345L, d.parseSecondMilli()); + Assert.assertEquals(1693962245L, d.parseSecond()); + } + + @Test + void TestDate_Year_Moth_Date_Hs_Min_Sec () { + TbDate d = new TbDate(2023, 8, 18); + Assert.assertEquals("2023-08-18T00:00:00Z", d.instant().toString()); + d = new TbDate(2023, 9, 17, 17, 34); + Assert.assertEquals("2023-09-17T17:34:00Z", d.instant().toString()); + d = new TbDate(23, 9, 7, 8, 4); + Assert.assertEquals("2023-09-07T08:04:00Z", d.instant().toString()); + d = new TbDate(23, 9, 7, 8, 4, 5); + Assert.assertEquals("2023-09-07T08:04:05Z", d.instant().toString()); + d = new TbDate(23, 9, 7, 8, 4, 5, "+04:00"); + Assert.assertEquals("2023-09-07T04:04:05Z", d.instant().toString()); + d = new TbDate(23, 9, 7, 8, 4, 5, "-03:00"); + Assert.assertEquals("2023-09-07T11:04:05Z", d.instant().toString()); + d = new TbDate(23, 9, 7, 23, 4, 5, "-03:00"); + Assert.assertEquals("2023-09-08T02:04:05Z", d.instant().toString()); + d = new TbDate(23, 9, 7, 23, 4, 5, 567,"-03:00"); + Assert.assertEquals("2023-09-08T02:04:05.567Z", d.instant().toString()); } private static String toLocalString(TbDate d, Locale locale, ZoneId tz) { - LocalDateTime ldt = d.toInstant().atZone(tz).toLocalDateTime(); + LocalDateTime ldt = d.getLocalDateTime(); // new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter(locale) From 47d1dc5fcf0d5b8a9866dfd6f08e635fed94f85f Mon Sep 17 00:00:00 2001 From: nick Date: Fri, 29 Sep 2023 11:53:38 +0300 Subject: [PATCH 02/11] tbDate: class TbDate implements InstantSource --- .../test/java/org/thingsboard/script/api/tbel/TbDateTest.java | 2 -- 1 file changed, 2 deletions(-) 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 34643a2f86..594047e1cc 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 @@ -29,8 +29,6 @@ import org.thingsboard.common.util.JacksonUtil; import java.text.DateFormat; import java.text.SimpleDateFormat; -import java.time.Instant; -import java.time.InstantSource; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.chrono.IsoChronology; From ab2976292b08c20b0b7f00338c4f2dc947b0c18e Mon Sep 17 00:00:00 2001 From: nick Date: Fri, 29 Sep 2023 17:22:36 +0300 Subject: [PATCH 03/11] tbDate: fix bug tests --- .../script/api/tbel/TbDateTest.java | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) 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 594047e1cc..c415f59508 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 @@ -121,22 +121,29 @@ class TbDateTest { @Test void testToISOStringThreadLocalStaticFormatter() throws ExecutionException, InterruptedException, TimeoutException { executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1)); + int hrs = 14; + String pattern = "2024-02-29T%s:35:42.987Z"; + String tsStr = String.format(pattern, hrs); //Thu Feb 29 2024 14:35:42.987 GMT+0000 + TbDate tbDate = new TbDate(tsStr); long ts = 1709217342987L; //Thu Feb 29 2024 14:35:42.987 GMT+0000 + Assert.assertEquals(ts, tbDate.millis()); int offset = Calendar.getInstance().get(Calendar.ZONE_OFFSET); // for example 3600000 for GMT + 1 - TbDate tbDate = new TbDate(ts - offset); - String datePrefix = "2024-02-29T12:35:42.987Z"; //without time zone + + String datePrefix = tsStr; //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); + int offsetHrs = offset/1000/60/60; + String datePrefixLocal = String.format(pattern, (hrs - offsetHrs)); assertThat(new TbDate(ts - offset).toISOString()) .as("new instance format in main thread") - .startsWith(datePrefix); + .startsWith(datePrefixLocal); assertThat(executor.submit(() -> new TbDate(ts - offset).toISOString()).get(30, TimeUnit.SECONDS)) .as("new instance format in executor thread") - .startsWith(datePrefix); + .startsWith(datePrefixLocal); } @Test @@ -144,7 +151,6 @@ class TbDateTest { TbDate d = new TbDate(1693962245000L); Assert.assertEquals("2023-09-06T01:04:05Z", d.instant().toString()); - Assert.assertEquals("06.09.23", d.toDateString()); // Depends on time zone, so we just check it works; Assert.assertNotNull(d.toLocaleDateString()); @@ -194,8 +200,6 @@ class TbDateTest { void testToLocaleTimeString() { TbDate d = new TbDate(1693962245000L); - Assert.assertEquals("04:04:05", d.toTimeString()); - // Depends on time zone, so we just check it works; Assert.assertNotNull(d.toLocaleTimeString()); Assert.assertNotNull(d.toLocaleTimeString("en-US")); @@ -306,6 +310,9 @@ class TbDateTest { String stringDateRFC_1123 = "Sat, 3 Jun 2023 11:05:30 GMT"; d = new TbDate(stringDateRFC_1123); Assert.assertEquals("2023-06-03T11:05:30Z", d.instant().toString()); + stringDateRFC_1123 = "Thu, 29 Feb 2024 11:05:30 GMT"; + d = new TbDate(stringDateRFC_1123); + Assert.assertEquals("2024-02-29T11:05:30Z", d.instant().toString()); String stringDateRFC_1123_error = "Tue, 3 Jun 2023 11:05:30 GMT"; Exception exception = assertThrows(ConversionException.class, () -> { From f3d258e60a7c688db3bb16aa3c030d8dd8c0f4e6 Mon Sep 17 00:00:00 2001 From: nick Date: Mon, 2 Oct 2023 15:32:38 +0300 Subject: [PATCH 04/11] tbDate: tests comments1 --- .../script/api/tbel/TbDateTest.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) 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 c415f59508..5115940a6b 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 @@ -150,7 +150,7 @@ class TbDateTest { void testToLocaleDateString() { TbDate d = new TbDate(1693962245000L); - Assert.assertEquals("2023-09-06T01:04:05Z", d.instant().toString()); + Assert.assertEquals("2023-09-06T01:04:05Z", d.toISOString()); // Depends on time zone, so we just check it works; Assert.assertNotNull(d.toLocaleDateString()); @@ -300,19 +300,19 @@ class TbDateTest { void TestFromString () { String stringDateUTC = "2023-09-06T01:04:05.00Z"; TbDate d = new TbDate(stringDateUTC); - Assert.assertEquals("2023-09-06T01:04:05Z", d.instant().toString()); + Assert.assertEquals("2023-09-06T01:04:05Z", d.toISOString()); String stringDateTZ = "2023-09-06T01:04:05.00+04:00"; d = new TbDate(stringDateTZ); - Assert.assertEquals("2023-09-05T21:04:05Z", d.instant().toString()); + Assert.assertEquals("2023-09-05T21:04:05Z", d.toISOString()); stringDateTZ = "2023-09-06T01:04:05.00-02:00"; d = new TbDate(stringDateTZ); - Assert.assertEquals("2023-09-06T03:04:05Z", d.instant().toString()); + Assert.assertEquals("2023-09-06T03:04:05Z", d.toISOString()); String stringDateRFC_1123 = "Sat, 3 Jun 2023 11:05:30 GMT"; d = new TbDate(stringDateRFC_1123); - Assert.assertEquals("2023-06-03T11:05:30Z", d.instant().toString()); + Assert.assertEquals("2023-06-03T11:05:30Z", d.toISOString()); stringDateRFC_1123 = "Thu, 29 Feb 2024 11:05:30 GMT"; d = new TbDate(stringDateRFC_1123); - Assert.assertEquals("2024-02-29T11:05:30Z", d.instant().toString()); + Assert.assertEquals("2024-02-29T11:05:30Z", d.toISOString()); String stringDateRFC_1123_error = "Tue, 3 Jun 2023 11:05:30 GMT"; Exception exception = assertThrows(ConversionException.class, () -> { @@ -334,21 +334,21 @@ class TbDateTest { @Test void TestDate_Year_Moth_Date_Hs_Min_Sec () { TbDate d = new TbDate(2023, 8, 18); - Assert.assertEquals("2023-08-18T00:00:00Z", d.instant().toString()); + Assert.assertEquals("2023-08-18T00:00:00Z", d.toISOString()); d = new TbDate(2023, 9, 17, 17, 34); - Assert.assertEquals("2023-09-17T17:34:00Z", d.instant().toString()); + Assert.assertEquals("2023-09-17T17:34:00Z", d.toISOString()); d = new TbDate(23, 9, 7, 8, 4); - Assert.assertEquals("2023-09-07T08:04:00Z", d.instant().toString()); + Assert.assertEquals("2023-09-07T08:04:00Z", d.toISOString()); d = new TbDate(23, 9, 7, 8, 4, 5); - Assert.assertEquals("2023-09-07T08:04:05Z", d.instant().toString()); + Assert.assertEquals("2023-09-07T08:04:05Z", d.toISOString()); d = new TbDate(23, 9, 7, 8, 4, 5, "+04:00"); - Assert.assertEquals("2023-09-07T04:04:05Z", d.instant().toString()); + Assert.assertEquals("2023-09-07T04:04:05Z", d.toISOString()); d = new TbDate(23, 9, 7, 8, 4, 5, "-03:00"); - Assert.assertEquals("2023-09-07T11:04:05Z", d.instant().toString()); + Assert.assertEquals("2023-09-07T11:04:05Z", d.toISOString()); d = new TbDate(23, 9, 7, 23, 4, 5, "-03:00"); - Assert.assertEquals("2023-09-08T02:04:05Z", d.instant().toString()); + Assert.assertEquals("2023-09-08T02:04:05Z", d.toISOString()); d = new TbDate(23, 9, 7, 23, 4, 5, 567,"-03:00"); - Assert.assertEquals("2023-09-08T02:04:05.567Z", d.instant().toString()); + Assert.assertEquals("2023-09-08T02:04:05.567Z", d.toISOString()); } private static String toLocalString(TbDate d, Locale locale, ZoneId tz) { From 73f8a7f537909e5d5d6912e61ee8792aa652ab49 Mon Sep 17 00:00:00 2001 From: nick Date: Mon, 2 Oct 2023 15:46:58 +0300 Subject: [PATCH 05/11] tbDate: tests comments12 --- .../thingsboard/script/api/tbel/TbDate.java | 31 ----------------- .../thingsboard/script/api/tbel/TbUtils.java | 33 +++++++++++++++++++ 2 files changed, 33 insertions(+), 31 deletions(-) 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 64ab9a1c76..42c5a228cf 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 @@ -39,12 +39,6 @@ public class TbDate implements InstantSource { private static String patternDefault = "%s-%s-%sT%s:%s:%s.%d%s"; -// 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 ThreadLocal isoDateFormat = ThreadLocal.withInitial(() -> -// new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")); - public TbDate() { instant = Instant.now(); } @@ -183,14 +177,6 @@ public class TbDate implements InstantSource { return System.currentTimeMillis(); } -// public static long parse(String value, String format) { -// try { -// DateFormat dateFormat = new SimpleDateFormat(format); -// return dateFormat.parse(value).getTime(); -// } catch (Exception e) { -// return -1; -// } -// } public static long parseSecond() { return instant.getEpochSecond(); } @@ -199,23 +185,6 @@ public class TbDate implements InstantSource { return instant.toEpochMilli(); } -// public static long parse(String value) { -// try { -// TemporalAccessor accessor = isoDateFormatter.parseBest(value, -// ZonedDateTime::from, -// LocalDateTime::from, -// LocalDate::from); -// Instant instant = Instant.from(accessor); -// return Instant.EPOCH.until(instant, ChronoUnit.MILLIS); -// } catch (Exception e) { -// try { -// return Date.parse(value); -// } catch (IllegalArgumentException e2) { -// return -1; -// } -// } -// } - public static long UTC(int year, int month, int date, int hrs, int min, int sec) { return Date.UTC(year - 1900, month, date, hrs, min, sec); diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java index bd14871fe2..1e71795f97 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java @@ -32,6 +32,16 @@ import java.math.RoundingMode; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.time.temporal.TemporalAccessor; import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; @@ -649,4 +659,27 @@ public class TbUtils { return true; } + public static long parse(String value, String format) { + try { + DateFormat dateFormat = new SimpleDateFormat(format); + return dateFormat.parse(value).getTime(); + } catch (Exception e) { + return -1; + } + } + public static long parse(String value) { + DateTimeFormatter isoDateFormatter = DateTimeFormatter.ofPattern( + "yyyy-MM-dd[[ ]['T']HH:mm[:ss[.SSS]][ ][XXX][Z][z][VV][O]]").withZone(ZoneId.systemDefault()); + try { + TemporalAccessor accessor = isoDateFormatter.parseBest(value, + ZonedDateTime::from, + LocalDateTime::from, + LocalDate::from); + Instant instant = Instant.from(accessor); + return Instant.EPOCH.until(instant, ChronoUnit.MILLIS); + } catch (Exception e) { + return -1; + } + } + } From 42e5f063a4857d4b4a9489bef5161a476c4b7570 Mon Sep 17 00:00:00 2001 From: nick Date: Fri, 6 Oct 2023 10:52:36 +0300 Subject: [PATCH 06/11] tbDate: tests add method as Date JS --- .../thingsboard/script/api/tbel/TbDate.java | 374 ++++++++++++++++-- .../thingsboard/script/api/tbel/TbUtils.java | 25 +- .../script/api/tbel/TbDateTest.java | 371 +++++++++++++++-- 3 files changed, 665 insertions(+), 105 deletions(-) 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 42c5a228cf..0dba460686 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 @@ -19,8 +19,11 @@ import org.mvel2.ConversionException; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.StringUtils; +import java.io.Serializable; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.time.Instant; -import java.time.InstantSource; +import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; @@ -28,39 +31,47 @@ import java.time.chrono.IsoChronology; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoUnit; +import java.time.temporal.TemporalAccessor; import java.util.Arrays; -import java.util.Date; import java.util.Locale; import java.util.function.BiFunction; -public class TbDate implements InstantSource { +public class TbDate implements Serializable, Cloneable { - private static Instant instant; + private Instant instant; + private ZonedDateTime zonedDateTime; + private LocalDateTime localDateTime; + private final ZoneId zoneIdUTC = ZoneId.of("UTC"); - private static String patternDefault = "%s-%s-%sT%s:%s:%s.%d%s"; + private static String patternDefault = "%s-%s-%sT%s:%s:%s.%s%s"; public TbDate() { - instant = Instant.now(); + this.instant = Instant.now(); + initZonedLocalDateTime(); } public TbDate(String s) { - try{ - if (s.length() > 0 && Character.isDigit(s.charAt(0))) { - // assuming UTC instant a la "2007-12-03T10:15:30.00Z" - instant = Instant.parse(s); - } - else { - // assuming RFC-1123 value a la "Tue, 3 Jun 2008 11:05:30 GMT" - instant = Instant.from(DateTimeFormatter.RFC_1123_DATE_TIME.parse(s)); - } - } catch (final DateTimeParseException ex) { - final ConversionException exception = new ConversionException("Cannot parse value [" + s + "] as instant", ex); - throw exception; - } + parseInstant(s); + } + + /** + * String s = "09:15:30 PM, Sun 10/09/2022"; + * String pattern = "hh:mm:ss a, EEE M/d/uuuu"; + * @param s + * @param pattern + */ + public TbDate(String s, String pattern, Locale locale) { + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern, locale); + LocalDateTime localDateTime = LocalDateTime.parse(s, dateTimeFormatter); + ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault()); + instant = zonedDateTime.toInstant(); + initZonedLocalDateTime(); } public TbDate(long dateMilliSecond) { instant = Instant.ofEpochMilli(dateMilliSecond); + initZonedLocalDateTime(); } public TbDate(int year, int month, int date, String... tz) { @@ -76,25 +87,75 @@ public class TbDate implements InstantSource { } public TbDate(int year, int month, int date, int hrs, int min, int second, int secondMilli, String... tz) { - this(createDateTimeFromPattern (year, month, date, hrs, min, second, secondMilli, tz)); + this(createDateTimeFromPattern(year, month, date, hrs, min, second, secondMilli, tz)); } - @Override - public Instant instant() { + public Instant getInstant() { return instant; } - public String toDateString() { - return toLocaleDateString(); + public void setInstant(Instant instant) { + this.instant = instant; + } + public ZonedDateTime getZonedDateTime() { + return zonedDateTime; } - public String toTimeString() { - return toLocaleTimeString(); + private void initZonedLocalDateTime() { + setZonedDateTime(zoneIdUTC); + setLocalDateTime(); + } + public void setZonedDateTime(ZoneId z) { + this.zonedDateTime = instant.atZone(z);; + } + + public void setLocalDateTime() { + this.localDateTime = LocalDateTime.ofInstant(this.getInstant(), ZoneId.systemDefault()); + } + public LocalDateTime getLocalDateTime() { + return this.localDateTime ; } + public String toDateString() { + return toLocaleDateString("UTC", JacksonUtil.newObjectNode().put("dateStyle", "full").toString()); + } + public String toDateString(String locale) { + return toLocaleDateString(locale, JacksonUtil.newObjectNode().put("dateStyle", "full").toString()); + } + public String toTimeString() { + return toLocaleTimeString("UTC", JacksonUtil.newObjectNode().put("timeStyle", "full").toString()); + } + public String toTimeString(String locale) { + return toLocaleTimeString(locale, JacksonUtil.newObjectNode().put("timeStyle", "full").toString()); + } + /** + * "2011-10-05T14:48:00.000Z" + * @return + */ public String toISOString() { return instant.toString(); } + public String toJSON() { + return toISOString(); + } + public String toUTCString() { + return toLocaleString("UTC", JacksonUtil.newObjectNode().put("dateStyle", "full").put("timeStyle", "medium").toString()); + } + + public String toUTCString(String locale) { + return toLocaleString(locale, JacksonUtil.newObjectNode().put("dateStyle", "full").put("timeStyle", "medium").toString()); + } + + /** + * "Tue Aug 19 1975 23:15:30 GMT+0300 (за східноєвропейським стандартним часом)" + * @return + */ + public String toString() { + return toLocaleString(Locale.getDefault().toString(), JacksonUtil.newObjectNode().put("dateStyle", "full").put("timeStyle", "full").toString()); + } + public String toString(String locale) { + return toLocaleString(locale, JacksonUtil.newObjectNode().put("dateStyle", "full").put("timeStyle", "full").toString()); + } public String toLocaleDateString() { return toLocaleDateString(null, null); @@ -125,10 +186,6 @@ public class TbDate implements InstantSource { return localDateTime.toString(); } - public LocalDateTime getLocalDateTime() { - return LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); - } - public String toLocaleString(String locale) { return toLocaleString(locale, null); } @@ -148,7 +205,7 @@ public class TbDate implements InstantSource { public String toLocaleString(String localeStr, String optionsStr, BiFunction formatterBuilder) { Locale locale = StringUtils.isNotEmpty(localeStr) ? Locale.forLanguageTag(localeStr) : Locale.getDefault(); DateTimeFormatOptions options = getDateFormattingOptions(optionsStr); - ZonedDateTime zdt = this.instant().atZone(options.getTimeZone().toZoneId()); + ZonedDateTime zdt = this.getInstant().atZone(options.getTimeZone().toZoneId()); DateTimeFormatter formatter; if (StringUtils.isNotEmpty(options.getPattern())) { formatter = new DateTimeFormatterBuilder().appendPattern(options.getPattern()).toFormatter(locale); @@ -158,7 +215,7 @@ public class TbDate implements InstantSource { return formatter.format(zdt); } - private static DateTimeFormatOptions getDateFormattingOptions(String options) { + private DateTimeFormatOptions getDateFormattingOptions(String options) { DateTimeFormatOptions opt = null; if (StringUtils.isNotEmpty(options)) { try { @@ -173,32 +230,265 @@ public class TbDate implements InstantSource { return opt; } - public static long now() { - return System.currentTimeMillis(); + public long now() { + return Instant.now().toEpochMilli(); } - public static long parseSecond() { + public long parseSecond() { return instant.getEpochSecond(); } - public static long parseSecondMilli() { + public long parseSecondMilli() { + return instant.toEpochMilli(); + } + + public static long UTC(int year) { + return UTC(year, 0, 0, 0, 0, 0, 0); + } + public static long UTC(int year, int month) { + return UTC(year, month, 0, 0, 0, 0, 0); + } + public static long UTC(int year, int month, int date) { + return UTC(year, month, date, 0, 0, 0, 0); + } + public static long UTC(int year, int month, int date, int hrs) { + return UTC(year, month, date, hrs, 0, 0, 0); + } + public static long UTC(int year, int month, int date, int hrs, int min) { + return UTC(year, month, date, hrs, min, 0, 0); + } + public static long UTC(int year, int month, int date, int hrs, int min, int sec) { + return UTC(year, month, date, hrs, min, sec, 0); + } + public static long UTC(int year, int month, int date, int hrs, int min, int sec, int ms) { + year = year == 0 ? year = 1899 : year; + month = month == 0 ? month = 12 : month; + date = date == 0 ? date = 31 : date; + return Instant.parse(createDateTimeFromPattern (year, month, date, hrs, min, sec, ms)).toEpochMilli(); + } + public int getUTCFullYear() { + return zonedDateTime.getYear(); + } + + public int getUTCMonth() { + return zonedDateTime.getMonthValue(); + } + // day in month + public int getUTCDate() { + return zonedDateTime.getDayOfMonth(); + } + // day in week + public int getUTCDay() { + return zonedDateTime.getDayOfWeek().getValue(); + } + + public int getUTCHours() { + return zonedDateTime.getHour(); + } + + public int getUTCMinutes() { + return zonedDateTime.getMinute(); + } + + public int getUTCSeconds() { + return zonedDateTime.getSecond(); + } + public int getUTCMilliseconds() { + return zonedDateTime.getNano()/1000000; + } + + public void setUTCFullYear(int year) { + parseInstant(createDateTimeFromPattern(year, getUTCMonth(), getUTCDate(), getUTCHours(), getUTCMinutes(), getUTCSeconds(), getUTCMilliseconds())); + } + public void setUTCFullYear(int year, int month) { + parseInstant(createDateTimeFromPattern(year, month, getUTCDate(), getUTCHours(), getUTCMinutes(), getUTCSeconds(), getUTCMilliseconds())); + } + public void setUTCFullYear(int year, int month, int date) { + parseInstant(createDateTimeFromPattern(year, month, date, getUTCHours(), getUTCMinutes(), getUTCSeconds(), getUTCMilliseconds())); + } + public void setUTCMonth(int month) { + parseInstant(createDateTimeFromPattern(getUTCFullYear(), month, getUTCDate(), getUTCHours(), getUTCMinutes(), getUTCSeconds(), getUTCMilliseconds())); + } + public void setUTCMonth(int month, int date) { + parseInstant(createDateTimeFromPattern(getUTCFullYear(), month, date, getUTCHours(), getUTCMinutes(), getUTCSeconds(), getUTCMilliseconds())); + } + public void setUTCDate(int date) { + parseInstant(createDateTimeFromPattern(getUTCFullYear(), getUTCMonth(), date, getUTCHours(), getUTCMinutes(), getUTCSeconds(), getUTCMilliseconds())); + } + public void setUTCHours(int hrs) { + parseInstant(createDateTimeFromPattern(getUTCFullYear(), getUTCMonth(), getUTCDate(), hrs, getUTCMinutes(), getUTCSeconds(), getUTCMilliseconds())); + } + public void setUTCHours(int hrs, int minutes) { + parseInstant(createDateTimeFromPattern(getUTCFullYear(), getUTCMonth(), getUTCDate(), hrs, minutes, getUTCSeconds(), getUTCMilliseconds())); + } + public void setUTCHours(int hrs, int minutes, int seconds) { + parseInstant(createDateTimeFromPattern(getUTCFullYear(), getUTCMonth(), getUTCDate(), hrs, minutes, seconds, getUTCMilliseconds())); + } + public void setUTCHours(int hrs, int minutes, int seconds, int ms) { + parseInstant(createDateTimeFromPattern(getUTCFullYear(), getUTCMonth(), getUTCDate(), hrs, minutes, seconds, ms)); + } + public void setUTCMinutes(int minutes) { + parseInstant(createDateTimeFromPattern(getUTCFullYear(), getUTCMonth(), getUTCDate(), getUTCHours(), minutes, getUTCSeconds(), getUTCMilliseconds())); + } + public void setUTCMinutes(int minutes, int seconds) { + parseInstant(createDateTimeFromPattern(getUTCFullYear(), getUTCMonth(), getUTCDate(), getUTCHours(), minutes, seconds, getUTCMilliseconds())); + } + public void setUTCMinutes(int minutes, int seconds, int ms) { + parseInstant(createDateTimeFromPattern(getUTCFullYear(), getUTCMonth(), getUTCDate(), getUTCHours(), minutes, seconds, ms)); + } + public void setUTCSeconds(int seconds) { + parseInstant(createDateTimeFromPattern(getUTCFullYear(), getUTCMonth(), getUTCDate(), getUTCHours(), getUTCMinutes(), seconds, getUTCMilliseconds())); + } + public void setUTCSeconds(int seconds, int ms) { + parseInstant(createDateTimeFromPattern(getUTCFullYear(), getUTCMonth(), getUTCDate(), getUTCHours(), getUTCMinutes(), seconds, ms)); + } + public void setUTCMilliseconds(int ms) { + parseInstant(createDateTimeFromPattern(getUTCFullYear(), getUTCMonth(), getUTCDate(), getUTCHours(), getUTCMinutes(), getUTCSeconds(), ms)); + } + public int getFullYear() { + return localDateTime.getYear(); + } + + public int getMonth() { + return localDateTime.getMonthValue(); + } + // day in month + public int getDate() { + return localDateTime.getDayOfMonth(); + } + // day in week + public int getDay() { + return localDateTime.getDayOfWeek().getValue(); + } + + public int getHours() { + return localDateTime.getHour(); + } + + public int getMinutes() { + return localDateTime.getMinute(); + } + + public int getSeconds() { + return localDateTime.getSecond(); + } + public int getMilliseconds() { + return localDateTime.getNano()/1000000; + } + // Milliseconds since Jan 1, 1970, 00:00:00.000 GMT + public long getTime() { return instant.toEpochMilli(); } + public long valueOf(){ + return getTime() ; + } + public void setFullYear(int year) { + setUTCFullYear(year); + } + public void setFullYear(int year, int month) { + setUTCFullYear(year, month); + } public void setFullYear(int year, int month, int date) { + setUTCFullYear(year, month, date); + } + public void setMonth(int month) { + setUTCMonth(month); + } + public void setMonth(int month, int date) { + setUTCMonth(month, date) ; + } + public void setDate(int date) { + setUTCDate(date); + } + public void setHours(int hrs) { + setUTCHours(hrs); + } + public void setHours(int hrs, int minutes) { + setUTCHours(hrs, minutes); + } + public void setHours(int hrs, int minutes, int seconds) { + setUTCHours(hrs, minutes, seconds); + } + public void setHours(int hrs, int minutes, int seconds, int ms) { + setUTCHours(hrs, minutes, seconds, ms); + } + public void setMinutes(int minutes) { + setUTCMinutes(minutes); + } + public void setMinutes(int minutes, int seconds) { + setUTCMinutes(minutes, seconds); + } + public void setMinutes(int minutes, int seconds, int ms) { + setUTCMinutes(minutes, seconds, ms); + } + public void setSeconds(int seconds) { + setUTCSeconds(seconds); + } + public void setSeconds(int seconds, int ms) { + setUTCSeconds(seconds, ms); + } + public void setMilliseconds(int ms) { + setUTCMilliseconds(ms); + } - public static long UTC(int year, int month, int date, - int hrs, int min, int sec) { - return Date.UTC(year - 1900, month, date, hrs, min, sec); + // Milliseconds since Jan 1, 1970, 00:00:00.000 GMT + public void setTime(long dateMilliSecond) { + instant = Instant.ofEpochMilli(dateMilliSecond); + initZonedLocalDateTime(); + } + public int getTimezoneOffset() { + int seconds = ZoneId.systemDefault().getRules().getOffset(instant).getTotalSeconds(); + return -seconds/60; } - private static String createDateTimeFromPattern (int year, int month, int date, int hrs, int min, int second, int secondMilli, String... tz) { + public static long parse(String value, String format) { + try { + DateFormat dateFormat = new SimpleDateFormat(format); + return dateFormat.parse(value).getTime(); + } catch (Exception e) { + return -1; + } + } + public static long parse(String value) { + DateTimeFormatter isoDateFormatter = DateTimeFormatter.ofPattern( + "yyyy-MM-dd[[ ]['T']HH:mm[:ss[.SSS]][ ][XXX][Z][z][VV][O]]").withZone(ZoneId.systemDefault()); + try { + TemporalAccessor accessor = isoDateFormatter.parseBest(value, + ZonedDateTime::from, + LocalDateTime::from, + LocalDate::from); + Instant instant = Instant.from(accessor); + return Instant.EPOCH.until(instant, ChronoUnit.MILLIS); + } catch (Exception e) { + return -1; + } + } + private static String createDateTimeFromPattern(int year, int month, int date, int hrs, int min, int second, int secondMilli, String... tz) { String yearStr = String.format("%04d", year); - if (yearStr.substring(0, 2).equals("00")) yearStr = "20" + yearStr.substring(2,4); + yearStr = yearStr.substring(0, 2).equals("00") ? year < 70 ? "20" + yearStr.substring(2,4) : "19" + yearStr.substring(2,4) : yearStr; String monthStr = String.format("%02d", month); String dateStr = String.format("%02d", date); String hrsStr = String.format("%02d", hrs); String minStr = String.format("%02d", min); String secondStr = String.format("%02d", second); + String secondMilliStr = String.format("%03d", secondMilli); String tzStr = tz.length > 0 ? Arrays.stream(tz).findFirst().get() : "Z"; - return String.format(patternDefault, yearStr, monthStr, dateStr, hrsStr, minStr, secondStr, secondMilli, tzStr); + return String.format(patternDefault, yearStr, monthStr, dateStr, hrsStr, minStr, secondStr, secondMilliStr, tzStr); + } + + private void parseInstant(String s) { + try{ + if (s.length() > 0 && Character.isDigit(s.charAt(0))) { + // assuming UTC instant "2007-12-03T10:15:30.00Z" + instant = Instant.parse(s); + } + else { + // assuming RFC-1123 value "Tue, 3 Jun 2008 11:05:30 GMT-02:00" + instant = Instant.from(DateTimeFormatter.RFC_1123_DATE_TIME.parse(s)); + } + initZonedLocalDateTime(); + } catch (final DateTimeParseException ex) { + final ConversionException exception = new ConversionException("Cannot parse value [" + s + "] as instant", ex); + throw exception; + } } } diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java index 1e71795f97..3c803f1eff 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java @@ -658,28 +658,5 @@ public class TbUtils { } return true; } - - public static long parse(String value, String format) { - try { - DateFormat dateFormat = new SimpleDateFormat(format); - return dateFormat.parse(value).getTime(); - } catch (Exception e) { - return -1; - } - } - public static long parse(String value) { - DateTimeFormatter isoDateFormatter = DateTimeFormatter.ofPattern( - "yyyy-MM-dd[[ ]['T']HH:mm[:ss[.SSS]][ ][XXX][Z][z][VV][O]]").withZone(ZoneId.systemDefault()); - try { - TemporalAccessor accessor = isoDateFormatter.parseBest(value, - ZonedDateTime::from, - LocalDateTime::from, - LocalDate::from); - Instant instant = Instant.from(accessor); - return Instant.EPOCH.until(instant, ChronoUnit.MILLIS); - } catch (Exception e) { - return -1; - } - } - } + 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 5115940a6b..75027247b1 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 @@ -27,19 +27,10 @@ import org.junit.jupiter.api.Test; import org.mvel2.ConversionException; import org.thingsboard.common.util.JacksonUtil; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.time.chrono.IsoChronology; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatterBuilder; -import java.time.format.FormatStyle; +import java.time.format.DateTimeParseException; import java.util.ArrayList; -import java.util.Calendar; import java.util.List; import java.util.Locale; -import java.util.TimeZone; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; @@ -126,8 +117,8 @@ class TbDateTest { String tsStr = String.format(pattern, hrs); //Thu Feb 29 2024 14:35:42.987 GMT+0000 TbDate tbDate = new TbDate(tsStr); long ts = 1709217342987L; //Thu Feb 29 2024 14:35:42.987 GMT+0000 - Assert.assertEquals(ts, tbDate.millis()); - int offset = Calendar.getInstance().get(Calendar.ZONE_OFFSET); // for example 3600000 for GMT + 1 + Assert.assertEquals(ts, tbDate.parseSecondMilli()); + int offsetMin = tbDate.getTimezoneOffset(); // for example 3600000 for GMT + 1 String datePrefix = tsStr; //without time zone assertThat(tbDate.toISOString()) @@ -136,20 +127,29 @@ class TbDateTest { assertThat(executor.submit(tbDate::toISOString).get(30, TimeUnit.SECONDS)) .as("format in executor thread") .startsWith(datePrefix); - int offsetHrs = offset/1000/60/60; + int offsetHrs = offsetMin/60; String datePrefixLocal = String.format(pattern, (hrs - offsetHrs)); - assertThat(new TbDate(ts - offset).toISOString()) + long offsetMilli = offsetMin*60*1000; + assertThat(new TbDate(ts - offsetMilli).toISOString()) .as("new instance format in main thread") .startsWith(datePrefixLocal); - assertThat(executor.submit(() -> new TbDate(ts - offset).toISOString()).get(30, TimeUnit.SECONDS)) + assertThat(executor.submit(() -> new TbDate(ts - offsetMilli).toISOString()).get(30, TimeUnit.SECONDS)) .as("new instance format in executor thread") .startsWith(datePrefixLocal); } @Test void testToLocaleDateString() { - TbDate d = new TbDate(1693962245000L); - + String s = "09:15:30 PM, Sun 10/09/2022"; + String pattern = "hh:mm:ss a, EEE M/d/uuuu"; + TbDate d = new TbDate(s, pattern, Locale.US); + Assert.assertEquals("2022-10-09T18:15:30Z", d.toISOString()); + s = "09:15:30 пп, середа, 4 жовтня 2023 р."; + pattern = "hh:mm:ss a, EEEE, d MMMM y 'р.'"; + d = new TbDate(s, pattern, Locale.forLanguageTag("uk-UA")); + Assert.assertEquals("2023-10-04T18:15:30Z", d.toISOString()); + + d = new TbDate(1693962245000L); Assert.assertEquals("2023-09-06T01:04:05Z", d.toISOString()); // Depends on time zone, so we just check it works; @@ -309,18 +309,19 @@ class TbDateTest { Assert.assertEquals("2023-09-06T03:04:05Z", d.toISOString()); String stringDateRFC_1123 = "Sat, 3 Jun 2023 11:05:30 GMT"; d = new TbDate(stringDateRFC_1123); - Assert.assertEquals("2023-06-03T11:05:30Z", d.toISOString()); - stringDateRFC_1123 = "Thu, 29 Feb 2024 11:05:30 GMT"; + stringDateRFC_1123 = "Sat, 3 Jun 2023 11:05:30 +0400"; + d = new TbDate(stringDateRFC_1123); + Assert.assertEquals("2023-06-03T07:05:30Z", d.toISOString()); + stringDateRFC_1123 = "Thu, 29 Feb 2024 11:05:30 -03"; d = new TbDate(stringDateRFC_1123); - Assert.assertEquals("2024-02-29T11:05:30Z", d.toISOString()); + Assert.assertEquals("2024-02-29T14:05:30Z", d.toISOString()); String stringDateRFC_1123_error = "Tue, 3 Jun 2023 11:05:30 GMT"; - Exception exception = assertThrows(ConversionException.class, () -> { + Exception actual = assertThrows(ConversionException.class, () -> { new TbDate(stringDateRFC_1123_error); }); - String expectedMessage = "Cannot parse value [Tue, 3 Jun 2023 11:05:30 GMT] as instant"; - String actualMessage = exception.getMessage(); - assertTrue(actualMessage.contains(expectedMessage)); + String expectedMessage = "Cannot parse value"; + assertTrue(actual.getMessage().contains(expectedMessage)); } @Test @@ -329,6 +330,13 @@ class TbDateTest { TbDate d = new TbDate(stringDateUTC); Assert.assertEquals(1693962245345L, d.parseSecondMilli()); Assert.assertEquals(1693962245L, d.parseSecond()); + String stringDateStart = "1970-01-01T00:00:00Z"; + d = new TbDate(stringDateStart); + long actualMillis = TbDate.parse("1970-01-01 T00:00:00"); + Assert.assertEquals(d.getTimezoneOffset(), actualMillis/60/1000); + String pattern = "yyyy-MM-dd HH:mm:ss.SSS"; + String stringDate = "1995-12-04 00:12:00.000"; + Assert.assertNotEquals(-1L, TbDate.parse(stringDate, pattern)); } @Test @@ -351,25 +359,310 @@ class TbDateTest { Assert.assertEquals("2023-09-08T02:04:05.567Z", d.toISOString()); } - private static String toLocalString(TbDate d, Locale locale, ZoneId tz) { - LocalDateTime ldt = d.getLocalDateTime(); + @Test + void TestMethodGetAsDateUTC () { + TbDate dd = new TbDate(TbDate.UTC(1996, 2, 2, 3, 4, 5)); + Assert.assertEquals(823230245000L, dd.valueOf()); + dd = new TbDate(1996, 2, 2, 3, 4, 5); + Assert.assertEquals(823230245000L, dd.valueOf()); + TbDate beforeStartUTC = new TbDate(1969, 7, 20, 20, 17, 40); + Assert.assertEquals(-14182940000L, beforeStartUTC.getTime()); + + TbDate d1 = new TbDate(1975, 12, 31, 23,15,30, 567,"+02:00"); + TbDate d2 = new TbDate(1975, 12, 31, 23,15,30, 567,"-02:00"); + + Assert.assertEquals(189292530567L, d1.getTime()); + Assert.assertEquals(189306930567L, d2.getTime()); + Assert.assertEquals(d1.getTimezoneOffset(), d2.getTimezoneOffset()); + + Assert.assertEquals(1975, d1.getUTCFullYear()); + Assert.assertEquals(1976, d2.getUTCFullYear()); + + Assert.assertEquals(12, d1.getUTCMonth()); + Assert.assertEquals(1, d2.getUTCMonth()); + + Assert.assertEquals(31, d1.getUTCDate()); + Assert.assertEquals(1, d2.getUTCDate()); + + Assert.assertEquals(3, d1.getUTCDay()); + Assert.assertEquals(4, d2.getUTCDay()); + + Assert.assertEquals(21, d1.getUTCHours()); + Assert.assertEquals(1, d2.getUTCHours()); + + Assert.assertEquals(15, d1.getUTCMinutes()); + Assert.assertEquals(15, d2.getUTCMinutes()); + + Assert.assertEquals(30, d1.getUTCSeconds()); + Assert.assertEquals(30, d2.getUTCSeconds()); + + Assert.assertEquals(567, d1.getUTCMilliseconds()); + Assert.assertEquals(567, d2.getUTCMilliseconds()); + } @Test + void TestMethodGetAsDateLocal () { + TbDate d1 = new TbDate(1975, 12, 31, 23,15,30, 567,"+02:00"); + TbDate d2 = new TbDate(1975, 12, 31, 23,15,30, 567,"-02:00"); + TbDate dLocal1 = new TbDate(d1.parseSecondMilli()-d1.getTimezoneOffset()*60*1000); + TbDate dLocal2 = new TbDate(d2.parseSecondMilli()-d2.getTimezoneOffset()*60*1000); + + Assert.assertEquals(dLocal1.getUTCFullYear(), d1.getFullYear()); + Assert.assertEquals(dLocal2.getUTCFullYear(), d2.getFullYear()); + + Assert.assertEquals(dLocal1.getUTCMonth(), d1.getMonth()); + Assert.assertEquals(dLocal2.getUTCMonth(), d2.getMonth()); + + Assert.assertEquals(dLocal1.getUTCDate(), d1.getDate()); + Assert.assertEquals(dLocal2.getUTCDate(), d2.getDate()); + + Assert.assertEquals(dLocal1.getUTCDay(), d1.getDay()); + Assert.assertEquals(dLocal1.getUTCDay(), d2.getDay()); + + Assert.assertEquals(dLocal1.getUTCHours(), d1.getHours()); + Assert.assertEquals(dLocal2.getUTCHours(), d2.getHours()); + + Assert.assertEquals(dLocal1.getUTCMinutes(), d1.getMinutes()); + Assert.assertEquals(dLocal2.getUTCMinutes(), d2.getMinutes()); -// new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter(locale) + Assert.assertEquals(dLocal1.getUTCSeconds(), d1.getSeconds()); + Assert.assertEquals(dLocal2.getUTCSeconds(), d2.getSeconds()); - String formatPattern = - DateTimeFormatterBuilder.getLocalizedDateTimePattern( - FormatStyle.SHORT, - FormatStyle.MEDIUM, - IsoChronology.INSTANCE, - locale); - DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatPattern, locale); - return formatter.format(ldt); + Assert.assertEquals(dLocal1.getUTCMilliseconds(), d1.getMilliseconds()); + Assert.assertEquals(dLocal2.getUTCMilliseconds(), d2.getMilliseconds()); } - private static String toLocalString2(TbDate d, Locale locale, ZoneId tz) { - DateFormat dateFormat = SimpleDateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale); - dateFormat.setTimeZone(TimeZone.getTimeZone(tz)); - return dateFormat.format(d); + @Test + void TestMethodSetUTCFullYearMonthDate() { + TbDate d1 = new TbDate(1975, 12, 31, 23,15,30, 567,"-03:00"); + Assert.assertEquals(1976, d1.getUTCFullYear()); + Assert.assertEquals(4, d1.getUTCDay()); + d1.setUTCFullYear(1969); + Assert.assertEquals(1969, d1.getUTCFullYear()); + d1.setUTCFullYear(1975); + Assert.assertEquals(1975, d1.getUTCFullYear()); + Assert.assertEquals(3, d1.getUTCDay()); + d1.setUTCFullYear(1977, 4); + Assert.assertEquals(1977, d1.getUTCFullYear()); + Assert.assertEquals(4, d1.getUTCMonth()); + Assert.assertEquals(5, d1.getUTCDay()); + d1.setUTCFullYear(2023, 2, 24); + Assert.assertEquals(2023, d1.getUTCFullYear()); + Assert.assertEquals(2, d1.getUTCMonth()); + Assert.assertEquals(24, d1.getUTCDate()); + Assert.assertEquals(5, d1.getUTCDay()); + + d1.setUTCMonth(11); + Assert.assertEquals(11, d1.getUTCMonth()); + Assert.assertEquals(5, d1.getUTCDay()); + d1.setUTCMonth(2, 28); + Assert.assertEquals(2, d1.getUTCMonth()); + Assert.assertEquals(28, d1.getUTCDate()); + Assert.assertEquals(2, d1.getUTCDay()); + + d1.setUTCDate(11); + Assert.assertEquals(11, d1.getUTCDate()); + Assert.assertEquals(6, d1.getUTCDay()); + } + + @Test + void TestMethodSetUTCHoursMinutesSecondsMilliSec() { + TbDate d1 = new TbDate(1975, 12, 31, 23, 15, 30, 567, "-03:00"); + Assert.assertEquals(2, d1.getUTCHours()); + Assert.assertEquals(4, d1.getUTCDay()); + + d1.setUTCHours(5); + Assert.assertEquals(5, d1.getUTCHours()); + Assert.assertEquals(4, d1.getUTCDay()); + d1.setUTCHours(12, 45); + Assert.assertEquals(12, d1.getUTCHours()); + Assert.assertEquals(45, d1.getUTCMinutes()); + Assert.assertEquals(4, d1.getUTCDay()); + d1.setUTCHours(0, 12, 59); + Assert.assertEquals(0, d1.getUTCHours()); + Assert.assertEquals(12, d1.getUTCMinutes()); + Assert.assertEquals(59, d1.getUTCSeconds()); + Assert.assertEquals(4, d1.getUTCDay()); + d1.setUTCHours(4, 58, 2, 456); + Assert.assertEquals(4, d1.getUTCHours()); + Assert.assertEquals(58, d1.getUTCMinutes()); + Assert.assertEquals(2, d1.getUTCSeconds()); + Assert.assertEquals(456, d1.getUTCMilliseconds()); + Assert.assertEquals(4, d1.getUTCDay()); + + d1.setUTCMinutes(5); + Assert.assertEquals(5, d1.getUTCMinutes()); + Assert.assertEquals(4, d1.getUTCDay()); + d1.setUTCMinutes(15, 32); + Assert.assertEquals(15, d1.getUTCMinutes()); + Assert.assertEquals(32, d1.getUTCSeconds()); + Assert.assertEquals(4, d1.getUTCDay()); + d1.setUTCMinutes(10, 42, 321); + Assert.assertEquals(10, d1.getUTCMinutes()); + Assert.assertEquals(42, d1.getUTCSeconds()); + Assert.assertEquals(321, d1.getUTCMilliseconds()); + Assert.assertEquals(4, d1.getUTCDay()); + + d1.setUTCSeconds(5); + Assert.assertEquals(5, d1.getUTCSeconds()); + Assert.assertEquals(4, d1.getUTCDay()); + d1.setUTCSeconds(15, 32); + Assert.assertEquals(15, d1.getUTCSeconds()); + Assert.assertEquals(32, d1.getUTCMilliseconds()); + Assert.assertEquals(4, d1.getUTCDay()); + + d1.setUTCMilliseconds(5); + Assert.assertEquals(5, d1.getUTCMilliseconds()); + Assert.assertEquals(4, d1.getUTCDay()); + } + @Test + void TestMethodSetTome() { + TbDate d1 = new TbDate(1975, 12, 31, 23, 15, 30, 567, "-03:00"); + long dateMilliSecond = d1.getTime(); + int fiveMinutesInMillis = 5 * 60 * 1000; + Assert.assertEquals(15, d1.getUTCMinutes()); + Assert.assertEquals(4, d1.getUTCDay()); + d1.setTime(dateMilliSecond + fiveMinutesInMillis); + Assert.assertEquals(20, d1.getUTCMinutes()); + Assert.assertEquals(4, d1.getUTCDay()); + d1.setTime(-378682769433L); + Assert.assertEquals(1958, d1.getUTCFullYear()); + Assert.assertEquals(1, d1.getUTCMonth()); + Assert.assertEquals(1, d1.getUTCDate()); + Assert.assertEquals(2, d1.getUTCHours()); + Assert.assertEquals(20, d1.getUTCMinutes()); + Assert.assertEquals(30, d1.getUTCSeconds()); + Assert.assertEquals(567, d1.getUTCMilliseconds()); + Assert.assertEquals(3, d1.getUTCDay()); } + @Test + void TestMethodSeFullYearMonthDate() { + TbDate d1 = new TbDate(1975, 12, 31, 23,15,30, 567,"-03:00"); + Assert.assertEquals(1976, d1.getFullYear()); + Assert.assertEquals(1, d1.getMonth()); + Assert.assertEquals(1, d1.getDate()); + Assert.assertEquals(4, d1.getUTCDay()); + d1.setFullYear(1969); + Assert.assertEquals(1969, d1.getFullYear()); + d1.setUTCFullYear(1975); + Assert.assertEquals(1975, d1.getFullYear()); + Assert.assertEquals(3, d1.getUTCDay()); + d1.setFullYear(1977, 4); + Assert.assertEquals(1977, d1.getFullYear()); + Assert.assertEquals(4, d1.getMonth()); + Assert.assertEquals(5, d1.getDay()); + d1.setFullYear(2023, 2, 24); + Assert.assertEquals(2023, d1.getFullYear()); + Assert.assertEquals(2, d1.getMonth()); + Assert.assertEquals(24, d1.getDate()); + Assert.assertEquals(5, d1.getDay()); + + d1.setMonth(11); + Assert.assertEquals(11, d1.getMonth()); + Assert.assertEquals(5, d1.getDay()); + d1.setMonth(2, 28); + Assert.assertEquals(2, d1.getMonth()); + Assert.assertEquals(28, d1.getDate()); + Assert.assertEquals(2, d1.getDay()); + + d1.setDate(11); + Assert.assertEquals(11, d1.getDate()); + Assert.assertEquals(6, d1.getDay()); + } + @Test + void TestMethodSeHoursMinutesSecondsMilliSec() { + TbDate d1 = new TbDate(1975, 12, 31, 23, 15, 30, 567, "-03:00"); + Assert.assertEquals(5, d1.getHours()); + Assert.assertEquals(4, d1.getDay()); + + d1.setHours(5); + Assert.assertEquals(8, d1.getHours()); + Assert.assertEquals(4, d1.getDay()); + d1.setHours(23, 45); + Assert.assertEquals(1, d1.getMonth()); + Assert.assertEquals(2, d1.getDate()); + Assert.assertEquals(2, d1.getHours()); + Assert.assertEquals(45, d1.getMinutes()); + Assert.assertEquals(5, d1.getDay()); + d1.setUTCHours(0, 12, 59); + Assert.assertEquals(3, d1.getHours()); + Assert.assertEquals(12, d1.getMinutes()); + Assert.assertEquals(59, d1.getSeconds()); + Assert.assertEquals(4, d1.getDay()); + d1.setUTCHours(4, 58, 2, 456); + Assert.assertEquals(7, d1.getHours()); + Assert.assertEquals(58, d1.getMinutes()); + Assert.assertEquals(2, d1.getSeconds()); + Assert.assertEquals(456, d1.getMilliseconds()); + Assert.assertEquals(4, d1.getDay()); + + d1.setMinutes(5); + Assert.assertEquals(5, d1.getMinutes()); + Assert.assertEquals(4, d1.getUTCDay()); + d1.setMinutes(15, 32); + Assert.assertEquals(15, d1.getMinutes()); + Assert.assertEquals(32, d1.getSeconds()); + Assert.assertEquals(4, d1.getDay()); + d1.setMinutes(10, 42, 321); + Assert.assertEquals(10, d1.getMinutes()); + Assert.assertEquals(42, d1.getSeconds()); + Assert.assertEquals(321, d1.getMilliseconds()); + Assert.assertEquals(4, d1.getDay()); + + d1.setSeconds(5); + Assert.assertEquals(5, d1.getSeconds()); + Assert.assertEquals(4, d1.getDay()); + d1.setSeconds(15, 32); + Assert.assertEquals(15, d1.getSeconds()); + Assert.assertEquals(32, d1.getMilliseconds()); + Assert.assertEquals(4, d1.getDay()); + + d1.setMilliseconds(5); + Assert.assertEquals(5, d1.getMilliseconds()); + Assert.assertEquals(4, d1.getDay()); + } + @Test + public void toStringAsJs() { + TbDate d1 = new TbDate(1975, 12, 31, 23,15,30, 567,"-14:00"); + Assert.assertEquals("1976 Jan 1, Thu 16:15:30 Eastern European Time", d1.toString()); + Assert.assertEquals("1976 Jan 1, Thu 16:15:30 Eastern European Time", d1.toString("GMT")); + Assert.assertEquals("1976 Jan 1, Thu 16:15:30 Eastern European Time", d1.toString("UTC")); + Assert.assertEquals("Thursday, January 1, 1976 at 4:15:30 PM Eastern European Standard Time", d1.toString("en-US")); + Assert.assertEquals("1976 Jan 1, Thu 16:15:30", d1.toUTCString()); + Assert.assertEquals("четвер, 1 січня 1976 р., 16:15:30", d1.toUTCString("uk-UA")); + Assert.assertEquals("Thursday, January 1, 1976, 4:15:30 PM", d1.toUTCString("en-US")); + Assert.assertEquals("четвер, 1 січня 1976 р., 16:15:30", d1.toUTCString("uk-UA")); + Assert.assertEquals("Thursday, January 1, 1976, 4:15:30 PM", d1.toUTCString("en-US")); + Assert.assertEquals("1976 Jan 1, Thu", d1.toDateString()); + Assert.assertEquals("четвер, 1 січня 1976 р.", d1.toDateString("uk-UA")); + Assert.assertEquals("Thursday, January 1, 1976", d1.toDateString("en-US")); + Assert.assertEquals("16:15:30 Eastern European Time", d1.toTimeString()); + Assert.assertEquals("16:15:30 за східноєвропейським стандартним часом", d1.toTimeString("uk-UA")); + Assert.assertEquals("4:15:30 PM Eastern European Standard Time", d1.toTimeString("en-US")); + Assert.assertEquals("1976-01-01T13:15:30.567Z", d1.toJSON()); + } + + /** + * Date.UTC(0) + * -2208988800000 + * > "Mon, 01 Jan 1900 00:00:00 GMT" + * new Date(Date.UTC(0, 0, 0, 0, 0, 0)); + * "Sun, 31 Dec 1899 00:00:00 GMT" + */ + @Test + public void toUTC() { + Assert.assertEquals(-2209075200000L, TbDate.UTC(0)); + Assert.assertEquals("1899-12-31T00:00:00Z", new TbDate(TbDate.UTC(0)).toJSON()); + Assert.assertEquals("1996-02-02T03:04:05Z", new TbDate(TbDate.UTC(96, 2, 2, 3, 4, 5)).toJSON()); + Assert.assertEquals("2022-12-31T03:04:05.678Z", new TbDate(TbDate.UTC(22, 0, 0, 3, 4, 5, 678)).toJSON()); + Assert.assertEquals("0903-12-31T03:04:05.678Z", new TbDate(TbDate.UTC(903, 0, 0, 3, 4, 5, 678)).toJSON()); + Assert.assertEquals("1958-12-31T03:04:05.678Z", new TbDate(TbDate.UTC(1958, 0, 0, 3, 4, 5, 678)).toJSON()); + Assert.assertEquals("2032-04-05T03:04:05.678Z", new TbDate(TbDate.UTC(2032, 4, 5, 3, 4, 5, 678)).toJSON()); + Assert.assertEquals("2024-02-29T03:04:05.678Z", new TbDate(TbDate.UTC(2024, 2, 29, 3, 4, 5, 678)).toJSON()); + Exception actual = assertThrows(DateTimeParseException.class, () -> { + TbDate.UTC(2023, 2, 29, 3, 4, 5, 678); + }); + String expectedMessage = "could not be parsed"; + assertTrue(actual.getMessage().contains(expectedMessage)); + } } + From 5126c9abab6acff8a18e9bbb4b326aa5155287f5 Mon Sep 17 00:00:00 2001 From: nick Date: Tue, 17 Oct 2023 16:20:01 +0300 Subject: [PATCH 07/11] tbDate: delete timeZneId --- .../thingsboard/script/api/tbel/TbDate.java | 309 ++++---- .../script/api/tbel/TbDateTest.java | 673 +++++++++++------- .../script/api/tbel/TbDateTestEntity.java | 90 +++ 3 files changed, 663 insertions(+), 409 deletions(-) create mode 100644 common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateTestEntity.java 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 0dba460686..146de4570f 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 @@ -26,11 +26,13 @@ import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneId; +import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.chrono.IsoChronology; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.DateTimeParseException; +import java.time.format.FormatStyle; import java.time.temporal.ChronoUnit; import java.time.temporal.TemporalAccessor; import java.util.Arrays; @@ -40,38 +42,31 @@ import java.util.function.BiFunction; public class TbDate implements Serializable, Cloneable { private Instant instant; - private ZonedDateTime zonedDateTime; - private LocalDateTime localDateTime; - private final ZoneId zoneIdUTC = ZoneId.of("UTC"); - private static String patternDefault = "%s-%s-%sT%s:%s:%s.%s%s"; + private static final ZoneId zoneIdUTC = ZoneId.of("UTC"); + private static final Locale localeUTC = Locale.forLanguageTag("UTC"); public TbDate() { this.instant = Instant.now(); - initZonedLocalDateTime(); } public TbDate(String s) { - parseInstant(s); + this.instant = parseInstant(s); } - /** - * String s = "09:15:30 PM, Sun 10/09/2022"; - * String pattern = "hh:mm:ss a, EEE M/d/uuuu"; - * @param s - * @param pattern - */ public TbDate(String s, String pattern, Locale locale) { - DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern, locale); - LocalDateTime localDateTime = LocalDateTime.parse(s, dateTimeFormatter); - ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault()); - instant = zonedDateTime.toInstant(); - initZonedLocalDateTime(); + instant = parseInstant(s, pattern, locale, zoneIdUTC); + } + public TbDate(String s, String pattern, Locale locale, String zoneIdStr) { + ZoneId zoneId = ZoneId.of(zoneIdStr); + instant = parseInstant(s, pattern, locale, zoneId); + } + public TbDate(String s, String pattern, Locale locale, ZoneId zoneId) { + instant = parseInstant(s, pattern, locale, zoneId); } public TbDate(long dateMilliSecond) { instant = Instant.ofEpochMilli(dateMilliSecond); - initZonedLocalDateTime(); } public TbDate(int year, int month, int date, String... tz) { @@ -87,51 +82,45 @@ public class TbDate implements Serializable, Cloneable { } public TbDate(int year, int month, int date, int hrs, int min, int second, int secondMilli, String... tz) { - this(createDateTimeFromPattern(year, month, date, hrs, min, second, secondMilli, tz)); + ZoneId zoneId = tz.length > 0 ? ZoneId.of(Arrays.stream(tz).findFirst().get()) : ZoneId.systemDefault(); + instant = parseInstant(year, month, date, hrs, min, second, secondMilli, zoneId); } public Instant getInstant() { return instant; } - public void setInstant(Instant instant) { - this.instant = instant; - } public ZonedDateTime getZonedDateTime() { - return zonedDateTime; + return instant.atZone(zoneIdUTC); } - private void initZonedLocalDateTime() { - setZonedDateTime(zoneIdUTC); - setLocalDateTime(); - } - public void setZonedDateTime(ZoneId z) { - this.zonedDateTime = instant.atZone(z);; + public LocalDateTime getLocalDateTime() { + return LocalDateTime.ofInstant(this.instant, ZoneId.systemDefault()); } - public void setLocalDateTime() { - this.localDateTime = LocalDateTime.ofInstant(this.getInstant(), ZoneId.systemDefault()); - } - public LocalDateTime getLocalDateTime() { - return this.localDateTime ; + public LocalDateTime getUTCDateTime() { + return LocalDateTime.ofInstant(this.instant, zoneIdUTC); } public String toDateString() { - return toLocaleDateString("UTC", JacksonUtil.newObjectNode().put("dateStyle", "full").toString()); + return toDateString(localeUTC.getLanguage()); } public String toDateString(String locale) { - return toLocaleDateString(locale, JacksonUtil.newObjectNode().put("dateStyle", "full").toString()); + return toDateString(locale, ZoneId.systemDefault().toString()); + } + public String toDateString(String locale, String zoneStr) { + return toLocaleDateString(locale, JacksonUtil.newObjectNode().put("dateStyle", FormatStyle.FULL.name()).put("timeZone", zoneStr).toString()); } public String toTimeString() { - return toLocaleTimeString("UTC", JacksonUtil.newObjectNode().put("timeStyle", "full").toString()); + return toTimeString(Locale.getDefault().getLanguage()); } public String toTimeString(String locale) { - return toLocaleTimeString(locale, JacksonUtil.newObjectNode().put("timeStyle", "full").toString()); + return toTimeString(locale, ZoneId.systemDefault().toString()); + } + public String toTimeString(String locale, String zoneStr) { + return toLocaleTbTimeString(locale, JacksonUtil.newObjectNode().put("timeStyle", FormatStyle.FULL.name()).put("timeZone", zoneStr).toString()); } - /** - * "2011-10-05T14:48:00.000Z" - * @return - */ + public String toISOString() { return instant.toString(); } @@ -139,59 +128,73 @@ public class TbDate implements Serializable, Cloneable { return toISOString(); } public String toUTCString() { - return toLocaleString("UTC", JacksonUtil.newObjectNode().put("dateStyle", "full").put("timeStyle", "medium").toString()); + return toUTCString(localeUTC.getLanguage()); } public String toUTCString(String locale) { - return toLocaleString(locale, JacksonUtil.newObjectNode().put("dateStyle", "full").put("timeStyle", "medium").toString()); + return toLocaleTbString(locale, JacksonUtil.newObjectNode().put("dateStyle", FormatStyle.FULL.name()).put("timeStyle", FormatStyle.MEDIUM.name()).put("timeZone", zoneIdUTC.getId()).toString()); } - /** - * "Tue Aug 19 1975 23:15:30 GMT+0300 (за східноєвропейським стандартним часом)" - * @return - */ public String toString() { - return toLocaleString(Locale.getDefault().toString(), JacksonUtil.newObjectNode().put("dateStyle", "full").put("timeStyle", "full").toString()); + return toString(Locale.getDefault().getLanguage()); } + public String toString(String locale) { - return toLocaleString(locale, JacksonUtil.newObjectNode().put("dateStyle", "full").put("timeStyle", "full").toString()); + return toString(locale, ZoneId.systemDefault().toString()); + } + + public String toString(String locale, String zoneStr) { + return toLocaleTbString(locale, JacksonUtil.newObjectNode().put("dateStyle", FormatStyle.FULL.name()).put("timeStyle", FormatStyle.FULL.name()).put("timeZone", zoneStr).toString()); + } + public String toISOZonedDateTimeString() { + return getZonedDateTime().toString(); + } + public String toISOZonedDateTimeString(DateTimeFormatter formatter) { + return getZonedDateTime().format(formatter); } public String toLocaleDateString() { - return toLocaleDateString(null, null); + return toLocaleDateString(localeUTC.getLanguage()); } public String toLocaleDateString(String locale) { - return toLocaleDateString(locale, null); + return toLocaleDateString(locale, JacksonUtil.newObjectNode().put("dateStyle", FormatStyle.FULL.name()).put("timeZone", ZoneId.systemDefault().toString()).toString()); } public String toLocaleDateString(String localeStr, String optionsStr) { - return toLocaleString(localeStr, optionsStr, (locale, options) -> DateTimeFormatter.ofLocalizedDate(options.getDateStyle()).withLocale(locale)); + return toLocaleTbString(localeStr, optionsStr, (locale, options) -> DateTimeFormatter.ofLocalizedDate(options.getDateStyle()).withLocale(locale)); } public String toLocaleTimeString() { - return toLocaleTimeString(null, null); + return toLocaleTimeString(Locale.getDefault().getLanguage()); } - public String toLocaleTimeString(String locale) { - return toLocaleTimeString(locale, null); + public String toLocaleTimeString(String localeStr) { + return toLocaleTimeString(localeStr, ZoneId.systemDefault().toString()); } - public String toLocaleTimeString(String localeStr, String optionsStr) { - return toLocaleString(localeStr, optionsStr, (locale, options) -> DateTimeFormatter.ofLocalizedTime(options.getTimeStyle()).withLocale(locale)); + public String toLocaleTimeString(String localeStr, String zoneStr) { + return toLocaleTbTimeString(localeStr, JacksonUtil.newObjectNode().put("timeStyle", FormatStyle.MEDIUM.name()).put("timeZone", zoneStr).toString()); + } + + public String toLocaleTbTimeString(String localeStr, String optionsStr) { + return toLocaleTbString(localeStr, optionsStr, (locale, options) -> DateTimeFormatter.ofLocalizedTime(options.getTimeStyle()).withLocale(locale)); } public String toLocaleString() { - LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); - return localDateTime.toString(); + return toLocaleString(localeUTC.getLanguage(), ZoneId.systemDefault().toString()); } public String toLocaleString(String locale) { - return toLocaleString(locale, null); + return toLocaleString(locale, ZoneId.systemDefault().toString()); } - public String toLocaleString(String localeStr, String optionsStr) { - return toLocaleString(localeStr, optionsStr, (locale, options) -> { + public String toLocaleString(String locale, String zoneStr) { + return toLocaleTbString(locale, JacksonUtil.newObjectNode().put("dateStyle", FormatStyle.SHORT.name()).put("timeStyle", FormatStyle.MEDIUM.name()).put("timeZone", zoneStr).toString()); + } + + public String toLocaleTbString(String localeStr, String optionsStr) { + return toLocaleTbString(localeStr, optionsStr, (locale, options) -> { String formatPattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern( options.getDateStyle(), @@ -202,7 +205,7 @@ public class TbDate implements Serializable, Cloneable { }); } - public String toLocaleString(String localeStr, String optionsStr, BiFunction formatterBuilder) { + public String toLocaleTbString(String localeStr, String optionsStr, BiFunction formatterBuilder) { Locale locale = StringUtils.isNotEmpty(localeStr) ? Locale.forLanguageTag(localeStr) : Locale.getDefault(); DateTimeFormatOptions options = getDateFormattingOptions(optionsStr); ZonedDateTime zdt = this.getInstant().atZone(options.getTimeZone().toZoneId()); @@ -264,116 +267,130 @@ public class TbDate implements Serializable, Cloneable { year = year == 0 ? year = 1899 : year; month = month == 0 ? month = 12 : month; date = date == 0 ? date = 31 : date; - return Instant.parse(createDateTimeFromPattern (year, month, date, hrs, min, sec, ms)).toEpochMilli(); + return parseInstant(year, month, date, hrs, min, sec, ms, zoneIdUTC).toEpochMilli(); } public int getUTCFullYear() { - return zonedDateTime.getYear(); + return getUTCDateTime().getYear(); } public int getUTCMonth() { - return zonedDateTime.getMonthValue(); + return getUTCDateTime().getMonthValue(); } // day in month public int getUTCDate() { - return zonedDateTime.getDayOfMonth(); + return getUTCDateTime().getDayOfMonth(); } // day in week public int getUTCDay() { - return zonedDateTime.getDayOfWeek().getValue(); + return getUTCDateTime().getDayOfWeek().getValue(); } public int getUTCHours() { - return zonedDateTime.getHour(); + return getUTCDateTime().getHour(); } public int getUTCMinutes() { - return zonedDateTime.getMinute(); + return getZonedDateTime().getMinute(); } public int getUTCSeconds() { - return zonedDateTime.getSecond(); + return getUTCDateTime().getSecond(); } public int getUTCMilliseconds() { - return zonedDateTime.getNano()/1000000; + return getUTCDateTime().getNano()/1000000; } public void setUTCFullYear(int year) { - parseInstant(createDateTimeFromPattern(year, getUTCMonth(), getUTCDate(), getUTCHours(), getUTCMinutes(), getUTCSeconds(), getUTCMilliseconds())); + if (getUTCDate() > 28) { + long time = getZonedDateTime().withYear(year).withDayOfMonth(1).toInstant().toEpochMilli() + (getUTCDate() - 1) * 24 * 60 * 60 * 1000L; + this.instant = Instant.ofEpochMilli(time); + } else { + this.instant = getZonedDateTime().withYear(year).toInstant(); + } } public void setUTCFullYear(int year, int month) { - parseInstant(createDateTimeFromPattern(year, month, getUTCDate(), getUTCHours(), getUTCMinutes(), getUTCSeconds(), getUTCMilliseconds())); + if (getUTCDate() > 28) { + long time = getZonedDateTime().withYear(year).withMonth(month).withDayOfMonth(1).toInstant().toEpochMilli() + (getUTCDate() - 1) * 24 * 60 * 60 * 1000L; + this.instant = Instant.ofEpochMilli(time); + } else { + this.instant = getZonedDateTime().withYear(year).withMonth(month).toInstant(); + } } public void setUTCFullYear(int year, int month, int date) { - parseInstant(createDateTimeFromPattern(year, month, date, getUTCHours(), getUTCMinutes(), getUTCSeconds(), getUTCMilliseconds())); + this.instant = getZonedDateTime().withYear(year).withMonth(month).withDayOfMonth(date).toInstant(); } public void setUTCMonth(int month) { - parseInstant(createDateTimeFromPattern(getUTCFullYear(), month, getUTCDate(), getUTCHours(), getUTCMinutes(), getUTCSeconds(), getUTCMilliseconds())); + if (getUTCDate() > 28) { + long time = getZonedDateTime().withMonth(month).withDayOfMonth(1).toInstant().toEpochMilli() + (getUTCDate() - 1) * 24 * 60 * 60 * 1000L; + this.instant = Instant.ofEpochMilli(time); + } else { + this.instant = getZonedDateTime().withMonth(month).toInstant(); + } } public void setUTCMonth(int month, int date) { - parseInstant(createDateTimeFromPattern(getUTCFullYear(), month, date, getUTCHours(), getUTCMinutes(), getUTCSeconds(), getUTCMilliseconds())); + this.instant = getZonedDateTime().withMonth(month).withDayOfMonth(date).toInstant(); } public void setUTCDate(int date) { - parseInstant(createDateTimeFromPattern(getUTCFullYear(), getUTCMonth(), date, getUTCHours(), getUTCMinutes(), getUTCSeconds(), getUTCMilliseconds())); + this.instant = getZonedDateTime().withDayOfMonth(date).toInstant(); } public void setUTCHours(int hrs) { - parseInstant(createDateTimeFromPattern(getUTCFullYear(), getUTCMonth(), getUTCDate(), hrs, getUTCMinutes(), getUTCSeconds(), getUTCMilliseconds())); + this.instant = getZonedDateTime().withHour(hrs).toInstant(); } public void setUTCHours(int hrs, int minutes) { - parseInstant(createDateTimeFromPattern(getUTCFullYear(), getUTCMonth(), getUTCDate(), hrs, minutes, getUTCSeconds(), getUTCMilliseconds())); + this.instant = getZonedDateTime().withHour(hrs).withMinute(minutes).toInstant(); } public void setUTCHours(int hrs, int minutes, int seconds) { - parseInstant(createDateTimeFromPattern(getUTCFullYear(), getUTCMonth(), getUTCDate(), hrs, minutes, seconds, getUTCMilliseconds())); + this.instant = getZonedDateTime().withHour(hrs).withMinute(minutes).withSecond(seconds).toInstant(); } public void setUTCHours(int hrs, int minutes, int seconds, int ms) { - parseInstant(createDateTimeFromPattern(getUTCFullYear(), getUTCMonth(), getUTCDate(), hrs, minutes, seconds, ms)); + this.instant = getZonedDateTime().withHour(hrs).withMinute(minutes).withSecond(seconds).withNano(ms*1000000).toInstant(); } public void setUTCMinutes(int minutes) { - parseInstant(createDateTimeFromPattern(getUTCFullYear(), getUTCMonth(), getUTCDate(), getUTCHours(), minutes, getUTCSeconds(), getUTCMilliseconds())); + this.instant = getZonedDateTime().withMinute(minutes).toInstant(); } public void setUTCMinutes(int minutes, int seconds) { - parseInstant(createDateTimeFromPattern(getUTCFullYear(), getUTCMonth(), getUTCDate(), getUTCHours(), minutes, seconds, getUTCMilliseconds())); - } + this.instant = getZonedDateTime().withMinute(minutes).withSecond(seconds).toInstant(); } public void setUTCMinutes(int minutes, int seconds, int ms) { - parseInstant(createDateTimeFromPattern(getUTCFullYear(), getUTCMonth(), getUTCDate(), getUTCHours(), minutes, seconds, ms)); + this.instant = parseInstant(getUTCFullYear(), getUTCMonth(), getUTCDate(), getUTCHours(), minutes, seconds, ms, zoneIdUTC); } public void setUTCSeconds(int seconds) { - parseInstant(createDateTimeFromPattern(getUTCFullYear(), getUTCMonth(), getUTCDate(), getUTCHours(), getUTCMinutes(), seconds, getUTCMilliseconds())); + this.instant = getZonedDateTime().withSecond(seconds).toInstant(); } public void setUTCSeconds(int seconds, int ms) { - parseInstant(createDateTimeFromPattern(getUTCFullYear(), getUTCMonth(), getUTCDate(), getUTCHours(), getUTCMinutes(), seconds, ms)); + this.instant = getZonedDateTime().withSecond(seconds).withNano(ms*1000000).toInstant(); } public void setUTCMilliseconds(int ms) { - parseInstant(createDateTimeFromPattern(getUTCFullYear(), getUTCMonth(), getUTCDate(), getUTCHours(), getUTCMinutes(), getUTCSeconds(), ms)); + this.instant = getZonedDateTime().withNano(ms*1000000).toInstant(); } public int getFullYear() { - return localDateTime.getYear(); + return getLocalDateTime().getYear(); } public int getMonth() { - return localDateTime.getMonthValue(); + return getLocalDateTime().getMonthValue(); } // day in month public int getDate() { - return localDateTime.getDayOfMonth(); + return getLocalDateTime().getDayOfMonth(); } // day in week public int getDay() { - return localDateTime.getDayOfWeek().getValue(); + return getLocalDateTime().getDayOfWeek().getValue(); } public int getHours() { - return localDateTime.getHour(); + return getLocalDateTime().getHour(); } public int getMinutes() { - return localDateTime.getMinute(); + return getLocalDateTime().getMinute(); } public int getSeconds() { - return localDateTime.getSecond(); + return getLocalDateTime().getSecond(); } public int getMilliseconds() { - return localDateTime.getNano()/1000000; + return getLocalDateTime().getNano()/1000000; } // Milliseconds since Jan 1, 1970, 00:00:00.000 GMT public long getTime() { @@ -383,61 +400,84 @@ public class TbDate implements Serializable, Cloneable { return getTime() ; } public void setFullYear(int year) { - setUTCFullYear(year); + Instant instantEpochWithYear = getZonedDateTime().withYear(year).toInstant(); + if (getDate() > 28) { + long time = getLocalDateTime().withYear(year).withDayOfMonth(1).toInstant(getLocaleZoneOffset(instantEpochWithYear)).toEpochMilli() + (getDate() - 1) * 24 * 60 * 60 * 1000L; + this.instant = Instant.ofEpochMilli(time); + } else { + this.instant = getLocalDateTime().withYear(year).toInstant(getLocaleZoneOffset(instantEpochWithYear)); + } } public void setFullYear(int year, int month) { - setUTCFullYear(year, month); - } public void setFullYear(int year, int month, int date) { - setUTCFullYear(year, month, date); + Instant instantEpochWithYear = getZonedDateTime().withYear(year).withMonth(month).toInstant(); + if (getDate() > 28) { + long time = getLocalDateTime().withYear(year).withMonth(month).withDayOfMonth(1).toInstant(getLocaleZoneOffset(instantEpochWithYear)).toEpochMilli() + (getDate() - 1) * 24 * 60 * 60 * 1000L; + this.instant = Instant.ofEpochMilli(time); + } else { + this.instant = getLocalDateTime().withYear(year).withMonth(month).toInstant(getLocaleZoneOffset(instantEpochWithYear)); + } + } + public void setFullYear(int year, int month, int date) { + Instant instantEpochWithYearMonthDate = getZonedDateTime().withYear(year).withMonth(month).withDayOfMonth(date).toInstant(); + this.instant = getLocalDateTime().withYear(year).withMonth(month).withDayOfMonth(date).toInstant(getLocaleZoneOffset(instantEpochWithYearMonthDate)); } public void setMonth(int month) { - setUTCMonth(month); + Instant instantEpochWithYear = getZonedDateTime().withMonth(month).toInstant(); + if (getDate() > 28) { + long time = getLocalDateTime().withMonth(month).withDayOfMonth(1).toInstant(getLocaleZoneOffset(instantEpochWithYear)).toEpochMilli() + (getDate() - 1) * 24 * 60 * 60 * 1000L; + this.instant = Instant.ofEpochMilli(time); + } else { + this.instant = getLocalDateTime().withMonth(month).toInstant(getLocaleZoneOffset(instantEpochWithYear)); + } + } public void setMonth(int month, int date) { - setUTCMonth(month, date) ; + Instant instantEpochWithMonthDate = getZonedDateTime().withMonth(month).withDayOfMonth(date).toInstant(); + this.instant = getLocalDateTime().withMonth(month).withDayOfMonth(date).toInstant(getLocaleZoneOffset(instantEpochWithMonthDate)); } public void setDate(int date) { - setUTCDate(date); + Instant instantEpochWithDate = getZonedDateTime().withDayOfMonth(date).toInstant(); + this.instant = getLocalDateTime().withDayOfMonth(date).toInstant(getLocaleZoneOffset(instantEpochWithDate)); } public void setHours(int hrs) { - setUTCHours(hrs); + this.instant = getLocalDateTime().withHour(hrs).toInstant(getLocaleZoneOffset(this.instant)); } public void setHours(int hrs, int minutes) { - setUTCHours(hrs, minutes); + this.instant = getLocalDateTime().withHour(hrs).withMinute(minutes).toInstant(getLocaleZoneOffset(this.instant)); } public void setHours(int hrs, int minutes, int seconds) { - setUTCHours(hrs, minutes, seconds); + this.instant = getLocalDateTime().withHour(hrs).withMinute(minutes).withSecond(seconds).toInstant(getLocaleZoneOffset(this.instant)); } public void setHours(int hrs, int minutes, int seconds, int ms) { - setUTCHours(hrs, minutes, seconds, ms); + this.instant = getLocalDateTime().withHour(hrs).withMinute(minutes).withSecond(seconds).withNano(ms*1000000).toInstant(getLocaleZoneOffset(this.instant)); } public void setMinutes(int minutes) { - setUTCMinutes(minutes); + this.instant = getLocalDateTime().withMinute(minutes).toInstant(getLocaleZoneOffset(this.instant)); } public void setMinutes(int minutes, int seconds) { - setUTCMinutes(minutes, seconds); + this.instant = getLocalDateTime().withMinute(minutes).withSecond(seconds).toInstant(getLocaleZoneOffset(this.instant)); + } public void setMinutes(int minutes, int seconds, int ms) { - setUTCMinutes(minutes, seconds, ms); + this.instant = getLocalDateTime().withMinute(minutes).withSecond(seconds).withNano(ms*1000000).toInstant(getLocaleZoneOffset(this.instant)); } public void setSeconds(int seconds) { - setUTCSeconds(seconds); + this.instant = getLocalDateTime().withSecond(seconds).toInstant(getLocaleZoneOffset(this.instant)); } public void setSeconds(int seconds, int ms) { - setUTCSeconds(seconds, ms); + this.instant = getLocalDateTime().withSecond(seconds).withNano(ms*1000000).toInstant(getLocaleZoneOffset(this.instant)); } public void setMilliseconds(int ms) { - setUTCMilliseconds(ms); + this.instant = getLocalDateTime().withNano(ms*1000000).toInstant(getLocaleZoneOffset(this.instant)); } // Milliseconds since Jan 1, 1970, 00:00:00.000 GMT public void setTime(long dateMilliSecond) { instant = Instant.ofEpochMilli(dateMilliSecond); - initZonedLocalDateTime(); } - public int getTimezoneOffset() { - int seconds = ZoneId.systemDefault().getRules().getOffset(instant).getTotalSeconds(); - return -seconds/60; + + public ZoneOffset getLocaleZoneOffset(Instant... instants){ + return ZoneId.systemDefault().getRules().getOffset(instants.length > 0 ? instants[0] : this.instant); } public static long parse(String value, String format) { @@ -462,33 +502,32 @@ public class TbDate implements Serializable, Cloneable { return -1; } } - private static String createDateTimeFromPattern(int year, int month, int date, int hrs, int min, int second, int secondMilli, String... tz) { - String yearStr = String.format("%04d", year); - yearStr = yearStr.substring(0, 2).equals("00") ? year < 70 ? "20" + yearStr.substring(2,4) : "19" + yearStr.substring(2,4) : yearStr; - String monthStr = String.format("%02d", month); - String dateStr = String.format("%02d", date); - String hrsStr = String.format("%02d", hrs); - String minStr = String.format("%02d", min); - String secondStr = String.format("%02d", second); - String secondMilliStr = String.format("%03d", secondMilli); - String tzStr = tz.length > 0 ? Arrays.stream(tz).findFirst().get() : "Z"; - return String.format(patternDefault, yearStr, monthStr, dateStr, hrsStr, minStr, secondStr, secondMilliStr, tzStr); - } - private void parseInstant(String s) { + private static Instant parseInstant(String s) { try{ if (s.length() > 0 && Character.isDigit(s.charAt(0))) { // assuming UTC instant "2007-12-03T10:15:30.00Z" - instant = Instant.parse(s); + return Instant.parse(s); } else { // assuming RFC-1123 value "Tue, 3 Jun 2008 11:05:30 GMT-02:00" - instant = Instant.from(DateTimeFormatter.RFC_1123_DATE_TIME.parse(s)); + return Instant.from(DateTimeFormatter.RFC_1123_DATE_TIME.parse(s)); } - initZonedLocalDateTime(); } catch (final DateTimeParseException ex) { final ConversionException exception = new ConversionException("Cannot parse value [" + s + "] as instant", ex); throw exception; } } + + private static Instant parseInstant(int year, int month, int date, int hrs, int min, int second, int secondMilli, ZoneId zoneId) { + year = year < 70 ? 2000 + year : year <= 99 ? 1900 + year : year; + 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); + LocalDateTime localDateTime = LocalDateTime.parse(s, dateTimeFormatter); + ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId); + return zonedDateTime.toInstant(); + } } 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 75027247b1..f020d3e092 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 @@ -27,7 +27,9 @@ import org.junit.jupiter.api.Test; import org.mvel2.ConversionException; import org.thingsboard.common.util.JacksonUtil; -import java.time.format.DateTimeParseException; +import java.time.DateTimeException; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -113,12 +115,14 @@ class TbDateTest { void testToISOStringThreadLocalStaticFormatter() throws ExecutionException, InterruptedException, TimeoutException { executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1)); int hrs = 14; - String pattern = "2024-02-29T%s:35:42.987Z"; - String tsStr = String.format(pattern, hrs); //Thu Feb 29 2024 14:35:42.987 GMT+0000 + int date = 29; + int month = 2; + String pattern = "2024-%s-%sT%s:35:42.987Z"; + String tsStr = String.format(pattern, String.format("%02d", month), date, hrs); //Thu Feb 29 2024 14:35:42.987 GMT+0000 TbDate tbDate = new TbDate(tsStr); long ts = 1709217342987L; //Thu Feb 29 2024 14:35:42.987 GMT+0000 Assert.assertEquals(ts, tbDate.parseSecondMilli()); - int offsetMin = tbDate.getTimezoneOffset(); // for example 3600000 for GMT + 1 + int offsetLocalSecond = tbDate.getLocaleZoneOffset().getTotalSeconds(); // for example 7200 for GMT + 2 String datePrefix = tsStr; //without time zone assertThat(tbDate.toISOString()) @@ -127,13 +131,13 @@ class TbDateTest { assertThat(executor.submit(tbDate::toISOString).get(30, TimeUnit.SECONDS)) .as("format in executor thread") .startsWith(datePrefix); - int offsetHrs = offsetMin/60; - String datePrefixLocal = String.format(pattern, (hrs - offsetHrs)); - long offsetMilli = offsetMin*60*1000; - assertThat(new TbDate(ts - offsetMilli).toISOString()) + TbDateTestEntity tbDateTest = new TbDateTestEntity(tbDate.getFullYear(), month, date,hrs + offsetLocalSecond/60/60); + String datePrefixLocal = String.format(pattern, tbDateTest.geMonthStr(), tbDateTest.geDateStr(), tbDateTest.geHoursStr()); + long offsetLocalMilli = offsetLocalSecond*1000; + assertThat(new TbDate(ts + offsetLocalMilli).toISOString()) .as("new instance format in main thread") .startsWith(datePrefixLocal); - assertThat(executor.submit(() -> new TbDate(ts - offsetMilli).toISOString()).get(30, TimeUnit.SECONDS)) + assertThat(executor.submit(() -> new TbDate(ts + offsetLocalMilli).toISOString()).get(30, TimeUnit.SECONDS)) .as("new instance format in executor thread") .startsWith(datePrefixLocal); } @@ -143,11 +147,21 @@ class TbDateTest { String s = "09:15:30 PM, Sun 10/09/2022"; String pattern = "hh:mm:ss a, EEE M/d/uuuu"; TbDate d = new TbDate(s, pattern, Locale.US); - Assert.assertEquals("2022-10-09T18:15:30Z", d.toISOString()); + Assert.assertEquals("2022-10-09T21:15:30Z", d.toISOString()); + // tz = "-04:00" + d = new TbDate(s, pattern, Locale.US, "-04:00"); + Assert.assertEquals("2022-10-10T01:15:30Z", d.toISOString()); + d = new TbDate(s, pattern, Locale.US, "America/New_York"); + Assert.assertEquals("2022-10-10T01:15:30Z", d.toISOString()); + // tz = "+02:00" + s = "09:15:30 PM, So. 10/09/2022"; + d = new TbDate(s, pattern, Locale.GERMAN, ZoneId.of("Europe/Berlin")); + Assert.assertEquals("2022-10-09T19:15:30Z", d.toISOString()); + s = "09:15:30 пп, середа, 4 жовтня 2023 р."; pattern = "hh:mm:ss a, EEEE, d MMMM y 'р.'"; d = new TbDate(s, pattern, Locale.forLanguageTag("uk-UA")); - Assert.assertEquals("2023-10-04T18:15:30Z", d.toISOString()); + Assert.assertEquals("2023-10-04T21:15:30Z", d.toISOString()); d = new TbDate(1693962245000L); Assert.assertEquals("2023-09-06T01:04:05Z", d.toISOString()); @@ -204,41 +218,41 @@ class TbDateTest { Assert.assertNotNull(d.toLocaleTimeString()); Assert.assertNotNull(d.toLocaleTimeString("en-US")); - Assert.assertEquals("9:04:05 PM", d.toLocaleTimeString("en-US", "America/New_York")); - Assert.assertEquals("오후 9:04:05", d.toLocaleTimeString("ko-KR", "America/New_York")); - Assert.assertEquals("04:04:05", d.toLocaleTimeString( "uk-UA", "Europe/Kiev")); - Assert.assertEquals("9:04:05 م", d.toLocaleTimeString( "ar-EG", "America/New_York")); + Assert.assertEquals("9:04:05 PM", d.toLocaleTbTimeString("en-US", "America/New_York")); + Assert.assertEquals("오후 9:04:05", d.toLocaleTbTimeString("ko-KR", "America/New_York")); + Assert.assertEquals("04:04:05", d.toLocaleTbTimeString( "uk-UA", "Europe/Kiev")); + Assert.assertEquals("9:04:05 م", d.toLocaleTbTimeString( "ar-EG", "America/New_York")); - Assert.assertEquals("9:04:05 PM Eastern Daylight Time", d.toLocaleTimeString("en-US", JacksonUtil.newObjectNode() + Assert.assertEquals("9:04:05 PM Eastern Daylight Time", d.toLocaleTbTimeString("en-US", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("timeStyle", "full") .toString())); - Assert.assertEquals("오후 9시 4분 5초 미 동부 하계 표준시", d.toLocaleTimeString("ko-KR", JacksonUtil.newObjectNode() + Assert.assertEquals("오후 9시 4분 5초 미 동부 하계 표준시", d.toLocaleTbTimeString("ko-KR", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("timeStyle", "full") .toString())); - Assert.assertEquals("04:04:05 за східноєвропейським літнім часом", d.toLocaleTimeString("uk-UA", JacksonUtil.newObjectNode() + Assert.assertEquals("04:04:05 за східноєвропейським літнім часом", d.toLocaleTbTimeString("uk-UA", JacksonUtil.newObjectNode() .put("timeZone", "Europe/Kiev") .put("timeStyle", "full") .toString())); - Assert.assertEquals("9:04:05 م التوقيت الصيفي الشرقي لأمريكا الشمالية", d.toLocaleTimeString("ar-EG", JacksonUtil.newObjectNode() + Assert.assertEquals("9:04:05 م التوقيت الصيفي الشرقي لأمريكا الشمالية", d.toLocaleTbTimeString("ar-EG", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("timeStyle", "full") .toString())); - Assert.assertEquals("9:04:05 PM", d.toLocaleTimeString("en-US", JacksonUtil.newObjectNode() + Assert.assertEquals("9:04:05 PM", d.toLocaleTbTimeString("en-US", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("pattern", "h:mm:ss a") .toString())); - Assert.assertEquals("9:04:05 오후", d.toLocaleTimeString("ko-KR", JacksonUtil.newObjectNode() + Assert.assertEquals("9:04:05 오후", d.toLocaleTbTimeString("ko-KR", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("pattern", "h:mm:ss a") .toString())); - Assert.assertEquals("4:04:05 дп", d.toLocaleTimeString("uk-UA", JacksonUtil.newObjectNode() + Assert.assertEquals("4:04:05 дп", d.toLocaleTbTimeString("uk-UA", JacksonUtil.newObjectNode() .put("timeZone", "Europe/Kiev") .put("pattern", "h:mm:ss a") .toString())); - Assert.assertEquals("9:04:05 م", d.toLocaleTimeString("ar-EG", JacksonUtil.newObjectNode() + Assert.assertEquals("9:04:05 م", d.toLocaleTbTimeString("ar-EG", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("pattern", "h:mm:ss a") .toString())); @@ -252,45 +266,45 @@ class TbDateTest { Assert.assertNotNull(d.toLocaleString()); Assert.assertNotNull(d.toLocaleString("en-US")); - Assert.assertEquals("9/5/23, 9:04:05 PM", d.toLocaleString("en-US", "America/New_York")); - Assert.assertEquals("23. 9. 5. 오후 9:04:05", d.toLocaleString("ko-KR", "America/New_York")); - Assert.assertEquals("06.09.23, 04:04:05", d.toLocaleString( "uk-UA", "Europe/Kiev")); - Assert.assertEquals("5\u200F/9\u200F/2023, 9:04:05 م", d.toLocaleString( "ar-EG", "America/New_York")); + Assert.assertEquals("9/5/23, 9:04:05 PM", d.toLocaleTbString("en-US", "America/New_York")); + Assert.assertEquals("23. 9. 5. 오후 9:04:05", d.toLocaleTbString("ko-KR", "America/New_York")); + Assert.assertEquals("06.09.23, 04:04:05", d.toLocaleTbString( "uk-UA", "Europe/Kiev")); + Assert.assertEquals("5\u200F/9\u200F/2023, 9:04:05 م", d.toLocaleTbString( "ar-EG", "America/New_York")); - Assert.assertEquals("Tuesday, September 5, 2023 at 9:04:05 PM Eastern Daylight Time", d.toLocaleString("en-US", JacksonUtil.newObjectNode() + Assert.assertEquals("Tuesday, September 5, 2023 at 9:04:05 PM Eastern Daylight Time", d.toLocaleTbString("en-US", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("dateStyle", "full") .put("timeStyle", "full") .toString())); - Assert.assertEquals("2023년 9월 5일 화요일 오후 9시 4분 5초 미 동부 하계 표준시", d.toLocaleString("ko-KR", JacksonUtil.newObjectNode() + Assert.assertEquals("2023년 9월 5일 화요일 오후 9시 4분 5초 미 동부 하계 표준시", d.toLocaleTbString("ko-KR", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("dateStyle", "full") .put("timeStyle", "full") .toString())); - Assert.assertEquals("середа, 6 вересня 2023 р. о 04:04:05 за східноєвропейським літнім часом", d.toLocaleString("uk-UA", JacksonUtil.newObjectNode() + Assert.assertEquals("середа, 6 вересня 2023 р. о 04:04:05 за східноєвропейським літнім часом", d.toLocaleTbString("uk-UA", JacksonUtil.newObjectNode() .put("timeZone", "Europe/Kiev") .put("dateStyle", "full") .put("timeStyle", "full") .toString())); - Assert.assertEquals("الثلاثاء، 5 سبتمبر 2023 في 9:04:05 م التوقيت الصيفي الشرقي لأمريكا الشمالية", d.toLocaleString("ar-EG", JacksonUtil.newObjectNode() + Assert.assertEquals("الثلاثاء، 5 سبتمبر 2023 في 9:04:05 م التوقيت الصيفي الشرقي لأمريكا الشمالية", d.toLocaleTbString("ar-EG", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("dateStyle", "full") .put("timeStyle", "full") .toString())); - Assert.assertEquals("9/5/2023, 9:04:05 PM", d.toLocaleString("en-US", JacksonUtil.newObjectNode() + Assert.assertEquals("9/5/2023, 9:04:05 PM", d.toLocaleTbString("en-US", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("pattern", "M/d/yyyy, h:mm:ss a") .toString())); - Assert.assertEquals("9/5/2023, 9:04:05 오후", d.toLocaleString("ko-KR", JacksonUtil.newObjectNode() + Assert.assertEquals("9/5/2023, 9:04:05 오후", d.toLocaleTbString("ko-KR", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("pattern", "M/d/yyyy, h:mm:ss a") .toString())); - Assert.assertEquals("9/6/2023, 4:04:05 дп", d.toLocaleString("uk-UA", JacksonUtil.newObjectNode() + Assert.assertEquals("9/6/2023, 4:04:05 дп", d.toLocaleTbString("uk-UA", JacksonUtil.newObjectNode() .put("timeZone", "Europe/Kiev") .put("pattern", "M/d/yyyy, h:mm:ss a") .toString())); - Assert.assertEquals("9/5/2023, 9:04:05 م", d.toLocaleString("ar-EG", JacksonUtil.newObjectNode() + Assert.assertEquals("9/5/2023, 9:04:05 م", d.toLocaleTbString("ar-EG", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("pattern", "M/d/yyyy, h:mm:ss a") .toString())); @@ -301,27 +315,63 @@ class TbDateTest { String stringDateUTC = "2023-09-06T01:04:05.00Z"; TbDate d = new TbDate(stringDateUTC); Assert.assertEquals("2023-09-06T01:04:05Z", d.toISOString()); - String stringDateTZ = "2023-09-06T01:04:05.00+04:00"; + String stringDateTZ = "2023-09-06T01:04:05.00+04:00:00"; d = new TbDate(stringDateTZ); Assert.assertEquals("2023-09-05T21:04:05Z", d.toISOString()); + stringDateTZ = "2023-09-06T01:04:05.00-04:00"; + d = new TbDate(stringDateTZ); + Assert.assertEquals("2023-09-06T05:04:05Z", d.toISOString()); + stringDateTZ = "2023-09-06T01:04:05.00+04:30:56"; + d = new TbDate(stringDateTZ); + Assert.assertEquals("2023-09-05T20:33:09Z", d.toISOString()); stringDateTZ = "2023-09-06T01:04:05.00-02:00"; d = new TbDate(stringDateTZ); Assert.assertEquals("2023-09-06T03:04:05Z", d.toISOString()); String stringDateRFC_1123 = "Sat, 3 Jun 2023 11:05:30 GMT"; d = new TbDate(stringDateRFC_1123); - stringDateRFC_1123 = "Sat, 3 Jun 2023 11:05:30 +0400"; + Assert.assertEquals("2023-06-03T11:05:30Z", d.toISOString()); + stringDateRFC_1123 = "Sat, 3 Jun 2023 01:04:05 +043056"; + d = new TbDate(stringDateRFC_1123); + Assert.assertEquals("2023-06-02T20:33:09Z", d.toISOString()); + stringDateRFC_1123 = "Sat, 3 Jun 2023 11:05:30 +0400"; d = new TbDate(stringDateRFC_1123); Assert.assertEquals("2023-06-03T07:05:30Z", d.toISOString()); stringDateRFC_1123 = "Thu, 29 Feb 2024 11:05:30 -03"; d = new TbDate(stringDateRFC_1123); Assert.assertEquals("2024-02-29T14:05:30Z", d.toISOString()); - String stringDateRFC_1123_error = "Tue, 3 Jun 2023 11:05:30 GMT"; + String stringDateZ_error = "2023-09-06T01:04:05.00+04"; Exception actual = assertThrows(ConversionException.class, () -> { - new TbDate(stringDateRFC_1123_error); + new TbDate(stringDateZ_error); }); String expectedMessage = "Cannot parse value"; assertTrue(actual.getMessage().contains(expectedMessage)); + + String stringDateRFC_1123_error = "Tue, 3 Jun 2023 11:05:30 GMT"; + actual = assertThrows(ConversionException.class, () -> { + new TbDate(stringDateRFC_1123_error); + }); + assertTrue(actual.getMessage().contains(expectedMessage)); + } + + @Test + void TestDateTimeFormatterToString () { + TbDate d1 = new TbDate(23, 9, 7, 8, 4, 5, "+04:00"); + TbDate d2 = new TbDate(23, 9, 7, 8, 4, 5, "-03:00"); + + Assert.assertEquals("2023-09-07T04:04:05Z[UTC]", d1.toISOZonedDateTimeString()); + Assert.assertEquals("2023-09-07T04:04:05Z", d1.toISOZonedDateTimeString(DateTimeFormatter.ISO_OFFSET_DATE_TIME)); + Assert.assertEquals("2023-09-07T04:04:05Z[UTC]", d1.toISOZonedDateTimeString(DateTimeFormatter.ISO_ZONED_DATE_TIME)); + Assert.assertEquals("2023-09-07T04:04:05", d1.toISOZonedDateTimeString(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); + Assert.assertEquals("Thu, 7 Sep 2023 04:04:05 GMT", d1.toISOZonedDateTimeString(DateTimeFormatter.RFC_1123_DATE_TIME)); + Assert.assertEquals("2023-09-07T04:04:05Z", d1.toISOZonedDateTimeString(DateTimeFormatter.ISO_INSTANT)); + + Assert.assertEquals("2023-09-07T11:04:05Z[UTC]", d2.toISOZonedDateTimeString()); + Assert.assertEquals("2023-09-07T11:04:05Z", d2.toISOZonedDateTimeString(DateTimeFormatter.ISO_OFFSET_DATE_TIME)); + Assert.assertEquals("2023-09-07T11:04:05Z[UTC]", d2.toISOZonedDateTimeString(DateTimeFormatter.ISO_ZONED_DATE_TIME)); + Assert.assertEquals("2023-09-07T11:04:05", d2.toISOZonedDateTimeString(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); + Assert.assertEquals("Thu, 7 Sep 2023 11:04:05 GMT", d2.toISOZonedDateTimeString(DateTimeFormatter.RFC_1123_DATE_TIME)); + Assert.assertEquals("2023-09-07T11:04:05Z", d2.toISOZonedDateTimeString(DateTimeFormatter.ISO_INSTANT)); } @Test @@ -333,188 +383,231 @@ class TbDateTest { String stringDateStart = "1970-01-01T00:00:00Z"; d = new TbDate(stringDateStart); long actualMillis = TbDate.parse("1970-01-01 T00:00:00"); - Assert.assertEquals(d.getTimezoneOffset(), actualMillis/60/1000); + Assert.assertEquals(-d.getLocaleZoneOffset().getTotalSeconds() * 1000, actualMillis); String pattern = "yyyy-MM-dd HH:mm:ss.SSS"; String stringDate = "1995-12-04 00:12:00.000"; Assert.assertNotEquals(-1L, TbDate.parse(stringDate, pattern)); } @Test - void TestDate_Year_Moth_Date_Hs_Min_Sec () { - TbDate d = new TbDate(2023, 8, 18); - Assert.assertEquals("2023-08-18T00:00:00Z", d.toISOString()); - d = new TbDate(2023, 9, 17, 17, 34); - Assert.assertEquals("2023-09-17T17:34:00Z", d.toISOString()); - d = new TbDate(23, 9, 7, 8, 4); - Assert.assertEquals("2023-09-07T08:04:00Z", d.toISOString()); - d = new TbDate(23, 9, 7, 8, 4, 5); - Assert.assertEquals("2023-09-07T08:04:05Z", d.toISOString()); - d = new TbDate(23, 9, 7, 8, 4, 5, "+04:00"); - Assert.assertEquals("2023-09-07T04:04:05Z", d.toISOString()); - d = new TbDate(23, 9, 7, 8, 4, 5, "-03:00"); - Assert.assertEquals("2023-09-07T11:04:05Z", d.toISOString()); - d = new TbDate(23, 9, 7, 23, 4, 5, "-03:00"); - Assert.assertEquals("2023-09-08T02:04:05Z", d.toISOString()); - d = new TbDate(23, 9, 7, 23, 4, 5, 567,"-03:00"); - Assert.assertEquals("2023-09-08T02:04:05.567Z", d.toISOString()); - } - - @Test - void TestMethodGetAsDateUTC () { - TbDate dd = new TbDate(TbDate.UTC(1996, 2, 2, 3, 4, 5)); - Assert.assertEquals(823230245000L, dd.valueOf()); - dd = new TbDate(1996, 2, 2, 3, 4, 5); - Assert.assertEquals(823230245000L, dd.valueOf()); - TbDate beforeStartUTC = new TbDate(1969, 7, 20, 20, 17, 40); - Assert.assertEquals(-14182940000L, beforeStartUTC.getTime()); - - TbDate d1 = new TbDate(1975, 12, 31, 23,15,30, 567,"+02:00"); - TbDate d2 = new TbDate(1975, 12, 31, 23,15,30, 567,"-02:00"); - - Assert.assertEquals(189292530567L, d1.getTime()); - Assert.assertEquals(189306930567L, d2.getTime()); - Assert.assertEquals(d1.getTimezoneOffset(), d2.getTimezoneOffset()); - - Assert.assertEquals(1975, d1.getUTCFullYear()); - Assert.assertEquals(1976, d2.getUTCFullYear()); - - Assert.assertEquals(12, d1.getUTCMonth()); - Assert.assertEquals(1, d2.getUTCMonth()); - - Assert.assertEquals(31, d1.getUTCDate()); - Assert.assertEquals(1, d2.getUTCDate()); - - Assert.assertEquals(3, d1.getUTCDay()); - Assert.assertEquals(4, d2.getUTCDay()); - - Assert.assertEquals(21, d1.getUTCHours()); - Assert.assertEquals(1, d2.getUTCHours()); - - Assert.assertEquals(15, d1.getUTCMinutes()); - Assert.assertEquals(15, d2.getUTCMinutes()); - - Assert.assertEquals(30, d1.getUTCSeconds()); - Assert.assertEquals(30, d2.getUTCSeconds()); - - Assert.assertEquals(567, d1.getUTCMilliseconds()); - Assert.assertEquals(567, d2.getUTCMilliseconds()); - } @Test - void TestMethodGetAsDateLocal () { - TbDate d1 = new TbDate(1975, 12, 31, 23,15,30, 567,"+02:00"); - TbDate d2 = new TbDate(1975, 12, 31, 23,15,30, 567,"-02:00"); - TbDate dLocal1 = new TbDate(d1.parseSecondMilli()-d1.getTimezoneOffset()*60*1000); - TbDate dLocal2 = new TbDate(d2.parseSecondMilli()-d2.getTimezoneOffset()*60*1000); - + void TestMethodGetAsDateTimeLocal() { + TbDate d = new TbDate(1975, 12, 31, 23,15,30, 560); + TbDate d0 = new TbDate(1975, 12, 31, 23,15,30, 560,"UTC"); + TbDate d1 = new TbDate(1975, 12, 31, 23,15,30, 561,"+03:00"); + TbDate d2 = new TbDate(1975, 12, 31, 23,15,30, 562,"-02:00"); + TbDate dLocal = new TbDate(d.parseSecondMilli() + d.getLocaleZoneOffset().getTotalSeconds()*1000); + TbDate dLocal0 = new TbDate(d0.parseSecondMilli() + d0.getLocaleZoneOffset().getTotalSeconds()*1000); + TbDate dLocal1 = new TbDate(d1.parseSecondMilli() + d1.getLocaleZoneOffset().getTotalSeconds()*1000); + TbDate dLocal2 = new TbDate(d2.parseSecondMilli() + d2.getLocaleZoneOffset().getTotalSeconds()*1000); + + Assert.assertEquals(dLocal.getUTCFullYear(), d.getFullYear()); + Assert.assertEquals(dLocal0.getUTCFullYear(), d0.getFullYear()); Assert.assertEquals(dLocal1.getUTCFullYear(), d1.getFullYear()); Assert.assertEquals(dLocal2.getUTCFullYear(), d2.getFullYear()); + Assert.assertEquals(dLocal.getUTCMonth(), d.getMonth()); + Assert.assertEquals(dLocal0.getUTCMonth(), d0.getMonth()); Assert.assertEquals(dLocal1.getUTCMonth(), d1.getMonth()); Assert.assertEquals(dLocal2.getUTCMonth(), d2.getMonth()); + Assert.assertEquals(dLocal.getUTCDate(), d.getDate()); + Assert.assertEquals(dLocal0.getUTCDate(), d0.getDate()); Assert.assertEquals(dLocal1.getUTCDate(), d1.getDate()); Assert.assertEquals(dLocal2.getUTCDate(), d2.getDate()); + Assert.assertEquals(dLocal.getUTCDay(), d.getDay()); + Assert.assertEquals(dLocal0.getUTCDay(), d0.getDay()); Assert.assertEquals(dLocal1.getUTCDay(), d1.getDay()); - Assert.assertEquals(dLocal1.getUTCDay(), d2.getDay()); + Assert.assertEquals(dLocal2.getUTCDay(), d2.getDay()); + Assert.assertEquals(dLocal.getUTCHours(), d.getHours()); + Assert.assertEquals(dLocal0.getUTCHours(), d0.getHours()); Assert.assertEquals(dLocal1.getUTCHours(), d1.getHours()); Assert.assertEquals(dLocal2.getUTCHours(), d2.getHours()); + Assert.assertEquals(dLocal.getUTCMinutes(), d.getMinutes()); + Assert.assertEquals(dLocal0.getUTCMinutes(), d0.getMinutes()); Assert.assertEquals(dLocal1.getUTCMinutes(), d1.getMinutes()); Assert.assertEquals(dLocal2.getUTCMinutes(), d2.getMinutes()); + Assert.assertEquals(dLocal.getUTCSeconds(), d.getSeconds()); + Assert.assertEquals(dLocal0.getUTCSeconds(), d0.getSeconds()); Assert.assertEquals(dLocal1.getUTCSeconds(), d1.getSeconds()); Assert.assertEquals(dLocal2.getUTCSeconds(), d2.getSeconds()); + Assert.assertEquals(dLocal.getUTCMilliseconds(), d.getMilliseconds()); + Assert.assertEquals(dLocal0.getUTCMilliseconds(), d0.getMilliseconds()); Assert.assertEquals(dLocal1.getUTCMilliseconds(), d1.getMilliseconds()); Assert.assertEquals(dLocal2.getUTCMilliseconds(), d2.getMilliseconds()); } + @Test + void Test_Year_Moth_Date_Hours_Min_Sec_Without_TZ() { + TbDate d = new TbDate(2023, 8, 18); + Assert.assertEquals("2023-08-18 00:00:00", d.toLocaleString()); + d = new TbDate(2023, 9, 17, 17, 34); + Assert.assertEquals("2023-09-17 17:34:00", d.toLocaleString()); + d = new TbDate(23, 9, 7, 8, 4); + Assert.assertEquals("2023-09-07 08:04:00", d.toLocaleString()); + d = new TbDate(23, 9, 7, 8, 4, 5); + Assert.assertEquals("2023-09-07 08:04:05", d.toLocaleString()); + d = new TbDate(23, 9, 7, 8, 4, 5, 567); + Assert.assertEquals("2023-09-07 08:04:05", d.toLocaleString()); + } + + /** + * Tests for: + * min TZ = "Etc/GMT+12" = '-12' + * max TZ = "Etc/GMT-14" = '+14' + */ + @Test + void Test_Get_LocalDateTime_With_TZ() { + int hrs = 8; + int date = 7; + int tz = 0; + String pattern = "2023-09-%s %s:04:05"; + String tzStr = "+00:00"; + TbDate d = new TbDate(23, 9, date, hrs, 4, 5, tzStr); + int localOffsetHrs = ZoneId.systemDefault().getRules().getOffset(d.getInstant()).getTotalSeconds()/60/60; + TbDateTestEntity tbDateTest = new TbDateTestEntity(23, 9, date, hrs + localOffsetHrs - tz); + String expected = String.format(pattern, tbDateTest.geDateStr(), tbDateTest.geHoursStr()); + Assert.assertEquals(expected, d.toLocaleString()); + + tz = 3; + tzStr = "+03:00"; + d = new TbDate(23, 9, date, hrs, 4, 5, tzStr); + localOffsetHrs = ZoneId.systemDefault().getRules().getOffset(d.getInstant()).getTotalSeconds()/60/60; + tbDateTest = new TbDateTestEntity(23, 9, date, hrs + localOffsetHrs - tz); + expected = String.format(pattern, tbDateTest.geDateStr(), tbDateTest.geHoursStr()); + Assert.assertEquals(expected, d.toLocaleString()); + + tz = -4; + tzStr = "-04:00"; + d = new TbDate(23, 9, date, hrs, 4, 5, tzStr); + localOffsetHrs = ZoneId.systemDefault().getRules().getOffset(d.getInstant()).getTotalSeconds()/60/60; + tbDateTest = new TbDateTestEntity(23, 9, date, hrs + localOffsetHrs - tz); + expected = String.format(pattern, tbDateTest.geDateStr(), tbDateTest.geHoursStr()); + Assert.assertEquals(expected, d.toLocaleString()); + } + + @Test + void TestMethodGetTimeUTC() { + TbDate dd = new TbDate(TbDate.UTC(1996, 1, 2, 3, 4, 5)); + Assert.assertEquals(820551845000L, dd.valueOf()); + dd = new TbDate(1996, 1, 2, 3, 4, 5); + Assert.assertEquals(820544645000L, dd.valueOf()); + TbDate beforeStartUTC = new TbDate(1969, 7, 20, 20, 17, 40); + Assert.assertEquals(-14193740000L, beforeStartUTC.getTime()); + + TbDate d = new TbDate(1975, 12, 31, 23,15,30, 560); + TbDate d0 = new TbDate(1975, 12, 31, 23,15,30, 560,"UTC"); + TbDate d1 = new TbDate(1975, 12, 31, 23,15,30, 561,"+03:00"); + TbDate d2 = new TbDate(1975, 12, 31, 23,15,30, 562,"-04:00"); + + Assert.assertEquals(189288930560L, d.valueOf()); + Assert.assertEquals(189299730560L, d0.valueOf()); + Assert.assertEquals(189288930561L, d1.valueOf()); + Assert.assertEquals(189314130562L, d2.getTime()); + } + @Test void TestMethodSetUTCFullYearMonthDate() { - TbDate d1 = new TbDate(1975, 12, 31, 23,15,30, 567,"-03:00"); - Assert.assertEquals(1976, d1.getUTCFullYear()); - Assert.assertEquals(4, d1.getUTCDay()); + TbDate d1 = new TbDate(1975, 12, 31, 23,15,30, 567,"-04:00"); + TbDate d2 = new TbDate(1975, 12, 31, 23,15,30, 567,"+04:00"); + testResultChangeDateTime(d1); + testResultChangeDateTime(d2); + d1.setUTCFullYear(1969); - Assert.assertEquals(1969, d1.getUTCFullYear()); - d1.setUTCFullYear(1975); - Assert.assertEquals(1975, d1.getUTCFullYear()); - Assert.assertEquals(3, d1.getUTCDay()); - d1.setUTCFullYear(1977, 4); - Assert.assertEquals(1977, d1.getUTCFullYear()); - Assert.assertEquals(4, d1.getUTCMonth()); - Assert.assertEquals(5, d1.getUTCDay()); - d1.setUTCFullYear(2023, 2, 24); - Assert.assertEquals(2023, d1.getUTCFullYear()); - Assert.assertEquals(2, d1.getUTCMonth()); - Assert.assertEquals(24, d1.getUTCDate()); - Assert.assertEquals(5, d1.getUTCDay()); + d2.setUTCFullYear(1969); + testResultChangeDateTime(d1); + testResultChangeDateTime(d2); + + d1.setUTCFullYear(1975, 5); + d2.setUTCFullYear(2023, 11); + testResultChangeDateTime(d1); + testResultChangeDateTime(d2); + + d1.setUTCFullYear(2023, 2, 28); + d2.setUTCFullYear(2023, 12, 31); + testResultChangeDateTime(d1); + testResultChangeDateTime(d2); d1.setUTCMonth(11); - Assert.assertEquals(11, d1.getUTCMonth()); - Assert.assertEquals(5, d1.getUTCDay()); - d1.setUTCMonth(2, 28); - Assert.assertEquals(2, d1.getUTCMonth()); - Assert.assertEquals(28, d1.getUTCDate()); - Assert.assertEquals(2, d1.getUTCDay()); - - d1.setUTCDate(11); - Assert.assertEquals(11, d1.getUTCDate()); - Assert.assertEquals(6, d1.getUTCDay()); + d2.setUTCMonth(2); + testResultChangeDateTime(d1); + testResultChangeDateTime(d2); + + d1.setUTCMonth(5, 20); + d2.setUTCMonth(2, 8); + testResultChangeDateTime(d1); + testResultChangeDateTime(d2); + + d1.setUTCDate(6); + d2.setUTCDate(15); + testResultChangeDateTime(d1); + testResultChangeDateTime(d2); } @Test void TestMethodSetUTCHoursMinutesSecondsMilliSec() { - TbDate d1 = new TbDate(1975, 12, 31, 23, 15, 30, 567, "-03:00"); - Assert.assertEquals(2, d1.getUTCHours()); - Assert.assertEquals(4, d1.getUTCDay()); + TbDate d1 = new TbDate(1975, 12, 31, 23, 15, 30, 567, "+02:00"); + TbDate d2 = new TbDate(1975, 12, 31, 23, 15, 30, 567, "-02:00"); + + testResultChangeDateTime(d1); + testResultChangeDateTime(d2); d1.setUTCHours(5); - Assert.assertEquals(5, d1.getUTCHours()); - Assert.assertEquals(4, d1.getUTCDay()); - d1.setUTCHours(12, 45); - Assert.assertEquals(12, d1.getUTCHours()); - Assert.assertEquals(45, d1.getUTCMinutes()); - Assert.assertEquals(4, d1.getUTCDay()); + d2.setUTCHours(23); + testResultChangeDateTime(d1); + testResultChangeDateTime(d2); + + d1.setUTCHours(23, 45); + d2.setUTCHours(1, 5); + testResultChangeDateTime(d1); + testResultChangeDateTime(d2); + d1.setUTCHours(0, 12, 59); - Assert.assertEquals(0, d1.getUTCHours()); - Assert.assertEquals(12, d1.getUTCMinutes()); - Assert.assertEquals(59, d1.getUTCSeconds()); - Assert.assertEquals(4, d1.getUTCDay()); - d1.setUTCHours(4, 58, 2, 456); - Assert.assertEquals(4, d1.getUTCHours()); - Assert.assertEquals(58, d1.getUTCMinutes()); - Assert.assertEquals(2, d1.getUTCSeconds()); - Assert.assertEquals(456, d1.getUTCMilliseconds()); - Assert.assertEquals(4, d1.getUTCDay()); + d2.setUTCHours(4, 45, 01); + testResultChangeDateTime(d1); + testResultChangeDateTime(d2); + + d1.setUTCHours(2, 32, 49, 123); + d2.setUTCHours(8, 45, 12, 234); + testResultChangeDateTime(d1); + testResultChangeDateTime(d2); d1.setUTCMinutes(5); - Assert.assertEquals(5, d1.getUTCMinutes()); - Assert.assertEquals(4, d1.getUTCDay()); - d1.setUTCMinutes(15, 32); - Assert.assertEquals(15, d1.getUTCMinutes()); - Assert.assertEquals(32, d1.getUTCSeconds()); - Assert.assertEquals(4, d1.getUTCDay()); - d1.setUTCMinutes(10, 42, 321); - Assert.assertEquals(10, d1.getUTCMinutes()); - Assert.assertEquals(42, d1.getUTCSeconds()); - Assert.assertEquals(321, d1.getUTCMilliseconds()); - Assert.assertEquals(4, d1.getUTCDay()); + d2.setUTCMinutes(15); + testResultChangeDateTime(d1); + testResultChangeDateTime(d2); - d1.setUTCSeconds(5); - Assert.assertEquals(5, d1.getUTCSeconds()); - Assert.assertEquals(4, d1.getUTCDay()); - d1.setUTCSeconds(15, 32); - Assert.assertEquals(15, d1.getUTCSeconds()); - Assert.assertEquals(32, d1.getUTCMilliseconds()); - Assert.assertEquals(4, d1.getUTCDay()); + d1.setUTCMinutes(5, 34); + d2.setUTCMinutes(25, 43); + testResultChangeDateTime(d1); + testResultChangeDateTime(d2); - d1.setUTCMilliseconds(5); - Assert.assertEquals(5, d1.getUTCMilliseconds()); - Assert.assertEquals(4, d1.getUTCDay()); + d1.setUTCMinutes(25, 14, 567); + d2.setUTCMinutes(45, 3, 876); + testResultChangeDateTime(d1); + testResultChangeDateTime(d2); + + d1.setUTCSeconds(5); + d2.setUTCSeconds(23); + testResultChangeDateTime(d1); + testResultChangeDateTime(d2); + + d1.setUTCSeconds(45, 987); + d2.setUTCSeconds(54, 842); + testResultChangeDateTime(d1); + testResultChangeDateTime(d2); + + d1.setUTCMilliseconds(675); + d1.setUTCMilliseconds(923); + testResultChangeDateTime(d1); + testResultChangeDateTime(d2); } @Test - void TestMethodSetTome() { + void TestMethodSetTime() { TbDate d1 = new TbDate(1975, 12, 31, 23, 15, 30, 567, "-03:00"); long dateMilliSecond = d1.getTime(); int fiveMinutesInMillis = 5 * 60 * 1000; @@ -533,121 +626,141 @@ class TbDateTest { Assert.assertEquals(567, d1.getUTCMilliseconds()); Assert.assertEquals(3, d1.getUTCDay()); } - - @Test + @Test void TestMethodSeFullYearMonthDate() { - TbDate d1 = new TbDate(1975, 12, 31, 23,15,30, 567,"-03:00"); - Assert.assertEquals(1976, d1.getFullYear()); - Assert.assertEquals(1, d1.getMonth()); - Assert.assertEquals(1, d1.getDate()); - Assert.assertEquals(4, d1.getUTCDay()); - d1.setFullYear(1969); - Assert.assertEquals(1969, d1.getFullYear()); - d1.setUTCFullYear(1975); - Assert.assertEquals(1975, d1.getFullYear()); - Assert.assertEquals(3, d1.getUTCDay()); - d1.setFullYear(1977, 4); - Assert.assertEquals(1977, d1.getFullYear()); - Assert.assertEquals(4, d1.getMonth()); - Assert.assertEquals(5, d1.getDay()); - d1.setFullYear(2023, 2, 24); - Assert.assertEquals(2023, d1.getFullYear()); - Assert.assertEquals(2, d1.getMonth()); - Assert.assertEquals(24, d1.getDate()); - Assert.assertEquals(5, d1.getDay()); - - d1.setMonth(11); - Assert.assertEquals(11, d1.getMonth()); - Assert.assertEquals(5, d1.getDay()); - d1.setMonth(2, 28); - Assert.assertEquals(2, d1.getMonth()); - Assert.assertEquals(28, d1.getDate()); - Assert.assertEquals(2, d1.getDay()); - - d1.setDate(11); - Assert.assertEquals(11, d1.getDate()); - Assert.assertEquals(6, d1.getDay()); - } - @Test + TbDate d = new TbDate(2024, 1, 1, 1, 15, 30, 567); + testResultChangeDateTime(d); + + d = new TbDate(2023, 12, 31, 22, 15, 30, 567); + testResultChangeDateTime(d); + + d = new TbDate(1975, 12, 31, 1, 15, 30, 567); + testResultChangeDateTime(d); + + d.setFullYear(1969); + testResultChangeDateTime(d); + + d.setFullYear(1975, 2); + testResultChangeDateTime(d); + + d.setFullYear(2023, 6, 30); + testResultChangeDateTime(d); + + d.setMonth(2); + testResultChangeDateTime(d); + + d.setMonth(1, 24); + testResultChangeDateTime(d); + + d.setDate(6); + testResultChangeDateTime(d); + } + @Test void TestMethodSeHoursMinutesSecondsMilliSec() { - TbDate d1 = new TbDate(1975, 12, 31, 23, 15, 30, 567, "-03:00"); - Assert.assertEquals(5, d1.getHours()); - Assert.assertEquals(4, d1.getDay()); + TbDate d1 = new TbDate(1975, 12, 31, 23, 15, 30, 567, "+02:00"); + TbDate d2 = new TbDate(1975, 12, 31, 23, 15, 30, 567, "-02:00"); + testResultChangeDateTime(d1); + testResultChangeDateTime(d2); d1.setHours(5); - Assert.assertEquals(8, d1.getHours()); - Assert.assertEquals(4, d1.getDay()); + d2.setHours(23); + testResultChangeDateTime(d1); + testResultChangeDateTime(d2); + d1.setHours(23, 45); - Assert.assertEquals(1, d1.getMonth()); - Assert.assertEquals(2, d1.getDate()); - Assert.assertEquals(2, d1.getHours()); - Assert.assertEquals(45, d1.getMinutes()); - Assert.assertEquals(5, d1.getDay()); - d1.setUTCHours(0, 12, 59); - Assert.assertEquals(3, d1.getHours()); - Assert.assertEquals(12, d1.getMinutes()); - Assert.assertEquals(59, d1.getSeconds()); - Assert.assertEquals(4, d1.getDay()); - d1.setUTCHours(4, 58, 2, 456); - Assert.assertEquals(7, d1.getHours()); - Assert.assertEquals(58, d1.getMinutes()); - Assert.assertEquals(2, d1.getSeconds()); - Assert.assertEquals(456, d1.getMilliseconds()); - Assert.assertEquals(4, d1.getDay()); + d2.setHours(1, 5); + testResultChangeDateTime(d1); + testResultChangeDateTime(d2); + + d1.setHours(0, 12, 59); + d2.setHours(4, 45, 1); + testResultChangeDateTime(d1); + testResultChangeDateTime(d2); + + d1.setHours(2, 32, 49, 123); + d2.setHours(8, 45, 12, 234); + testResultChangeDateTime(d1); + testResultChangeDateTime(d2); d1.setMinutes(5); + d2.setMinutes(15); Assert.assertEquals(5, d1.getMinutes()); - Assert.assertEquals(4, d1.getUTCDay()); - d1.setMinutes(15, 32); - Assert.assertEquals(15, d1.getMinutes()); - Assert.assertEquals(32, d1.getSeconds()); - Assert.assertEquals(4, d1.getDay()); - d1.setMinutes(10, 42, 321); - Assert.assertEquals(10, d1.getMinutes()); - Assert.assertEquals(42, d1.getSeconds()); - Assert.assertEquals(321, d1.getMilliseconds()); - Assert.assertEquals(4, d1.getDay()); + Assert.assertEquals(15, d2.getMinutes()); + + d1.setMinutes(5, 34); + d2.setMinutes(25, 43); + Assert.assertEquals(5, d1.getMinutes()); + Assert.assertEquals(34, d1.getSeconds()); + Assert.assertEquals(25, d2.getMinutes()); + Assert.assertEquals(43, d2.getSeconds()); + + d1.setMinutes(25, 14, 567); + d2.setMinutes(45, 3, 876); + Assert.assertEquals(25, d1.getMinutes()); + Assert.assertEquals(14, d1.getSeconds()); + Assert.assertEquals(567, d1.getMilliseconds()); + Assert.assertEquals(45, d2.getMinutes()); + Assert.assertEquals(3, d2.getSeconds()); + Assert.assertEquals(876, d2.getMilliseconds()); d1.setSeconds(5); + d2.setSeconds(23); Assert.assertEquals(5, d1.getSeconds()); - Assert.assertEquals(4, d1.getDay()); - d1.setSeconds(15, 32); - Assert.assertEquals(15, d1.getSeconds()); - Assert.assertEquals(32, d1.getMilliseconds()); - Assert.assertEquals(4, d1.getDay()); - - d1.setMilliseconds(5); - Assert.assertEquals(5, d1.getMilliseconds()); - Assert.assertEquals(4, d1.getDay()); + Assert.assertEquals(23, d2.getSeconds()); + + d1.setSeconds(45, 987); + d2.setSeconds(54, 842); + Assert.assertEquals(45, d1.getSeconds()); + Assert.assertEquals(987, d1.getMilliseconds()); + Assert.assertEquals(54, d2.getSeconds()); + Assert.assertEquals(842, d2.getMilliseconds()); + + d1.setMilliseconds(675); + d2.setMilliseconds(923); + Assert.assertEquals(675, d1.getMilliseconds()); + Assert.assertEquals(923, d2.getMilliseconds()); } @Test public void toStringAsJs() { - TbDate d1 = new TbDate(1975, 12, 31, 23,15,30, 567,"-14:00"); - Assert.assertEquals("1976 Jan 1, Thu 16:15:30 Eastern European Time", d1.toString()); - Assert.assertEquals("1976 Jan 1, Thu 16:15:30 Eastern European Time", d1.toString("GMT")); - Assert.assertEquals("1976 Jan 1, Thu 16:15:30 Eastern European Time", d1.toString("UTC")); - Assert.assertEquals("Thursday, January 1, 1976 at 4:15:30 PM Eastern European Standard Time", d1.toString("en-US")); - Assert.assertEquals("1976 Jan 1, Thu 16:15:30", d1.toUTCString()); - Assert.assertEquals("четвер, 1 січня 1976 р., 16:15:30", d1.toUTCString("uk-UA")); - Assert.assertEquals("Thursday, January 1, 1976, 4:15:30 PM", d1.toUTCString("en-US")); - Assert.assertEquals("четвер, 1 січня 1976 р., 16:15:30", d1.toUTCString("uk-UA")); - Assert.assertEquals("Thursday, January 1, 1976, 4:15:30 PM", d1.toUTCString("en-US")); - Assert.assertEquals("1976 Jan 1, Thu", d1.toDateString()); - Assert.assertEquals("четвер, 1 січня 1976 р.", d1.toDateString("uk-UA")); - Assert.assertEquals("Thursday, January 1, 1976", d1.toDateString("en-US")); - Assert.assertEquals("16:15:30 Eastern European Time", d1.toTimeString()); - Assert.assertEquals("16:15:30 за східноєвропейським стандартним часом", d1.toTimeString("uk-UA")); - Assert.assertEquals("4:15:30 PM Eastern European Standard Time", d1.toTimeString("en-US")); - Assert.assertEquals("1976-01-01T13:15:30.567Z", d1.toJSON()); + TbDate d1 = new TbDate(1975, 12, 31, 23,15,30, 567,"-04:00"); + Assert.assertEquals("четвер, 1 січня 1976 р. о 06:15:30 за східноєвропейським стандартним часом", d1.toString("uk-UA", "Europe/Kyiv")); + Assert.assertEquals("Thursday, January 1, 1976 at 6:15:30 AM Eastern European Standard Time", d1.toString("en-US", "Europe/Kyiv")); + Assert.assertEquals("1976 Jan 1, Thu 06:15:30 Eastern European Time", d1.toString("UTC", "Europe/Kyiv")); + Assert.assertEquals("Wednesday, December 31, 1975 at 10:15:30 PM Eastern Standard Time", d1.toString("en-US", "America/New_York")); + Assert.assertEquals("1975 Dec 31, Wed 22:15:30 Eastern Standard Time", d1.toString("GMT", "America/New_York")); + Assert.assertEquals("1975 Dec 31, Wed 22:15:30 Eastern Standard Time", d1.toString("UTC", "America/New_York")); + + Assert.assertEquals(d1.toUTCString("UTC"), d1.toUTCString()); + Assert.assertEquals("четвер, 1 січня 1976 р., 03:15:30", d1.toUTCString("uk-UA")); + Assert.assertEquals("Thursday, January 1, 1976, 3:15:30 AM", d1.toUTCString("en-US")); + + Assert.assertEquals("1976-01-01T03:15:30.567Z", d1.toJSON()); + Assert.assertEquals("1976-01-01T03:15:30.567Z", d1.toISOString()); + + Assert.assertEquals("1976-01-01 06:15:30", d1.toLocaleString("UTC", "Europe/Kyiv")); + Assert.assertEquals("01.01.76, 06:15:30", d1.toLocaleString("uk-UA", "Europe/Kyiv")); + Assert.assertEquals("1975-12-31 22:15:30", d1.toLocaleString("UTC", "America/New_York")); + Assert.assertEquals("12/31/75, 10:15:30 PM", d1.toLocaleString("en-US", "America/New_York")); + + Assert.assertEquals("1976 Jan 1, Thu", d1.toDateString("UTC", "Europe/Kyiv")); + Assert.assertEquals("четвер, 1 січня 1976 р.", d1.toDateString("uk-UA", "Europe/Kyiv")); + Assert.assertEquals("1975 Dec 31, Wed", d1.toDateString("UTC", "America/New_York")); + Assert.assertEquals("Wednesday, December 31, 1975", d1.toDateString("en-US", "America/New_York")); + + + Assert.assertEquals("06:15:30", d1.toLocaleTimeString("uk-UA", "Europe/Kyiv")); + Assert.assertEquals("06:15:30", d1.toLocaleTimeString("UTC", "Europe/Kyiv")); + Assert.assertEquals("10:15:30 PM", d1.toLocaleTimeString("en-US", "America/New_York")); + Assert.assertEquals("22:15:30", d1.toLocaleTimeString("UTC", "America/New_York")); + + Assert.assertEquals("06:15:30 за східноєвропейським стандартним часом", d1.toTimeString("uk-UA", "Europe/Kyiv")); + Assert.assertEquals("06:15:30 Eastern European Time", d1.toTimeString("UTC", "Europe/Kyiv")); + Assert.assertEquals("10:15:30 PM Eastern Standard Time", d1.toTimeString("en-US", "America/New_York")); + Assert.assertEquals("22:15:30 Eastern Standard Time", d1.toTimeString("UTC", "America/New_York")); + + } - /** - * Date.UTC(0) - * -2208988800000 - * > "Mon, 01 Jan 1900 00:00:00 GMT" - * new Date(Date.UTC(0, 0, 0, 0, 0, 0)); - * "Sun, 31 Dec 1899 00:00:00 GMT" - */ @Test public void toUTC() { Assert.assertEquals(-2209075200000L, TbDate.UTC(0)); @@ -658,11 +771,23 @@ class TbDateTest { Assert.assertEquals("1958-12-31T03:04:05.678Z", new TbDate(TbDate.UTC(1958, 0, 0, 3, 4, 5, 678)).toJSON()); Assert.assertEquals("2032-04-05T03:04:05.678Z", new TbDate(TbDate.UTC(2032, 4, 5, 3, 4, 5, 678)).toJSON()); Assert.assertEquals("2024-02-29T03:04:05.678Z", new TbDate(TbDate.UTC(2024, 2, 29, 3, 4, 5, 678)).toJSON()); - Exception actual = assertThrows(DateTimeParseException.class, () -> { + Exception actual = assertThrows(DateTimeException.class, () -> { TbDate.UTC(2023, 2, 29, 3, 4, 5, 678); }); - String expectedMessage = "could not be parsed"; + String expectedMessage = "Invalid date 'February 29' as '2023' is not a leap year"; assertTrue(actual.getMessage().contains(expectedMessage)); } + + private void testResultChangeDateTime(TbDate d) { + int localOffset = ZoneId.systemDefault().getRules().getOffset(d.getInstant()).getTotalSeconds(); + TbDateTestEntity tbDateTestEntity = new TbDateTestEntity(d.getFullYear(), d.getMonth(), d.getDate(), (d.getHours() - (localOffset/60/60))); + Assert.assertEquals(tbDateTestEntity.getYear(), d.getUTCFullYear()); + Assert.assertEquals(tbDateTestEntity.getMonth(), d.getUTCMonth()); + Assert.assertEquals(tbDateTestEntity.getDate(), d.getUTCDate()); + Assert.assertEquals(tbDateTestEntity.getHours(), d.getUTCHours()); + Assert.assertEquals(d.getMinutes(), d.getUTCMinutes()); + Assert.assertEquals(d.getSeconds(), d.getUTCSeconds()); + Assert.assertEquals(d.getMilliseconds(), d.getUTCMilliseconds()); + } } diff --git a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateTestEntity.java b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateTestEntity.java new file mode 100644 index 0000000000..771eba896b --- /dev/null +++ b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateTestEntity.java @@ -0,0 +1,90 @@ +/** + * 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 lombok.Data; +import java.time.chrono.IsoChronology; +@Data +public class TbDateTestEntity { + private int year; + private int month; + private int date; + private int hours; + public TbDateTestEntity(int year, int month, int date, int hours) { + this.year = year; + this.month = month; + this.date = date; + this.hours = hours; + if (hours > 23) { + if (date == 31) { + this.year++; + this.month = 1; + this.date = 1; + } else { + this.date++; + } + this.hours = hours - 24; + } else if (hours < 0) { + if (month== 1 && date == 1) { + this.year--; + this.month = 12; + this.date = 31; + } else { + this.date--; + } + this.hours = hours + 24; + } + + if (this.date > 28) { + int dom = 31; + switch (month) { + case 2: + dom = IsoChronology.INSTANCE.isLeapYear((long) year) ? 29 : 28; + case 3: + case 5: + case 7: + case 8: + case 10: + default: + break; + case 4: + case 6: + case 9: + case 11: + dom = 30; + } + if (this.date > dom) { + this.date = this.date - dom; + this.month++; + } + } + } + public int getYear(){ + return year < 70 ? 2000 + year : year <= 99 ? 1900 + year : year; + } + + public String geMonthStr(){ + return String.format("%02d", month); + } + + public String geDateStr(){ + return String.format("%02d", date); + } + + public String geHoursStr(){ + return String.format("%02d", hours); + } +} From 69bcd8426e35d85f4cdb1b2b5c19e0698563182a Mon Sep 17 00:00:00 2001 From: nick Date: Tue, 17 Oct 2023 18:42:28 +0300 Subject: [PATCH 08/11] tbDate: Tests were checked with: * -timezone Etc/GMT-14 * -timezone Etc/GMT+12 * -timezone America/New_York * -timezone Europe/Kyiv --- .../script/api/tbel/TbDateTest.java | 86 +++++++++---------- 1 file changed, 42 insertions(+), 44 deletions(-) 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 f020d3e092..af9ff4c5e1 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 @@ -71,6 +71,11 @@ class TbDateTest { * at java.base/java.util.Calendar.setTimeInMillis(Calendar.java:1834) * at java.base/java.util.Calendar.setTime(Calendar.java:1800) * at java.base/java.text.SimpleDateFormat.format(SimpleDateFormat.java:974) + * Tests were checked with: + * -timezone Etc/GMT-14 + * -timezone Etc/GMT+12 + * -timezone America/New_York + * -timezone Europe/Kyiv */ @Test void testToISOStringConcurrently() throws ExecutionException, InterruptedException, TimeoutException { @@ -455,24 +460,25 @@ class TbDateTest { Assert.assertEquals("2023-09-07 08:04:05", d.toLocaleString()); } - /** - * Tests for: - * min TZ = "Etc/GMT+12" = '-12' - * max TZ = "Etc/GMT-14" = '+14' - */ @Test void Test_Get_LocalDateTime_With_TZ() { int hrs = 8; int date = 7; int tz = 0; String pattern = "2023-09-%s %s:04:05"; - String tzStr = "+00:00"; - TbDate d = new TbDate(23, 9, date, hrs, 4, 5, tzStr); - int localOffsetHrs = ZoneId.systemDefault().getRules().getOffset(d.getInstant()).getTotalSeconds()/60/60; + String tzStr = "UTC"; + TbDate d = new TbDate(23, 9, date, hrs, 4, 5); + int localOffsetHrs = 0; TbDateTestEntity tbDateTest = new TbDateTestEntity(23, 9, date, hrs + localOffsetHrs - tz); String expected = String.format(pattern, tbDateTest.geDateStr(), tbDateTest.geHoursStr()); Assert.assertEquals(expected, d.toLocaleString()); + d = new TbDate(23, 9, date, hrs, 4, 5, tzStr); + localOffsetHrs = ZoneId.systemDefault().getRules().getOffset(d.getInstant()).getTotalSeconds()/60/60; + tbDateTest = new TbDateTestEntity(23, 9, date, hrs + localOffsetHrs - tz); + expected = String.format(pattern, tbDateTest.geDateStr(), tbDateTest.geHoursStr()); + Assert.assertEquals(expected, d.toLocaleString()); + tz = 3; tzStr = "+03:00"; d = new TbDate(23, 9, date, hrs, 4, 5, tzStr); @@ -490,24 +496,36 @@ class TbDateTest { Assert.assertEquals(expected, d.toLocaleString()); } + @Test + public void TestToUTC() { + Assert.assertEquals(-2209075200000L, TbDate.UTC(0)); + Assert.assertEquals("1899-12-31T00:00:00Z", new TbDate(TbDate.UTC(0)).toJSON()); + Assert.assertEquals("1996-02-02T03:04:05Z", new TbDate(TbDate.UTC(96, 2, 2, 3, 4, 5)).toJSON()); + Assert.assertEquals("2022-12-31T03:04:05.678Z", new TbDate(TbDate.UTC(22, 0, 0, 3, 4, 5, 678)).toJSON()); + Assert.assertEquals("0903-12-31T03:04:05.678Z", new TbDate(TbDate.UTC(903, 0, 0, 3, 4, 5, 678)).toJSON()); + Assert.assertEquals("1958-12-31T03:04:05.678Z", new TbDate(TbDate.UTC(1958, 0, 0, 3, 4, 5, 678)).toJSON()); + Assert.assertEquals("2032-04-05T03:04:05.678Z", new TbDate(TbDate.UTC(2032, 4, 5, 3, 4, 5, 678)).toJSON()); + Assert.assertEquals("2024-02-29T03:04:05.678Z", new TbDate(TbDate.UTC(2024, 2, 29, 3, 4, 5, 678)).toJSON()); + Exception actual = assertThrows(DateTimeException.class, () -> { + TbDate.UTC(2023, 2, 29, 3, 4, 5, 678); + }); + String expectedMessage = "Invalid date 'February 29' as '2023' is not a leap year"; + assertTrue(actual.getMessage().contains(expectedMessage)); + } + @Test void TestMethodGetTimeUTC() { - TbDate dd = new TbDate(TbDate.UTC(1996, 1, 2, 3, 4, 5)); - Assert.assertEquals(820551845000L, dd.valueOf()); - dd = new TbDate(1996, 1, 2, 3, 4, 5); - Assert.assertEquals(820544645000L, dd.valueOf()); + TbDate ddUTC = new TbDate(TbDate.UTC(1996, 1, 2, 3, 4, 5)); + Assert.assertEquals(820551845000L, ddUTC.valueOf()); + TbDate dd = new TbDate(1996, 1, 2, 3, 4, 5); + int localOffsetMilli = ZoneId.systemDefault().getRules().getOffset(dd.getInstant()).getTotalSeconds()*1000; + Assert.assertEquals((dd.valueOf() + localOffsetMilli), ddUTC.valueOf()); + + ddUTC = new TbDate(TbDate.UTC(1969, 7, 20, 20, 17, 40)); + Assert.assertEquals(-14182940000L, ddUTC.valueOf()); TbDate beforeStartUTC = new TbDate(1969, 7, 20, 20, 17, 40); - Assert.assertEquals(-14193740000L, beforeStartUTC.getTime()); - - TbDate d = new TbDate(1975, 12, 31, 23,15,30, 560); - TbDate d0 = new TbDate(1975, 12, 31, 23,15,30, 560,"UTC"); - TbDate d1 = new TbDate(1975, 12, 31, 23,15,30, 561,"+03:00"); - TbDate d2 = new TbDate(1975, 12, 31, 23,15,30, 562,"-04:00"); - - Assert.assertEquals(189288930560L, d.valueOf()); - Assert.assertEquals(189299730560L, d0.valueOf()); - Assert.assertEquals(189288930561L, d1.valueOf()); - Assert.assertEquals(189314130562L, d2.getTime()); + localOffsetMilli = ZoneId.systemDefault().getRules().getOffset(beforeStartUTC.getInstant()).getTotalSeconds()*1000; + Assert.assertEquals((beforeStartUTC.valueOf() + localOffsetMilli), ddUTC.valueOf()); } @Test @@ -747,35 +765,15 @@ class TbDateTest { Assert.assertEquals("1975 Dec 31, Wed", d1.toDateString("UTC", "America/New_York")); Assert.assertEquals("Wednesday, December 31, 1975", d1.toDateString("en-US", "America/New_York")); - Assert.assertEquals("06:15:30", d1.toLocaleTimeString("uk-UA", "Europe/Kyiv")); Assert.assertEquals("06:15:30", d1.toLocaleTimeString("UTC", "Europe/Kyiv")); Assert.assertEquals("10:15:30 PM", d1.toLocaleTimeString("en-US", "America/New_York")); Assert.assertEquals("22:15:30", d1.toLocaleTimeString("UTC", "America/New_York")); - Assert.assertEquals("06:15:30 за східноєвропейським стандартним часом", d1.toTimeString("uk-UA", "Europe/Kyiv")); + Assert.assertEquals("06:15:30 за східноєвропейським стандартним часом", d1.toTimeString("uk-UA", "Europe/Kyiv")); Assert.assertEquals("06:15:30 Eastern European Time", d1.toTimeString("UTC", "Europe/Kyiv")); Assert.assertEquals("10:15:30 PM Eastern Standard Time", d1.toTimeString("en-US", "America/New_York")); Assert.assertEquals("22:15:30 Eastern Standard Time", d1.toTimeString("UTC", "America/New_York")); - - - } - - @Test - public void toUTC() { - Assert.assertEquals(-2209075200000L, TbDate.UTC(0)); - Assert.assertEquals("1899-12-31T00:00:00Z", new TbDate(TbDate.UTC(0)).toJSON()); - Assert.assertEquals("1996-02-02T03:04:05Z", new TbDate(TbDate.UTC(96, 2, 2, 3, 4, 5)).toJSON()); - Assert.assertEquals("2022-12-31T03:04:05.678Z", new TbDate(TbDate.UTC(22, 0, 0, 3, 4, 5, 678)).toJSON()); - Assert.assertEquals("0903-12-31T03:04:05.678Z", new TbDate(TbDate.UTC(903, 0, 0, 3, 4, 5, 678)).toJSON()); - Assert.assertEquals("1958-12-31T03:04:05.678Z", new TbDate(TbDate.UTC(1958, 0, 0, 3, 4, 5, 678)).toJSON()); - Assert.assertEquals("2032-04-05T03:04:05.678Z", new TbDate(TbDate.UTC(2032, 4, 5, 3, 4, 5, 678)).toJSON()); - Assert.assertEquals("2024-02-29T03:04:05.678Z", new TbDate(TbDate.UTC(2024, 2, 29, 3, 4, 5, 678)).toJSON()); - Exception actual = assertThrows(DateTimeException.class, () -> { - TbDate.UTC(2023, 2, 29, 3, 4, 5, 678); - }); - String expectedMessage = "Invalid date 'February 29' as '2023' is not a leap year"; - assertTrue(actual.getMessage().contains(expectedMessage)); } private void testResultChangeDateTime(TbDate d) { From dfb1200e958c9d1e575db737604d510184549a9f Mon Sep 17 00:00:00 2001 From: nick Date: Tue, 24 Oct 2023 16:11:00 +0300 Subject: [PATCH 09/11] tbDate: comments2 --- .../thingsboard/script/api/tbel/TbDate.java | 37 ++++++++++--------- .../script/api/tbel/TbDateTest.java | 33 ++++++++--------- 2 files changed, 35 insertions(+), 35 deletions(-) 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 146de4570f..591084f986 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 @@ -46,6 +46,9 @@ public class TbDate implements Serializable, Cloneable { private static final ZoneId zoneIdUTC = ZoneId.of("UTC"); private static final Locale localeUTC = Locale.forLanguageTag("UTC"); + private static final DateTimeFormatter isoDateFormatter = DateTimeFormatter.ofPattern( + "yyyy-MM-dd[[ ]['T']HH:mm[:ss[.SSS]][ ][XXX][Z][z][VV][O]]").withZone(ZoneId.systemDefault()); + public TbDate() { this.instant = Instant.now(); } @@ -108,8 +111,8 @@ public class TbDate implements Serializable, Cloneable { public String toDateString(String locale) { return toDateString(locale, ZoneId.systemDefault().toString()); } - public String toDateString(String locale, String zoneStr) { - return toLocaleDateString(locale, JacksonUtil.newObjectNode().put("dateStyle", FormatStyle.FULL.name()).put("timeZone", zoneStr).toString()); + public String toDateString(String localeStr, String zoneStr) { + return toLocaleTbString(localeStr, zoneStr, (locale, options) -> DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).withLocale(locale)); } public String toTimeString() { return toTimeString(Locale.getDefault().getLanguage()); @@ -117,8 +120,8 @@ public class TbDate implements Serializable, Cloneable { public String toTimeString(String locale) { return toTimeString(locale, ZoneId.systemDefault().toString()); } - public String toTimeString(String locale, String zoneStr) { - return toLocaleTbTimeString(locale, JacksonUtil.newObjectNode().put("timeStyle", FormatStyle.FULL.name()).put("timeZone", zoneStr).toString()); + public String toTimeString(String localeStr, String zoneStr) { + return toLocaleTbString(localeStr, zoneStr, (locale, options) -> DateTimeFormatter.ofLocalizedTime(FormatStyle.FULL).withLocale(locale)); } public String toISOString() { @@ -131,8 +134,8 @@ public class TbDate implements Serializable, Cloneable { return toUTCString(localeUTC.getLanguage()); } - public String toUTCString(String locale) { - return toLocaleTbString(locale, JacksonUtil.newObjectNode().put("dateStyle", FormatStyle.FULL.name()).put("timeStyle", FormatStyle.MEDIUM.name()).put("timeZone", zoneIdUTC.getId()).toString()); + public String toUTCString(String localeStr) { + return toLocaleTbString(localeStr, zoneIdUTC.getId(), (locale, options) -> DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL, FormatStyle.MEDIUM).withLocale(locale)); } public String toString() { @@ -143,8 +146,8 @@ public class TbDate implements Serializable, Cloneable { return toString(locale, ZoneId.systemDefault().toString()); } - public String toString(String locale, String zoneStr) { - return toLocaleTbString(locale, JacksonUtil.newObjectNode().put("dateStyle", FormatStyle.FULL.name()).put("timeStyle", FormatStyle.FULL.name()).put("timeZone", zoneStr).toString()); + public String toString(String localeStr, String zoneStr) { + return toLocaleTbString(localeStr, zoneStr, (locale, options) -> DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL, FormatStyle.FULL).withLocale(locale)); } public String toISOZonedDateTimeString() { return getZonedDateTime().toString(); @@ -157,8 +160,8 @@ public class TbDate implements Serializable, Cloneable { return toLocaleDateString(localeUTC.getLanguage()); } - public String toLocaleDateString(String locale) { - return toLocaleDateString(locale, JacksonUtil.newObjectNode().put("dateStyle", FormatStyle.FULL.name()).put("timeZone", ZoneId.systemDefault().toString()).toString()); + public String toLocaleDateString(String localeStr) { + return toLocaleTbString(localeStr, ZoneId.systemDefault().toString(), (locale, options) -> DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).withLocale(locale)); } public String toLocaleDateString(String localeStr, String optionsStr) { @@ -170,14 +173,14 @@ public class TbDate implements Serializable, Cloneable { } public String toLocaleTimeString(String localeStr) { - return toLocaleTimeString(localeStr, ZoneId.systemDefault().toString()); + return toLocaleTimeStringWithZoneId(localeStr, ZoneId.systemDefault().toString()); } - public String toLocaleTimeString(String localeStr, String zoneStr) { - return toLocaleTbTimeString(localeStr, JacksonUtil.newObjectNode().put("timeStyle", FormatStyle.MEDIUM.name()).put("timeZone", zoneStr).toString()); + public String toLocaleTimeStringWithZoneId(String localeStr, String zoneStr) { + return toLocaleTbString(localeStr, zoneStr, (locale, options) -> DateTimeFormatter.ofLocalizedTime(options.getTimeStyle()).withLocale(locale)); } - public String toLocaleTbTimeString(String localeStr, String optionsStr) { + public String toLocaleTimeString(String localeStr, String optionsStr) { return toLocaleTbString(localeStr, optionsStr, (locale, options) -> DateTimeFormatter.ofLocalizedTime(options.getTimeStyle()).withLocale(locale)); } @@ -189,8 +192,8 @@ public class TbDate implements Serializable, Cloneable { return toLocaleString(locale, ZoneId.systemDefault().toString()); } - public String toLocaleString(String locale, String zoneStr) { - return toLocaleTbString(locale, JacksonUtil.newObjectNode().put("dateStyle", FormatStyle.SHORT.name()).put("timeStyle", FormatStyle.MEDIUM.name()).put("timeZone", zoneStr).toString()); + public String toLocaleString(String localeStr, String zoneStr) { + return toLocaleTbString(localeStr, zoneStr, (locale, options) -> DateTimeFormatter.ofLocalizedDateTime(options.getDateStyle(), options.getTimeStyle()).withLocale(locale)); } public String toLocaleTbString(String localeStr, String optionsStr) { @@ -489,8 +492,6 @@ public class TbDate implements Serializable, Cloneable { } } public static long parse(String value) { - DateTimeFormatter isoDateFormatter = DateTimeFormatter.ofPattern( - "yyyy-MM-dd[[ ]['T']HH:mm[:ss[.SSS]][ ][XXX][Z][z][VV][O]]").withZone(ZoneId.systemDefault()); try { TemporalAccessor accessor = isoDateFormatter.parseBest(value, ZonedDateTime::from, 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 af9ff4c5e1..cf74ff3cb2 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 @@ -223,41 +223,41 @@ class TbDateTest { Assert.assertNotNull(d.toLocaleTimeString()); Assert.assertNotNull(d.toLocaleTimeString("en-US")); - Assert.assertEquals("9:04:05 PM", d.toLocaleTbTimeString("en-US", "America/New_York")); - Assert.assertEquals("오후 9:04:05", d.toLocaleTbTimeString("ko-KR", "America/New_York")); - Assert.assertEquals("04:04:05", d.toLocaleTbTimeString( "uk-UA", "Europe/Kiev")); - Assert.assertEquals("9:04:05 م", d.toLocaleTbTimeString( "ar-EG", "America/New_York")); + Assert.assertEquals("9:04:05 PM", d.toLocaleTimeString("en-US", "America/New_York")); + Assert.assertEquals("오후 9:04:05", d.toLocaleTimeString("ko-KR", "America/New_York")); + Assert.assertEquals("04:04:05", d.toLocaleTimeString( "uk-UA", "Europe/Kiev")); + Assert.assertEquals("9:04:05 م", d.toLocaleTimeString( "ar-EG", "America/New_York")); - Assert.assertEquals("9:04:05 PM Eastern Daylight Time", d.toLocaleTbTimeString("en-US", JacksonUtil.newObjectNode() + Assert.assertEquals("9:04:05 PM Eastern Daylight Time", d.toLocaleTimeString("en-US", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("timeStyle", "full") .toString())); - Assert.assertEquals("오후 9시 4분 5초 미 동부 하계 표준시", d.toLocaleTbTimeString("ko-KR", JacksonUtil.newObjectNode() + Assert.assertEquals("오후 9시 4분 5초 미 동부 하계 표준시", d.toLocaleTimeString("ko-KR", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("timeStyle", "full") .toString())); - Assert.assertEquals("04:04:05 за східноєвропейським літнім часом", d.toLocaleTbTimeString("uk-UA", JacksonUtil.newObjectNode() + Assert.assertEquals("04:04:05 за східноєвропейським літнім часом", d.toLocaleTimeString("uk-UA", JacksonUtil.newObjectNode() .put("timeZone", "Europe/Kiev") .put("timeStyle", "full") .toString())); - Assert.assertEquals("9:04:05 م التوقيت الصيفي الشرقي لأمريكا الشمالية", d.toLocaleTbTimeString("ar-EG", JacksonUtil.newObjectNode() + Assert.assertEquals("9:04:05 م التوقيت الصيفي الشرقي لأمريكا الشمالية", d.toLocaleTimeString("ar-EG", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("timeStyle", "full") .toString())); - Assert.assertEquals("9:04:05 PM", d.toLocaleTbTimeString("en-US", JacksonUtil.newObjectNode() + Assert.assertEquals("9:04:05 PM", d.toLocaleTimeString("en-US", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("pattern", "h:mm:ss a") .toString())); - Assert.assertEquals("9:04:05 오후", d.toLocaleTbTimeString("ko-KR", JacksonUtil.newObjectNode() + Assert.assertEquals("9:04:05 오후", d.toLocaleTimeString("ko-KR", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("pattern", "h:mm:ss a") .toString())); - Assert.assertEquals("4:04:05 дп", d.toLocaleTbTimeString("uk-UA", JacksonUtil.newObjectNode() + Assert.assertEquals("4:04:05 дп", d.toLocaleTimeString("uk-UA", JacksonUtil.newObjectNode() .put("timeZone", "Europe/Kiev") .put("pattern", "h:mm:ss a") .toString())); - Assert.assertEquals("9:04:05 م", d.toLocaleTbTimeString("ar-EG", JacksonUtil.newObjectNode() + Assert.assertEquals("9:04:05 م", d.toLocaleTimeString("ar-EG", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("pattern", "h:mm:ss a") .toString())); @@ -765,10 +765,10 @@ class TbDateTest { Assert.assertEquals("1975 Dec 31, Wed", d1.toDateString("UTC", "America/New_York")); Assert.assertEquals("Wednesday, December 31, 1975", d1.toDateString("en-US", "America/New_York")); - Assert.assertEquals("06:15:30", d1.toLocaleTimeString("uk-UA", "Europe/Kyiv")); - Assert.assertEquals("06:15:30", d1.toLocaleTimeString("UTC", "Europe/Kyiv")); - Assert.assertEquals("10:15:30 PM", d1.toLocaleTimeString("en-US", "America/New_York")); - Assert.assertEquals("22:15:30", d1.toLocaleTimeString("UTC", "America/New_York")); + Assert.assertEquals("06:15:30", d1.toLocaleTimeStringWithZoneId("uk-UA", "Europe/Kyiv")); + Assert.assertEquals("06:15:30", d1.toLocaleTimeStringWithZoneId("UTC", "Europe/Kyiv")); + Assert.assertEquals("10:15:30 PM", d1.toLocaleTimeStringWithZoneId("en-US", "America/New_York")); + Assert.assertEquals("22:15:30", d1.toLocaleTimeStringWithZoneId("UTC", "America/New_York")); Assert.assertEquals("06:15:30 за східноєвропейським стандартним часом", d1.toTimeString("uk-UA", "Europe/Kyiv")); Assert.assertEquals("06:15:30 Eastern European Time", d1.toTimeString("UTC", "Europe/Kyiv")); @@ -788,4 +788,3 @@ class TbDateTest { Assert.assertEquals(d.getMilliseconds(), d.getUTCMilliseconds()); } } - From 2046c4863f5c2ebf9a2927856d3889a034c2f510 Mon Sep 17 00:00:00 2001 From: nick Date: Tue, 24 Oct 2023 16:48:08 +0300 Subject: [PATCH 10/11] tbDate: comments3 --- .../thingsboard/script/api/tbel/TbDate.java | 42 +++++++++---------- .../script/api/tbel/TbDateTest.java | 8 ++-- 2 files changed, 23 insertions(+), 27 deletions(-) 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 591084f986..0e406cf6dd 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 @@ -111,8 +111,8 @@ public class TbDate implements Serializable, Cloneable { public String toDateString(String locale) { return toDateString(locale, ZoneId.systemDefault().toString()); } - public String toDateString(String localeStr, String zoneStr) { - return toLocaleTbString(localeStr, zoneStr, (locale, options) -> DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).withLocale(locale)); + public String toDateString(String localeStr, String optionsStr) { + return toLocaleString(localeStr, optionsStr, (locale, options) -> DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).withLocale(locale)); } public String toTimeString() { return toTimeString(Locale.getDefault().getLanguage()); @@ -120,8 +120,8 @@ public class TbDate implements Serializable, Cloneable { public String toTimeString(String locale) { return toTimeString(locale, ZoneId.systemDefault().toString()); } - public String toTimeString(String localeStr, String zoneStr) { - return toLocaleTbString(localeStr, zoneStr, (locale, options) -> DateTimeFormatter.ofLocalizedTime(FormatStyle.FULL).withLocale(locale)); + public String toTimeString(String localeStr, String optionsStr) { + return toLocaleString(localeStr, optionsStr, (locale, options) -> DateTimeFormatter.ofLocalizedTime(FormatStyle.FULL).withLocale(locale)); } public String toISOString() { @@ -135,7 +135,7 @@ public class TbDate implements Serializable, Cloneable { } public String toUTCString(String localeStr) { - return toLocaleTbString(localeStr, zoneIdUTC.getId(), (locale, options) -> DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL, FormatStyle.MEDIUM).withLocale(locale)); + return toLocaleString(localeStr, zoneIdUTC.getId(), (locale, options) -> DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL, FormatStyle.MEDIUM).withLocale(locale)); } public String toString() { @@ -146,8 +146,8 @@ public class TbDate implements Serializable, Cloneable { return toString(locale, ZoneId.systemDefault().toString()); } - public String toString(String localeStr, String zoneStr) { - return toLocaleTbString(localeStr, zoneStr, (locale, options) -> DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL, FormatStyle.FULL).withLocale(locale)); + public String toString(String localeStr, String optionsStr) { + return toLocaleString(localeStr, optionsStr, (locale, options) -> DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL, FormatStyle.FULL).withLocale(locale)); } public String toISOZonedDateTimeString() { return getZonedDateTime().toString(); @@ -161,11 +161,11 @@ public class TbDate implements Serializable, Cloneable { } public String toLocaleDateString(String localeStr) { - return toLocaleTbString(localeStr, ZoneId.systemDefault().toString(), (locale, options) -> DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).withLocale(locale)); + return toLocaleString(localeStr, ZoneId.systemDefault().toString(), (locale, options) -> DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).withLocale(locale)); } public String toLocaleDateString(String localeStr, String optionsStr) { - return toLocaleTbString(localeStr, optionsStr, (locale, options) -> DateTimeFormatter.ofLocalizedDate(options.getDateStyle()).withLocale(locale)); + return toLocaleString(localeStr, optionsStr, (locale, options) -> DateTimeFormatter.ofLocalizedDate(options.getDateStyle()).withLocale(locale)); } public String toLocaleTimeString() { @@ -173,15 +173,11 @@ public class TbDate implements Serializable, Cloneable { } public String toLocaleTimeString(String localeStr) { - return toLocaleTimeStringWithZoneId(localeStr, ZoneId.systemDefault().toString()); - } - - public String toLocaleTimeStringWithZoneId(String localeStr, String zoneStr) { - return toLocaleTbString(localeStr, zoneStr, (locale, options) -> DateTimeFormatter.ofLocalizedTime(options.getTimeStyle()).withLocale(locale)); + return toLocaleTimeString(localeStr, ZoneId.systemDefault().toString()); } public String toLocaleTimeString(String localeStr, String optionsStr) { - return toLocaleTbString(localeStr, optionsStr, (locale, options) -> DateTimeFormatter.ofLocalizedTime(options.getTimeStyle()).withLocale(locale)); + return toLocaleString(localeStr, optionsStr, (locale, options) -> DateTimeFormatter.ofLocalizedTime(options.getTimeStyle()).withLocale(locale)); } public String toLocaleString() { @@ -192,12 +188,12 @@ public class TbDate implements Serializable, Cloneable { return toLocaleString(locale, ZoneId.systemDefault().toString()); } - public String toLocaleString(String localeStr, String zoneStr) { - return toLocaleTbString(localeStr, zoneStr, (locale, options) -> DateTimeFormatter.ofLocalizedDateTime(options.getDateStyle(), options.getTimeStyle()).withLocale(locale)); + public String toLocaleString(String localeStr, String optionsStr) { + return toLocaleString(localeStr, optionsStr, (locale, options) -> DateTimeFormatter.ofLocalizedDateTime(options.getDateStyle(), options.getTimeStyle()).withLocale(locale)); } public String toLocaleTbString(String localeStr, String optionsStr) { - return toLocaleTbString(localeStr, optionsStr, (locale, options) -> { + return toLocaleString(localeStr, optionsStr, (locale, options) -> { String formatPattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern( options.getDateStyle(), @@ -208,7 +204,7 @@ public class TbDate implements Serializable, Cloneable { }); } - public String toLocaleTbString(String localeStr, String optionsStr, BiFunction formatterBuilder) { + public String toLocaleString(String localeStr, String optionsStr, BiFunction formatterBuilder) { Locale locale = StringUtils.isNotEmpty(localeStr) ? Locale.forLanguageTag(localeStr) : Locale.getDefault(); DateTimeFormatOptions options = getDateFormattingOptions(optionsStr); ZonedDateTime zdt = this.getInstant().atZone(options.getTimeZone().toZoneId()); @@ -221,13 +217,13 @@ public class TbDate implements Serializable, Cloneable { return formatter.format(zdt); } - private DateTimeFormatOptions getDateFormattingOptions(String options) { + private DateTimeFormatOptions getDateFormattingOptions(String optionsStr) { DateTimeFormatOptions opt = null; - if (StringUtils.isNotEmpty(options)) { + if (StringUtils.isNotEmpty(optionsStr)) { try { - opt = JacksonUtil.fromString(options, DateTimeFormatOptions.class); + opt = JacksonUtil.fromString(optionsStr, DateTimeFormatOptions.class); } catch (IllegalArgumentException iae) { - opt = new DateTimeFormatOptions(options); + opt = new DateTimeFormatOptions(optionsStr); } } if (opt == null) { 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 cf74ff3cb2..e6c9b3b140 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 @@ -765,10 +765,10 @@ class TbDateTest { Assert.assertEquals("1975 Dec 31, Wed", d1.toDateString("UTC", "America/New_York")); Assert.assertEquals("Wednesday, December 31, 1975", d1.toDateString("en-US", "America/New_York")); - Assert.assertEquals("06:15:30", d1.toLocaleTimeStringWithZoneId("uk-UA", "Europe/Kyiv")); - Assert.assertEquals("06:15:30", d1.toLocaleTimeStringWithZoneId("UTC", "Europe/Kyiv")); - Assert.assertEquals("10:15:30 PM", d1.toLocaleTimeStringWithZoneId("en-US", "America/New_York")); - Assert.assertEquals("22:15:30", d1.toLocaleTimeStringWithZoneId("UTC", "America/New_York")); + Assert.assertEquals("06:15:30", d1.toLocaleTimeString("uk-UA", "Europe/Kyiv")); + Assert.assertEquals("06:15:30", d1.toLocaleTimeString("UTC", "Europe/Kyiv")); + Assert.assertEquals("10:15:30 PM", d1.toLocaleTimeString("en-US", "America/New_York")); + Assert.assertEquals("22:15:30", d1.toLocaleTimeString("UTC", "America/New_York")); Assert.assertEquals("06:15:30 за східноєвропейським стандартним часом", d1.toTimeString("uk-UA", "Europe/Kyiv")); Assert.assertEquals("06:15:30 Eastern European Time", d1.toTimeString("UTC", "Europe/Kyiv")); From 5a0b942b7547888de0d465d53df26b6373d24235 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 25 Oct 2023 15:57:42 +0300 Subject: [PATCH 11/11] Fix backward compatibility --- .../thingsboard/script/api/tbel/TbDate.java | 15 ++--------- .../script/api/tbel/TbDateTest.java | 25 ++++++++++--------- 2 files changed, 15 insertions(+), 25 deletions(-) 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 0e406cf6dd..34c4669f1e 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 @@ -189,19 +189,8 @@ public class TbDate implements Serializable, Cloneable { } public String toLocaleString(String localeStr, String optionsStr) { - return toLocaleString(localeStr, optionsStr, (locale, options) -> DateTimeFormatter.ofLocalizedDateTime(options.getDateStyle(), options.getTimeStyle()).withLocale(locale)); - } - - public String toLocaleTbString(String localeStr, String optionsStr) { - return toLocaleString(localeStr, optionsStr, (locale, options) -> { - String formatPattern = - DateTimeFormatterBuilder.getLocalizedDateTimePattern( - options.getDateStyle(), - options.getTimeStyle(), - IsoChronology.INSTANCE, - locale); - return DateTimeFormatter.ofPattern(formatPattern, locale); - }); + return toLocaleString(localeStr, optionsStr, (locale, options) -> + DateTimeFormatter.ofLocalizedDateTime(options.getDateStyle(), options.getTimeStyle()).withLocale(locale)); } public String toLocaleString(String localeStr, String optionsStr, BiFunction formatterBuilder) { 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 e6c9b3b140..7f09219df9 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 @@ -271,45 +271,46 @@ class TbDateTest { Assert.assertNotNull(d.toLocaleString()); Assert.assertNotNull(d.toLocaleString("en-US")); - Assert.assertEquals("9/5/23, 9:04:05 PM", d.toLocaleTbString("en-US", "America/New_York")); - Assert.assertEquals("23. 9. 5. 오후 9:04:05", d.toLocaleTbString("ko-KR", "America/New_York")); - Assert.assertEquals("06.09.23, 04:04:05", d.toLocaleTbString( "uk-UA", "Europe/Kiev")); - Assert.assertEquals("5\u200F/9\u200F/2023, 9:04:05 م", d.toLocaleTbString( "ar-EG", "America/New_York")); + Assert.assertEquals("9/5/23, 9:04:05 PM", d.toLocaleString("en-US", "America/New_York")); + Assert.assertEquals("23. 9. 5. 오후 9:04:05", d.toLocaleString("ko-KR", "America/New_York")); + Assert.assertEquals("06.09.23, 04:04:05", d.toLocaleString( "uk-UA", "Europe/Kiev")); + Assert.assertEquals("5\u200F/9\u200F/2023, 9:04:05 م", d.toLocaleString( "ar-EG", "America/New_York")); - Assert.assertEquals("Tuesday, September 5, 2023 at 9:04:05 PM Eastern Daylight Time", d.toLocaleTbString("en-US", JacksonUtil.newObjectNode() + + Assert.assertEquals("Tuesday, September 5, 2023 at 9:04:05 PM Eastern Daylight Time", d.toLocaleString("en-US", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("dateStyle", "full") .put("timeStyle", "full") .toString())); - Assert.assertEquals("2023년 9월 5일 화요일 오후 9시 4분 5초 미 동부 하계 표준시", d.toLocaleTbString("ko-KR", JacksonUtil.newObjectNode() + Assert.assertEquals("2023년 9월 5일 화요일 오후 9시 4분 5초 미 동부 하계 표준시", d.toLocaleString("ko-KR", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("dateStyle", "full") .put("timeStyle", "full") .toString())); - Assert.assertEquals("середа, 6 вересня 2023 р. о 04:04:05 за східноєвропейським літнім часом", d.toLocaleTbString("uk-UA", JacksonUtil.newObjectNode() + Assert.assertEquals("середа, 6 вересня 2023 р. о 04:04:05 за східноєвропейським літнім часом", d.toLocaleString("uk-UA", JacksonUtil.newObjectNode() .put("timeZone", "Europe/Kiev") .put("dateStyle", "full") .put("timeStyle", "full") .toString())); - Assert.assertEquals("الثلاثاء، 5 سبتمبر 2023 في 9:04:05 م التوقيت الصيفي الشرقي لأمريكا الشمالية", d.toLocaleTbString("ar-EG", JacksonUtil.newObjectNode() + Assert.assertEquals("الثلاثاء، 5 سبتمبر 2023 في 9:04:05 م التوقيت الصيفي الشرقي لأمريكا الشمالية", d.toLocaleString("ar-EG", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("dateStyle", "full") .put("timeStyle", "full") .toString())); - Assert.assertEquals("9/5/2023, 9:04:05 PM", d.toLocaleTbString("en-US", JacksonUtil.newObjectNode() + Assert.assertEquals("9/5/2023, 9:04:05 PM", d.toLocaleString("en-US", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("pattern", "M/d/yyyy, h:mm:ss a") .toString())); - Assert.assertEquals("9/5/2023, 9:04:05 오후", d.toLocaleTbString("ko-KR", JacksonUtil.newObjectNode() + Assert.assertEquals("9/5/2023, 9:04:05 오후", d.toLocaleString("ko-KR", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("pattern", "M/d/yyyy, h:mm:ss a") .toString())); - Assert.assertEquals("9/6/2023, 4:04:05 дп", d.toLocaleTbString("uk-UA", JacksonUtil.newObjectNode() + Assert.assertEquals("9/6/2023, 4:04:05 дп", d.toLocaleString("uk-UA", JacksonUtil.newObjectNode() .put("timeZone", "Europe/Kiev") .put("pattern", "M/d/yyyy, h:mm:ss a") .toString())); - Assert.assertEquals("9/5/2023, 9:04:05 م", d.toLocaleTbString("ar-EG", JacksonUtil.newObjectNode() + Assert.assertEquals("9/5/2023, 9:04:05 م", d.toLocaleString("ar-EG", JacksonUtil.newObjectNode() .put("timeZone", "America/New_York") .put("pattern", "M/d/yyyy, h:mm:ss a") .toString()));