From b58befc4a008cbbc6f886c1cf8adf77e0be5b809 Mon Sep 17 00:00:00 2001 From: nick Date: Tue, 5 Dec 2023 22:21:20 +0200 Subject: [PATCH 01/10] tbel fix_bug tbDate from String without TZ --- .../thingsboard/script/api/tbel/TbDate.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 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 f06d4cec53..347f85e563 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 @@ -490,8 +490,18 @@ public class TbDate implements Serializable, Cloneable { 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" - return OffsetDateTime.parse(s).toInstant(); + // assuming "2007-12-03T10:15:30.00Z" UTC instant + // assuming "2007-12-03T10:15:30.00" ZoneId.systemDefault() instant + // assuming "2007-12-03T10:15:30.00-04:00" TZ instant + // assuming "2007-12-03T10:15:30.00+04:00" TZ instant + Instant inst = validateDateWithTZ(s); + if (inst == null) { + LocalDateTime dt = LocalDateTime.parse(s); + return parseInstant(dt.getYear(), dt.getMonthValue(), dt.getDayOfMonth(), dt.getHour(), dt.getMinute(), + dt.getSecond(),dt.getNano()/1000000, ZoneId.systemDefault()); + } else { + return inst; + } } else { // assuming RFC-1123 value "Tue, 3 Jun 2008 11:05:30 GMT-02:00" @@ -514,4 +524,12 @@ public class TbDate implements Serializable, Cloneable { ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId); return zonedDateTime.toInstant(); } + + private static Instant validateDateWithTZ(String s) { + try { + return OffsetDateTime.parse(s).toInstant(); + } catch (DateTimeParseException e) { + return null; + } + } } From 91552b18b865b68d624fec8d50be4df03a05865f Mon Sep 17 00:00:00 2001 From: nick Date: Tue, 5 Dec 2023 22:27:59 +0200 Subject: [PATCH 02/10] tbel fix_bug tbDate from String without TZ add test --- .../script/api/tbel/TbDateTest.java | 61 ++++++++++++++++++- 1 file changed, 59 insertions(+), 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 ab0b2875bd..7e33150562 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 @@ -15,8 +15,6 @@ */ package org.thingsboard.script.api.tbel; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; @@ -454,6 +452,7 @@ class TbDateTest { @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); @@ -466,6 +465,64 @@ class TbDateTest { Assert.assertEquals("2023-09-07 08:04:05", d.toLocaleString()); } + @Test + void Test_DateString_With_TZ() { + int date = 7; + int tz = -4; + int hrs = 8; + String pattern = "2023-09-%s %s:04:05"; + String tzStr = "-04:00:00"; + String dateStr = "2023-09-0" + date + "T0" + hrs + ":04:05.123" + tzStr; + TbDate d = new TbDate(dateStr); + 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 = +5; + tzStr = "+05:00"; + dateStr = "2023-09-0" + date + "T0" + hrs + ":04:05.123" + tzStr; + d = new TbDate(dateStr); + 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 = -2; + tzStr = "-02"; + dateStr = "2023-09-0" + date + "T0" + hrs + ":04:05.123" + tzStr; + d = new TbDate(dateStr); + 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 Test_DateString_Without_TZ() { + String dateStr = "2023-08-06T04:04:05.123"; + String expected = "2023-08-06 04:04:05"; + TbDate d = new TbDate(dateStr); + Assert.assertEquals(expected, d.toLocaleString()); + } + + @Test + void Test_DateString_Without_FailedTZ() { + try { + TbDate d = new TbDate("2023-08-06T04:04:05.123+04:00:00:00"); + Assert.fail("Should throw ConversionException"); + } catch (ConversionException e) { + Assert.assertTrue(e.getMessage().contains("Cannot parse value [2023-08-06T04:04:05.123+04:00:00:00] as instant")); + } + + try { + TbDate d = new TbDate("2023-08-06T04:04:05.123+4"); + Assert.fail("Should throw ConversionException"); + } catch (ConversionException e) { + Assert.assertTrue(e.getMessage().contains("Cannot parse value [2023-08-06T04:04:05.123+4] as instant")); + } + } + @Test void Test_Get_LocalDateTime_With_TZ() { int hrs = 8; From 39b0959c77eb70736226384c8f011897bd7e963e Mon Sep 17 00:00:00 2001 From: nick Date: Wed, 6 Dec 2023 08:10:58 +0200 Subject: [PATCH 03/10] tbel fix_bug tbDate from String without TZ RFC_1123 --- .../thingsboard/script/api/tbel/TbDate.java | 42 ++++++++----- .../script/api/tbel/TbDateTest.java | 60 ++++++++----------- 2 files changed, 52 insertions(+), 50 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 347f85e563..f54fbe95e1 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 @@ -494,22 +494,31 @@ public class TbDate implements Serializable, Cloneable { // assuming "2007-12-03T10:15:30.00" ZoneId.systemDefault() instant // assuming "2007-12-03T10:15:30.00-04:00" TZ instant // assuming "2007-12-03T10:15:30.00+04:00" TZ instant - Instant inst = validateDateWithTZ(s); - if (inst == null) { - LocalDateTime dt = LocalDateTime.parse(s); - return parseInstant(dt.getYear(), dt.getMonthValue(), dt.getDayOfMonth(), dt.getHour(), dt.getMinute(), - dt.getSecond(),dt.getNano()/1000000, ZoneId.systemDefault()); - } else { - return inst; - } + return OffsetDateTime.parse(s).toInstant(); } else { // assuming RFC-1123 value "Tue, 3 Jun 2008 11:05:30 GMT-02:00" return 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; + try { + if (s.length() > 0 && Character.isDigit(s.charAt(0))) { + long timeMS = parse(s); + if (timeMS != -1) { + return Instant.ofEpochMilli(timeMS); + } else { + final ConversionException exception = new ConversionException("Cannot parse value [" + s + "] as instant", ex); + throw exception; + } + } else { + // assuming RFC-1123 value "Tue, 3 Jun 2008 11:05:30 -0200" + // The offset ID without colons or seconds. + return getInstantWithLocalZoneOffsetId_RFC_1123(s); + } + } catch (final DateTimeParseException e) { + final ConversionException exception = new ConversionException("Cannot parse value [" + s + "] as instant", ex); + throw exception; + } } } @@ -525,11 +534,12 @@ public class TbDate implements Serializable, Cloneable { return zonedDateTime.toInstant(); } - private static Instant validateDateWithTZ(String s) { - try { - return OffsetDateTime.parse(s).toInstant(); - } catch (DateTimeParseException e) { - return null; - } + private static Instant getInstantWithLocalZoneOffsetId_RFC_1123(String value) { + String s = value.trim() + " GMT"; + Instant instant = Instant.from(DateTimeFormatter.RFC_1123_DATE_TIME.parse(s)); + ZoneId systemZone = ZoneId.systemDefault(); // my timezone + String id = systemZone.getRules().getOffset(instant).getId(); + value = value.trim() + " " + id.replaceAll(":", ""); + return Instant.from(DateTimeFormatter.RFC_1123_DATE_TIME.parse(value)); } } 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 7e33150562..e6c8eb639a 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 @@ -357,9 +357,18 @@ class TbDateTest { stringDateTZ = "2023-09-06T01:04:05.00-02:00"; d = new TbDate(stringDateTZ); Assert.assertEquals("2023-09-06T03:04:05Z", d.toISOString()); + // Without_TZ + stringDateTZ = "2023-08-06T04:04:05.123"; + d = new TbDate(stringDateTZ); + Assert.assertEquals("2023-08-06 04:04:05", d.toLocaleString()); + 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()); + // without TZ + stringDateRFC_1123 = "Sat, 3 Jun 2023 11:05:30"; + d = new TbDate(stringDateRFC_1123); + Assert.assertEquals("2023-06-03 11:05:30", d.toLocaleString()); stringDateRFC_1123 = "Sat, 3 Jun 2023 01:04:05 +043056"; d = new TbDate(stringDateRFC_1123); Assert.assertEquals("2023-06-02T20:33:09Z", d.toISOString()); @@ -370,11 +379,23 @@ class TbDateTest { d = new TbDate(stringDateRFC_1123); Assert.assertEquals("2024-02-29T14:05:30Z", d.toISOString()); - String stringDateZ_error = "2023-09-06T01:04:05.00+045"; - Exception actual = assertThrows(ConversionException.class, () -> { - new TbDate(stringDateZ_error); - }); String expectedMessage = "Cannot parse value"; + String finalStringDateZ_error0 = "2023-09-06T01:04:05.00+045"; + Exception actual = assertThrows(ConversionException.class, () -> { + new TbDate(finalStringDateZ_error0); + }); + assertTrue(actual.getMessage().contains(expectedMessage)); + + String finalStringDateZ_error1 = "2023-08-06T04:04:05.123+04:00:00:00"; + actual = assertThrows(ConversionException.class, () -> { + new TbDate(finalStringDateZ_error1); + }); + assertTrue(actual.getMessage().contains(expectedMessage)); + + String finalStringDateZ_error2 ="2023-08-06T04:04:05.123+4"; + actual = assertThrows(ConversionException.class, () -> { + new TbDate(finalStringDateZ_error2); + }); assertTrue(actual.getMessage().contains(expectedMessage)); String stringDateRFC_1123_error = "Tue, 3 Jun 2023 11:05:30 GMT"; @@ -385,12 +406,8 @@ class TbDateTest { } @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()); String stringDateStart = "1970-01-01T00:00:00Z"; - d = new TbDate(stringDateStart); + TbDate d = new TbDate(stringDateStart); long actualMillis = TbDate.parse("1970-01-01 T00:00:00"); Assert.assertEquals(-d.getLocaleZoneOffset().getTotalSeconds() * 1000, actualMillis); String pattern = "yyyy-MM-dd HH:mm:ss.SSS"; @@ -498,31 +515,6 @@ class TbDateTest { Assert.assertEquals(expected, d.toLocaleString()); } - @Test - void Test_DateString_Without_TZ() { - String dateStr = "2023-08-06T04:04:05.123"; - String expected = "2023-08-06 04:04:05"; - TbDate d = new TbDate(dateStr); - Assert.assertEquals(expected, d.toLocaleString()); - } - - @Test - void Test_DateString_Without_FailedTZ() { - try { - TbDate d = new TbDate("2023-08-06T04:04:05.123+04:00:00:00"); - Assert.fail("Should throw ConversionException"); - } catch (ConversionException e) { - Assert.assertTrue(e.getMessage().contains("Cannot parse value [2023-08-06T04:04:05.123+04:00:00:00] as instant")); - } - - try { - TbDate d = new TbDate("2023-08-06T04:04:05.123+4"); - Assert.fail("Should throw ConversionException"); - } catch (ConversionException e) { - Assert.assertTrue(e.getMessage().contains("Cannot parse value [2023-08-06T04:04:05.123+4] as instant")); - } - } - @Test void Test_Get_LocalDateTime_With_TZ() { int hrs = 8; From a246b3c4a7514005c5bea96f0449d8d930cc990c Mon Sep 17 00:00:00 2001 From: nick Date: Wed, 6 Dec 2023 11:27:05 +0200 Subject: [PATCH 04/10] tbel fix_bug tbDate parameters Locale and TZ as String --- .../org/thingsboard/script/api/tbel/TbDate.java | 14 +++++++------- .../thingsboard/script/api/tbel/TbDateTest.java | 10 +++++----- 2 files changed, 12 insertions(+), 12 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 f54fbe95e1..7b950650f3 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 @@ -58,15 +58,15 @@ public class TbDate implements Serializable, Cloneable { this.instant = parseInstant(s); } - public TbDate(String s, String pattern, Locale locale) { - instant = parseInstant(s, pattern, locale, ZoneId.systemDefault()); + public TbDate(String s, String pattern) { + instant = parseInstant(s, pattern, localeUTC, ZoneId.systemDefault()); } - 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, String localeStr) { + instant = parseInstant(s, pattern, Locale.forLanguageTag(localeStr), ZoneId.systemDefault()); } - public TbDate(String s, String pattern, Locale locale, ZoneId zoneId) { - instant = parseInstant(s, pattern, locale, zoneId); + public TbDate(String s, String pattern, String localeStr, String zoneIdStr) { + instant = parseInstant(s, pattern, Locale.forLanguageTag(localeStr), ZoneId.of(zoneIdStr)); } public TbDate(long dateMilliSecond) { 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 e6c8eb639a..7aa0e2b7ea 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 @@ -154,7 +154,7 @@ class TbDateTest { void testToLocaleDateString() { String s = "02: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); + TbDate d = new TbDate(s, pattern, "en-US"); // tz = local int localOffsetHrs = ZoneId.systemDefault().getRules().getOffset(d.getInstant()).getTotalSeconds()/60/60; int hrs = 14 - localOffsetHrs; @@ -167,9 +167,9 @@ class TbDateTest { Assert.assertEquals("2023-08-06T08:04:05Z", d.toISOString()); s = "02:15:30 PM, Sun 10/09/2022"; - d = new TbDate(s, pattern, Locale.US, "-04:00"); + d = new TbDate(s, pattern, "en-US", "-04:00"); Assert.assertEquals("2022-10-09T18:15:30Z", d.toISOString()); - d = new TbDate(s, pattern, Locale.US, "America/New_York"); + d = new TbDate(s, pattern,"en-US", "America/New_York"); Assert.assertEquals("2022-10-09T18:15:30Z", d.toISOString()); // tz = "+02:00" /** @@ -179,12 +179,12 @@ class TbDateTest { * `{ "AM", "PM" }` */ s = "09:15:30 nachm., So. 10/09/2022"; - d = new TbDate(s, pattern, Locale.GERMAN, ZoneId.of("Europe/Berlin")); + d = new TbDate(s, pattern, "de","Europe/Berlin"); Assert.assertEquals("2022-10-09T19:15:30Z", d.toISOString()); s = "02:15:30 пп, середа, 4 жовтня 2023 р."; pattern = "hh:mm:ss a, EEEE, d MMMM y 'р.'"; - d = new TbDate(s, pattern, Locale.forLanguageTag("uk-UA")); + d = new TbDate(s, pattern, "uk-UA"); localOffsetHrs = ZoneId.systemDefault().getRules().getOffset(d.getInstant()).getTotalSeconds()/60/60; hrs = 14 - localOffsetHrs; expected = "2023-10-04T" + hrs + ":15:30Z"; From 272cc272573e351af4d90a6e7dbf476f22c21359 Mon Sep 17 00:00:00 2001 From: nick Date: Wed, 6 Dec 2023 15:10:26 +0200 Subject: [PATCH 05/10] tbel fix_bug tbDate parameters date as String with patter + locale --- .../thingsboard/script/api/tbel/TbDate.java | 58 ++++++++++--------- .../script/api/tbel/TbDateTest.java | 31 ++++++++-- 2 files changed, 57 insertions(+), 32 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 7b950650f3..25feda75f2 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbDate.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbDate.java @@ -54,19 +54,15 @@ public class TbDate implements Serializable, Cloneable { this.instant = Instant.now(); } - public TbDate(String s) { - this.instant = parseInstant(s); - } - - public TbDate(String s, String pattern) { - instant = parseInstant(s, pattern, localeUTC, ZoneId.systemDefault()); - } - - public TbDate(String s, String pattern, String localeStr) { - instant = parseInstant(s, pattern, Locale.forLanguageTag(localeStr), ZoneId.systemDefault()); - } - public TbDate(String s, String pattern, String localeStr, String zoneIdStr) { - instant = parseInstant(s, pattern, Locale.forLanguageTag(localeStr), ZoneId.of(zoneIdStr)); + public TbDate(String s, String... options) { + if (options.length <= 2) { + this.instant = parseInstant(s, options); + } else { + String pattern = options[0]; + String localeStr = options[1]; + String zoneIdStr = options[2]; + instant = parseInstant(s, pattern, Locale.forLanguageTag(localeStr), ZoneId.of(zoneIdStr)); + } } public TbDate(long dateMilliSecond) { @@ -487,22 +483,30 @@ public class TbDate implements Serializable, Cloneable { } } - private static Instant parseInstant(String s) { + private static Instant parseInstant(String s, String... options) { + Locale locale = options.length > 1 ? Locale.forLanguageTag( options[1]) : Locale.getDefault(); + DateTimeFormatter formatter = null; + if (options.length > 0) { + formatter = DateTimeFormatter.ofPattern(options[0], locale); + } else if (s.length() > 0 && Character.isDigit(s.charAt(0))) { + // assuming "2007-12-03T10:15:30.00Z" UTC instant + // assuming "2007-12-03T10:15:30.00" ZoneId.systemDefault() instant + // assuming "2007-12-03T10:15:30.00-04:00" TZ instant + // assuming "2007-12-03T10:15:30.00+04:00" TZ instant + formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME; + } else { + // assuming RFC-1123 value "Tue, 3 Jun 2008 11:05:30 GMT" + // assuming RFC-1123 value "Tue, 3 Jun 2008 11:05:30 GMT-02:00" + // assuming RFC-1123 value "Tue, 3 Jun 2008 11:05:30 -0200" + formatter = DateTimeFormatter.RFC_1123_DATE_TIME; + } try{ - if (s.length() > 0 && Character.isDigit(s.charAt(0))) { - // assuming "2007-12-03T10:15:30.00Z" UTC instant - // assuming "2007-12-03T10:15:30.00" ZoneId.systemDefault() instant - // assuming "2007-12-03T10:15:30.00-04:00" TZ instant - // assuming "2007-12-03T10:15:30.00+04:00" TZ instant - return OffsetDateTime.parse(s).toInstant(); - } - else { - // assuming RFC-1123 value "Tue, 3 Jun 2008 11:05:30 GMT-02:00" - return Instant.from(DateTimeFormatter.RFC_1123_DATE_TIME.parse(s)); - } - } catch (final DateTimeParseException ex) { + return Instant.from(formatter.parse(s)); + } catch (Exception ex) { try { - if (s.length() > 0 && Character.isDigit(s.charAt(0))) { + if (options.length > 0) { + return parseInstant(s, options[0], locale, ZoneId.systemDefault()); + } else if (s.length() > 0 && Character.isDigit(s.charAt(0))) { long timeMS = parse(s); if (timeMS != -1) { return Instant.ofEpochMilli(timeMS); 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 7aa0e2b7ea..2c8c07fb26 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 @@ -34,7 +34,6 @@ import java.time.Instant; import java.time.ZoneId; import java.util.ArrayList; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; @@ -351,16 +350,21 @@ class TbDateTest { 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"; + 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()); - // Without_TZ + // Without_TZ stringDateTZ = "2023-08-06T04:04:05.123"; d = new TbDate(stringDateTZ); Assert.assertEquals("2023-08-06 04:04:05", d.toLocaleString()); + // With pattern + locale - ok + String pattern = "hh:mm:ss a, EEE M/d/uuuu"; + stringDateTZ = "09:15:30 nachm., So. 10/09/2022"; + d = new TbDate(stringDateTZ, pattern, "de"); + Assert.assertEquals("2022-10-09 21:15:30", d.toLocaleString()); String stringDateRFC_1123 = "Sat, 3 Jun 2023 11:05:30 GMT"; d = new TbDate(stringDateRFC_1123); @@ -379,25 +383,36 @@ class TbDateTest { d = new TbDate(stringDateRFC_1123); Assert.assertEquals("2024-02-29T14:05:30Z", d.toISOString()); + + // failed TZ String expectedMessage = "Cannot parse value"; String finalStringDateZ_error0 = "2023-09-06T01:04:05.00+045"; Exception actual = assertThrows(ConversionException.class, () -> { new TbDate(finalStringDateZ_error0); }); assertTrue(actual.getMessage().contains(expectedMessage)); - + // failed TZ String finalStringDateZ_error1 = "2023-08-06T04:04:05.123+04:00:00:00"; actual = assertThrows(ConversionException.class, () -> { new TbDate(finalStringDateZ_error1); }); assertTrue(actual.getMessage().contains(expectedMessage)); - + // failed TZ String finalStringDateZ_error2 ="2023-08-06T04:04:05.123+4"; actual = assertThrows(ConversionException.class, () -> { new TbDate(finalStringDateZ_error2); }); + assertTrue(actual.getMessage().contains(expectedMessage)); + // The locale does not match the pattern + String finalStringDateZ_error3= "02:15:30 PM, Sun 10/09/2022"; + pattern = "hh:mm:ss a, EEE M/d/uuuu"; + String finalPattern = pattern; + actual = assertThrows(ConversionException.class, () -> { + new TbDate(finalStringDateZ_error3, finalPattern, "de"); + }); assertTrue(actual.getMessage().contains(expectedMessage)); + // failed DayOfWeek String stringDateRFC_1123_error = "Tue, 3 Jun 2023 11:05:30 GMT"; actual = assertThrows(ConversionException.class, () -> { new TbDate(stringDateRFC_1123_error); @@ -482,6 +497,12 @@ class TbDateTest { Assert.assertEquals("2023-09-07 08:04:05", d.toLocaleString()); } + @Test + void Test_DateString_With_Pattern() { + String pattern = "yyyy-MM-dd HH:mm:ss.SSSXXX"; + TbDate d = new TbDate("2023-08-06 04:04:05.000-04:00", pattern); + Assert.assertEquals("2023-08-06T08:04:05Z", d.toISOString()); + } @Test void Test_DateString_With_TZ() { int date = 7; From a12c9e11f8089454865809746c1fa274019e3ada Mon Sep 17 00:00:00 2001 From: nick Date: Thu, 7 Dec 2023 15:05:45 +0200 Subject: [PATCH 06/10] tbel fix_bug tbDate test --- .../script/api/tbel/TbDateTest.java | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 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 2c8c07fb26..120a776c1a 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 @@ -360,19 +360,11 @@ class TbDateTest { stringDateTZ = "2023-08-06T04:04:05.123"; d = new TbDate(stringDateTZ); Assert.assertEquals("2023-08-06 04:04:05", d.toLocaleString()); - // With pattern + locale - ok - String pattern = "hh:mm:ss a, EEE M/d/uuuu"; - stringDateTZ = "09:15:30 nachm., So. 10/09/2022"; - d = new TbDate(stringDateTZ, pattern, "de"); - Assert.assertEquals("2022-10-09 21:15:30", d.toLocaleString()); - String stringDateRFC_1123 = "Sat, 3 Jun 2023 11:05:30 GMT"; + // With TZ RFC_1123 + 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()); - // without TZ - stringDateRFC_1123 = "Sat, 3 Jun 2023 11:05:30"; - d = new TbDate(stringDateRFC_1123); - Assert.assertEquals("2023-06-03 11:05:30", d.toLocaleString()); stringDateRFC_1123 = "Sat, 3 Jun 2023 01:04:05 +043056"; d = new TbDate(stringDateRFC_1123); Assert.assertEquals("2023-06-02T20:33:09Z", d.toISOString()); @@ -382,7 +374,16 @@ class TbDateTest { stringDateRFC_1123 = "Thu, 29 Feb 2024 11:05:30 -03"; d = new TbDate(stringDateRFC_1123); Assert.assertEquals("2024-02-29T14:05:30Z", d.toISOString()); + // Without TZ RFC_1123 + stringDateRFC_1123 = "Sat, 3 Jun 2023 11:05:30"; + d = new TbDate(stringDateRFC_1123); + Assert.assertEquals("2023-06-03 11:05:30", d.toLocaleString()); + // With pattern + locale - ok + String pattern = "hh:mm:ss a, EEE M/d/uuuu"; + stringDateRFC_1123 = "09:15:30 nachm., So. 10/09/2022"; + d = new TbDate(stringDateRFC_1123 , pattern, "de"); + Assert.assertEquals("2022-10-09 21:15:30", d.toLocaleString()); // failed TZ String expectedMessage = "Cannot parse value"; @@ -403,7 +404,7 @@ class TbDateTest { new TbDate(finalStringDateZ_error2); }); assertTrue(actual.getMessage().contains(expectedMessage)); - // The locale does not match the pattern + // The locale does not match the pattern RFC_1123 String finalStringDateZ_error3= "02:15:30 PM, Sun 10/09/2022"; pattern = "hh:mm:ss a, EEE M/d/uuuu"; String finalPattern = pattern; @@ -412,13 +413,14 @@ class TbDateTest { }); assertTrue(actual.getMessage().contains(expectedMessage)); - // failed DayOfWeek + // failed DayOfWeek RFC_1123 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 TestParse () { String stringDateStart = "1970-01-01T00:00:00Z"; From fbfecf34108ea7c04f5dc8d338d22a255bd654c8 Mon Sep 17 00:00:00 2001 From: nick Date: Thu, 7 Dec 2023 19:40:02 +0200 Subject: [PATCH 07/10] tbel fix_bug tbDate tests Constructor class --- .../thingsboard/script/api/tbel/TbDate.java | 32 +++--- .../api/tbel/TbDateConstructorTest.java | 103 ++++++++++++++++++ 2 files changed, 122 insertions(+), 13 deletions(-) create mode 100644 common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateConstructorTest.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 25feda75f2..089b4606f8 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbDate.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbDate.java @@ -54,15 +54,20 @@ public class TbDate implements Serializable, Cloneable { this.instant = Instant.now(); } - public TbDate(String s, String... options) { - if (options.length <= 2) { - this.instant = parseInstant(s, options); - } else { - String pattern = options[0]; - String localeStr = options[1]; - String zoneIdStr = options[2]; - instant = parseInstant(s, pattern, Locale.forLanguageTag(localeStr), ZoneId.of(zoneIdStr)); - } + public TbDate(String s) { + this.instant = parseInstant(s); + } + + public TbDate(String s, String pattern) { + this.instant = parseInstant(s, pattern); + } + + public TbDate(String s, String pattern, String locale) { + this.instant = parseInstant(s, pattern, locale); + } + + public TbDate(String s, String pattern, String locale, String zoneId) { + this.instant = parseInstant(s, pattern, locale, zoneId); } public TbDate(long dateMilliSecond) { @@ -505,7 +510,8 @@ public class TbDate implements Serializable, Cloneable { } catch (Exception ex) { try { if (options.length > 0) { - return parseInstant(s, options[0], locale, ZoneId.systemDefault()); + String zoneIdStr = options.length > 3 ? options[2] : ZoneId.systemDefault().getId(); + return parseInstant(s, options[0], locale.getLanguage(), zoneIdStr); } else if (s.length() > 0 && Character.isDigit(s.charAt(0))) { long timeMS = parse(s); if (timeMS != -1) { @@ -531,10 +537,10 @@ public class TbDate implements Serializable, Cloneable { ZonedDateTime zonedDateTime = ZonedDateTime.of(year, month, date, hrs, min, second, secondMilli*1000000, zoneId); return zonedDateTime.toInstant(); } - private static Instant parseInstant(String s, String pattern, Locale locale, ZoneId zoneId) { - DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern, locale); + private static Instant parseInstant(String s, String pattern, String localeStr, String zoneIdStr) { + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern, Locale.forLanguageTag(localeStr)); LocalDateTime localDateTime = LocalDateTime.parse(s, dateTimeFormatter); - ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId); + ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of(zoneIdStr)); return zonedDateTime.toInstant(); } diff --git a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateConstructorTest.java b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateConstructorTest.java new file mode 100644 index 0000000000..2dadf6adee --- /dev/null +++ b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateConstructorTest.java @@ -0,0 +1,103 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.script.api.tbel; + +import org.junit.Assert; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mvel2.CompileException; +import org.mvel2.ExecutionContext; +import org.mvel2.ParserContext; +import org.mvel2.SandboxedParserConfiguration; + +import java.io.Serializable; +import java.util.HashMap; + +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.mvel2.MVEL.compileExpression; +import static org.mvel2.MVEL.executeTbExpression; + +public class TbDateConstructorTest { + + private static ExecutionContext executionContext; + + @BeforeAll + public static void setup() { + SandboxedParserConfiguration parserConfig = ParserContext.enableSandboxedMode(); + parserConfig.addImport("JSON", TbJson.class); + parserConfig.registerDataType("Date", TbDate.class, date -> 8L); + executionContext = new ExecutionContext(parserConfig, 5 * 1024 * 1024); + } + + + @AfterAll + public static void tearDown() { + ParserContext.disableSandboxedMode(); + } + + + @Test + void TestTbDateConstructorWithStringParameters () { + // one: date in String + String body = "var d = new Date(\"2023-08-06T04:04:05.123Z\"); \n" + + "d.toISOString()"; + Object res = executeScript(body); + Assert.assertNotEquals("2023-08-06T04:04:05.123Z".length(), res); + + // two: date in String + pattern + body = "var pattern = \"yyyy-MM-dd HH:mm:ss.SSSXXX\";\n" + + "var d = new Date(\"2023-08-06 04:04:05.000Z\", pattern);\n" + + "d.toISOString()"; + res = executeScript(body); + Assert.assertNotEquals("2023-08-06T04:04:05Z".length(), res); + + + // three: date in String + pattern + locale + body = "var pattern = \"hh:mm:ss a, EEE M/d/uuuu\";\n" + + "var d = new Date(\"02:15:30 PM, Sun 10/09/2022\", pattern, \"en-US\");" + + "d.toISOString()"; + res = executeScript(body); + Assert.assertNotEquals("2023-08-06T04:04:05Z".length(), res); + + // four: date in String + pattern + locale + TimeZone + body = "var pattern = \"hh:mm:ss a, EEE M/d/uuuu\";\n" + + "var d = new Date(\"02:15:30 PM, Sun 10/09/2022\", pattern, \"en-US\", \"America/New_York\");" + + "d.toISOString()"; + res = executeScript(body); + Assert.assertNotEquals("22022-10-09T18:15:30Z".length(), res); + } + + @Test + void TbDateConstructorWithStringParameters_PatternNotMatchLocale_Error () { + String expectedMessage = "could not create constructor: null"; + + String body = "var pattern = \"hh:mm:ss a, EEE M/d/uuuu\";\n" + + "var d = new Date(\"02:15:30 PM, Sun 10/09/2022\", pattern, \"de\");" + + "d.toISOString()"; + Exception actual = assertThrows(CompileException.class, () -> { + executeScript(body); + }); + assertTrue(actual.getMessage().contains(expectedMessage)); + + } + + private Object executeScript(String ex) { + Serializable compiled = compileExpression(ex, new ParserContext()); + return executeTbExpression(compiled, executionContext, new HashMap()); + } +} From c14fe5b2cdc4e8113bea9ec446f85a4d672b1d63 Mon Sep 17 00:00:00 2001 From: nick Date: Fri, 8 Dec 2023 23:13:07 +0200 Subject: [PATCH 08/10] tbel fix_bug tbDate delete String... options --- .../thingsboard/script/api/tbel/TbDate.java | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 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 089b4606f8..5deacdebbd 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,7 +26,6 @@ import java.text.SimpleDateFormat; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; -import java.time.OffsetDateTime; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; @@ -55,11 +54,11 @@ public class TbDate implements Serializable, Cloneable { } public TbDate(String s) { - this.instant = parseInstant(s); + this.instant = parseInstant(s, null, Locale.getDefault().toLanguageTag()); } public TbDate(String s, String pattern) { - this.instant = parseInstant(s, pattern); + this.instant = parseInstant(s, pattern, Locale.getDefault().toLanguageTag()); } public TbDate(String s, String pattern, String locale) { @@ -488,11 +487,10 @@ public class TbDate implements Serializable, Cloneable { } } - private static Instant parseInstant(String s, String... options) { - Locale locale = options.length > 1 ? Locale.forLanguageTag( options[1]) : Locale.getDefault(); - DateTimeFormatter formatter = null; - if (options.length > 0) { - formatter = DateTimeFormatter.ofPattern(options[0], locale); + private static Instant parseInstant(String s, String pattern, String localeStr) { + DateTimeFormatter formatter; + if (pattern != null) { + formatter = DateTimeFormatter.ofPattern(pattern, Locale.forLanguageTag(localeStr)); } else if (s.length() > 0 && Character.isDigit(s.charAt(0))) { // assuming "2007-12-03T10:15:30.00Z" UTC instant // assuming "2007-12-03T10:15:30.00" ZoneId.systemDefault() instant @@ -509,9 +507,9 @@ public class TbDate implements Serializable, Cloneable { return Instant.from(formatter.parse(s)); } catch (Exception ex) { try { - if (options.length > 0) { - String zoneIdStr = options.length > 3 ? options[2] : ZoneId.systemDefault().getId(); - return parseInstant(s, options[0], locale.getLanguage(), zoneIdStr); + if (pattern != null) { + String zoneIdStr = ZoneId.systemDefault().getId(); + return parseInstant(s, pattern, localeStr, zoneIdStr); } else if (s.length() > 0 && Character.isDigit(s.charAt(0))) { long timeMS = parse(s); if (timeMS != -1) { From 3bf585ec80060bd3ee7a378bbbdfb4b1f2ffaddb Mon Sep 17 00:00:00 2001 From: nick Date: Sat, 9 Dec 2023 09:30:31 +0200 Subject: [PATCH 09/10] tbel fix_bug tbDate delete String... options --- .../thingsboard/script/api/tbel/TbDate.java | 34 ++++++++++++------- .../api/tbel/TbDateConstructorTest.java | 1 - 2 files changed, 22 insertions(+), 13 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 5deacdebbd..f428f08663 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbDate.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbDate.java @@ -54,19 +54,19 @@ public class TbDate implements Serializable, Cloneable { } public TbDate(String s) { - this.instant = parseInstant(s, null, Locale.getDefault().toLanguageTag()); + this.instant = parseInstant(s); } public TbDate(String s, String pattern) { - this.instant = parseInstant(s, pattern, Locale.getDefault().toLanguageTag()); + this.instant = parseInstant(s, Locale.getDefault().toLanguageTag(), pattern); } public TbDate(String s, String pattern, String locale) { - this.instant = parseInstant(s, pattern, locale); + this.instant = parseInstant(s, locale, pattern); } public TbDate(String s, String pattern, String locale, String zoneId) { - this.instant = parseInstant(s, pattern, locale, zoneId); + this.instant = parseInstant(s, pattern, locale, zoneId); } public TbDate(long dateMilliSecond) { @@ -487,11 +487,10 @@ public class TbDate implements Serializable, Cloneable { } } - private static Instant parseInstant(String s, String pattern, String localeStr) { + private static Instant parseInstant(String s) { DateTimeFormatter formatter; - if (pattern != null) { - formatter = DateTimeFormatter.ofPattern(pattern, Locale.forLanguageTag(localeStr)); - } else if (s.length() > 0 && Character.isDigit(s.charAt(0))) { + boolean isIsoFormat = s.length() > 0 && Character.isDigit(s.charAt(0)); + if (isIsoFormat) { // assuming "2007-12-03T10:15:30.00Z" UTC instant // assuming "2007-12-03T10:15:30.00" ZoneId.systemDefault() instant // assuming "2007-12-03T10:15:30.00-04:00" TZ instant @@ -507,10 +506,7 @@ public class TbDate implements Serializable, Cloneable { return Instant.from(formatter.parse(s)); } catch (Exception ex) { try { - if (pattern != null) { - String zoneIdStr = ZoneId.systemDefault().getId(); - return parseInstant(s, pattern, localeStr, zoneIdStr); - } else if (s.length() > 0 && Character.isDigit(s.charAt(0))) { + if (isIsoFormat) { long timeMS = parse(s); if (timeMS != -1) { return Instant.ofEpochMilli(timeMS); @@ -523,6 +519,20 @@ public class TbDate implements Serializable, Cloneable { // The offset ID without colons or seconds. return getInstantWithLocalZoneOffsetId_RFC_1123(s); } + } catch (final DateTimeParseException e) { + final ConversionException exception = new ConversionException("Cannot parse value [" + s + "] as instant", e); + throw exception; + } + } + } + + private static Instant parseInstant(String s, String localeStr, String pattern) { + try { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern, Locale.forLanguageTag(localeStr)); + return Instant.from(formatter.parse(s)); + } catch (Exception ex) { + try { + return parseInstant(s, pattern, localeStr, ZoneId.systemDefault().getId()); } catch (final DateTimeParseException e) { final ConversionException exception = new ConversionException("Cannot parse value [" + s + "] as instant", ex); throw exception; diff --git a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateConstructorTest.java b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateConstructorTest.java index 2dadf6adee..8a9d84b980 100644 --- a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateConstructorTest.java +++ b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateConstructorTest.java @@ -44,7 +44,6 @@ public class TbDateConstructorTest { executionContext = new ExecutionContext(parserConfig, 5 * 1024 * 1024); } - @AfterAll public static void tearDown() { ParserContext.disableSandboxedMode(); From 7e00acd44b535e2c7bf1ab6c2ba2554d3b2070d1 Mon Sep 17 00:00:00 2001 From: nick Date: Fri, 15 Dec 2023 12:18:05 +0200 Subject: [PATCH 10/10] tbDate: fix bug comments 3 --- .../thingsboard/script/api/tbel/TbDate.java | 70 ++++++++++--------- 1 file changed, 38 insertions(+), 32 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 f428f08663..9bab4060ab 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 @@ -488,41 +488,11 @@ public class TbDate implements Serializable, Cloneable { } private static Instant parseInstant(String s) { - DateTimeFormatter formatter; boolean isIsoFormat = s.length() > 0 && Character.isDigit(s.charAt(0)); if (isIsoFormat) { - // assuming "2007-12-03T10:15:30.00Z" UTC instant - // assuming "2007-12-03T10:15:30.00" ZoneId.systemDefault() instant - // assuming "2007-12-03T10:15:30.00-04:00" TZ instant - // assuming "2007-12-03T10:15:30.00+04:00" TZ instant - formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME; + return getInstant_ISO_OFFSET_DATE_TIME(s); } else { - // assuming RFC-1123 value "Tue, 3 Jun 2008 11:05:30 GMT" - // assuming RFC-1123 value "Tue, 3 Jun 2008 11:05:30 GMT-02:00" - // assuming RFC-1123 value "Tue, 3 Jun 2008 11:05:30 -0200" - formatter = DateTimeFormatter.RFC_1123_DATE_TIME; - } - try{ - return Instant.from(formatter.parse(s)); - } catch (Exception ex) { - try { - if (isIsoFormat) { - long timeMS = parse(s); - if (timeMS != -1) { - return Instant.ofEpochMilli(timeMS); - } else { - final ConversionException exception = new ConversionException("Cannot parse value [" + s + "] as instant", ex); - throw exception; - } - } else { - // assuming RFC-1123 value "Tue, 3 Jun 2008 11:05:30 -0200" - // The offset ID without colons or seconds. - return getInstantWithLocalZoneOffsetId_RFC_1123(s); - } - } catch (final DateTimeParseException e) { - final ConversionException exception = new ConversionException("Cannot parse value [" + s + "] as instant", e); - throw exception; - } + return getInstant_RFC_1123(s); } } @@ -552,6 +522,42 @@ public class TbDate implements Serializable, Cloneable { return zonedDateTime.toInstant(); } + private static Instant getInstant_ISO_OFFSET_DATE_TIME(String s) { + // assuming "2007-12-03T10:15:30.00Z" UTC instant + // assuming "2007-12-03T10:15:30.00" ZoneId.systemDefault() instant + // assuming "2007-12-03T10:15:30.00-04:00" TZ instant + // assuming "2007-12-03T10:15:30.00+04:00" TZ instant + DateTimeFormatter formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME; + try { + return Instant.from(formatter.parse(s)); + } catch (DateTimeParseException ex) { + try { + long timeMS = parse(s); + if (timeMS != -1) { + return Instant.ofEpochMilli(timeMS); + } else { + throw new ConversionException("Cannot parse value [" + s + "] as instant"); + } + } catch (final DateTimeParseException e) { + throw new ConversionException("Cannot parse value [" + s + "] as instant"); + } + } + } + private static Instant getInstant_RFC_1123(String s) { + // assuming RFC-1123 value "Tue, 3 Jun 2008 11:05:30 GMT" + // assuming RFC-1123 value "Tue, 3 Jun 2008 11:05:30 GMT-02:00" + // assuming RFC-1123 value "Tue, 3 Jun 2008 11:05:30 -0200" + DateTimeFormatter formatter = DateTimeFormatter.RFC_1123_DATE_TIME; + try { + return Instant.from(formatter.parse(s)); + } catch (DateTimeParseException ex) { + try { + return getInstantWithLocalZoneOffsetId_RFC_1123(s); + } catch (final DateTimeParseException e) { + throw new ConversionException("Cannot parse value [" + s + "] as instant"); + } + } + } private static Instant getInstantWithLocalZoneOffsetId_RFC_1123(String value) { String s = value.trim() + " GMT"; Instant instant = Instant.from(DateTimeFormatter.RFC_1123_DATE_TIME.parse(s));