Merge pull request #9505 from thingsboard/tbDate_to_instant

[master] tbData_ java11_date_to_Instant
This commit is contained in:
Andrew Shvayka 2023-10-27 13:09:50 +03:00 committed by GitHub
commit b409e609fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 1024 additions and 115 deletions

View File

@ -15,79 +15,153 @@
*/
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.io.Serializable;
import java.text.DateFormat;
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;
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.Date;
import java.util.GregorianCalendar;
import java.util.Arrays;
import java.util.Locale;
import java.util.function.BiFunction;
public class TbDate extends Date {
public class TbDate implements Serializable, Cloneable {
private Instant instant;
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());
private static final ThreadLocal<DateFormat> isoDateFormat = ThreadLocal.withInitial(() ->
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"));
public TbDate() {
super();
this.instant = Instant.now();
}
public TbDate(String s) {
super(parse(s));
this.instant = parseInstant(s);
}
public TbDate(long date) {
super(date);
public TbDate(String s, String pattern, Locale locale) {
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(int year, int month, int date) {
this(year, month, date, 0, 0, 0);
public TbDate(long dateMilliSecond) {
instant = Instant.ofEpochMilli(dateMilliSecond);
}
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, String... tz) {
this(year, month, date, 0, 0, 0, 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, String... tz) {
this(year, month, date, hrs, min, 0, 0, tz);
}
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, int secondMilli, String... 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 ZonedDateTime getZonedDateTime() {
return instant.atZone(zoneIdUTC);
}
public LocalDateTime getLocalDateTime() {
return LocalDateTime.ofInstant(this.instant, ZoneId.systemDefault());
}
public LocalDateTime getUTCDateTime() {
return LocalDateTime.ofInstant(this.instant, zoneIdUTC);
}
public String toDateString() {
DateFormat formatter = DateFormat.getDateInstance();
return formatter.format(this);
return toDateString(localeUTC.getLanguage());
}
public String toDateString(String locale) {
return toDateString(locale, ZoneId.systemDefault().toString());
}
public String toDateString(String localeStr, String optionsStr) {
return toLocaleString(localeStr, optionsStr, (locale, options) -> DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).withLocale(locale));
}
public String toTimeString() {
DateFormat formatter = DateFormat.getTimeInstance(DateFormat.LONG);
return formatter.format(this);
return toTimeString(Locale.getDefault().getLanguage());
}
public String toTimeString(String locale) {
return toTimeString(locale, ZoneId.systemDefault().toString());
}
public String toTimeString(String localeStr, String optionsStr) {
return toLocaleString(localeStr, optionsStr, (locale, options) -> DateTimeFormatter.ofLocalizedTime(FormatStyle.FULL).withLocale(locale));
}
public String toISOString() {
return isoDateFormat.get().format(this);
return instant.toString();
}
public String toJSON() {
return toISOString();
}
public String toUTCString() {
return toUTCString(localeUTC.getLanguage());
}
public String toUTCString(String localeStr) {
return toLocaleString(localeStr, zoneIdUTC.getId(), (locale, options) -> DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL, FormatStyle.MEDIUM).withLocale(locale));
}
public String toString() {
return toString(Locale.getDefault().getLanguage());
}
public String toString(String locale) {
return toString(locale, ZoneId.systemDefault().toString());
}
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();
}
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);
public String toLocaleDateString(String localeStr) {
return toLocaleString(localeStr, ZoneId.systemDefault().toString(), (locale, options) -> DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).withLocale(locale));
}
public String toLocaleDateString(String localeStr, String optionsStr) {
@ -95,42 +169,34 @@ public class TbDate extends Date {
}
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));
}
@Override
public String toLocaleString() {
return toLocaleString(null, null);
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) -> {
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<Locale, DateTimeFormatOptions, DateTimeFormatter> 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.getInstant().atZone(options.getTimeZone().toZoneId());
DateTimeFormatter formatter;
if (StringUtils.isNotEmpty(options.getPattern())) {
formatter = new DateTimeFormatterBuilder().appendPattern(options.getPattern()).toFormatter(locale);
@ -140,13 +206,13 @@ public class TbDate extends Date {
return formatter.format(zdt);
}
private static 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) {
@ -155,8 +221,251 @@ public class TbDate extends Date {
return opt;
}
public static long now() {
return System.currentTimeMillis();
public long now() {
return Instant.now().toEpochMilli();
}
public long parseSecond() {
return instant.getEpochSecond();
}
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 parseInstant(year, month, date, hrs, min, sec, ms, zoneIdUTC).toEpochMilli();
}
public int getUTCFullYear() {
return getUTCDateTime().getYear();
}
public int getUTCMonth() {
return getUTCDateTime().getMonthValue();
}
// day in month
public int getUTCDate() {
return getUTCDateTime().getDayOfMonth();
}
// day in week
public int getUTCDay() {
return getUTCDateTime().getDayOfWeek().getValue();
}
public int getUTCHours() {
return getUTCDateTime().getHour();
}
public int getUTCMinutes() {
return getZonedDateTime().getMinute();
}
public int getUTCSeconds() {
return getUTCDateTime().getSecond();
}
public int getUTCMilliseconds() {
return getUTCDateTime().getNano()/1000000;
}
public void setUTCFullYear(int year) {
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) {
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) {
this.instant = getZonedDateTime().withYear(year).withMonth(month).withDayOfMonth(date).toInstant();
}
public void setUTCMonth(int month) {
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) {
this.instant = getZonedDateTime().withMonth(month).withDayOfMonth(date).toInstant();
}
public void setUTCDate(int date) {
this.instant = getZonedDateTime().withDayOfMonth(date).toInstant();
}
public void setUTCHours(int hrs) {
this.instant = getZonedDateTime().withHour(hrs).toInstant();
}
public void setUTCHours(int hrs, int minutes) {
this.instant = getZonedDateTime().withHour(hrs).withMinute(minutes).toInstant();
}
public void setUTCHours(int hrs, int minutes, int seconds) {
this.instant = getZonedDateTime().withHour(hrs).withMinute(minutes).withSecond(seconds).toInstant();
}
public void setUTCHours(int hrs, int minutes, int seconds, int ms) {
this.instant = getZonedDateTime().withHour(hrs).withMinute(minutes).withSecond(seconds).withNano(ms*1000000).toInstant();
}
public void setUTCMinutes(int minutes) {
this.instant = getZonedDateTime().withMinute(minutes).toInstant();
}
public void setUTCMinutes(int minutes, int seconds) {
this.instant = getZonedDateTime().withMinute(minutes).withSecond(seconds).toInstant(); }
public void setUTCMinutes(int minutes, int seconds, int ms) {
this.instant = parseInstant(getUTCFullYear(), getUTCMonth(), getUTCDate(), getUTCHours(), minutes, seconds, ms, zoneIdUTC);
}
public void setUTCSeconds(int seconds) {
this.instant = getZonedDateTime().withSecond(seconds).toInstant();
}
public void setUTCSeconds(int seconds, int ms) {
this.instant = getZonedDateTime().withSecond(seconds).withNano(ms*1000000).toInstant();
}
public void setUTCMilliseconds(int ms) {
this.instant = getZonedDateTime().withNano(ms*1000000).toInstant();
}
public int getFullYear() {
return getLocalDateTime().getYear();
}
public int getMonth() {
return getLocalDateTime().getMonthValue();
}
// day in month
public int getDate() {
return getLocalDateTime().getDayOfMonth();
}
// day in week
public int getDay() {
return getLocalDateTime().getDayOfWeek().getValue();
}
public int getHours() {
return getLocalDateTime().getHour();
}
public int getMinutes() {
return getLocalDateTime().getMinute();
}
public int getSeconds() {
return getLocalDateTime().getSecond();
}
public int getMilliseconds() {
return getLocalDateTime().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) {
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) {
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) {
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) {
Instant instantEpochWithMonthDate = getZonedDateTime().withMonth(month).withDayOfMonth(date).toInstant();
this.instant = getLocalDateTime().withMonth(month).withDayOfMonth(date).toInstant(getLocaleZoneOffset(instantEpochWithMonthDate));
}
public void setDate(int date) {
Instant instantEpochWithDate = getZonedDateTime().withDayOfMonth(date).toInstant();
this.instant = getLocalDateTime().withDayOfMonth(date).toInstant(getLocaleZoneOffset(instantEpochWithDate));
}
public void setHours(int hrs) {
this.instant = getLocalDateTime().withHour(hrs).toInstant(getLocaleZoneOffset(this.instant));
}
public void setHours(int hrs, int minutes) {
this.instant = getLocalDateTime().withHour(hrs).withMinute(minutes).toInstant(getLocaleZoneOffset(this.instant));
}
public void setHours(int hrs, int minutes, int 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) {
this.instant = getLocalDateTime().withHour(hrs).withMinute(minutes).withSecond(seconds).withNano(ms*1000000).toInstant(getLocaleZoneOffset(this.instant));
}
public void setMinutes(int minutes) {
this.instant = getLocalDateTime().withMinute(minutes).toInstant(getLocaleZoneOffset(this.instant));
}
public void setMinutes(int minutes, int seconds) {
this.instant = getLocalDateTime().withMinute(minutes).withSecond(seconds).toInstant(getLocaleZoneOffset(this.instant));
}
public void setMinutes(int minutes, int seconds, int ms) {
this.instant = getLocalDateTime().withMinute(minutes).withSecond(seconds).withNano(ms*1000000).toInstant(getLocaleZoneOffset(this.instant));
}
public void setSeconds(int seconds) {
this.instant = getLocalDateTime().withSecond(seconds).toInstant(getLocaleZoneOffset(this.instant));
}
public void setSeconds(int seconds, int ms) {
this.instant = getLocalDateTime().withSecond(seconds).withNano(ms*1000000).toInstant(getLocaleZoneOffset(this.instant));
}
public void setMilliseconds(int 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);
}
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) {
@ -167,7 +476,6 @@ public class TbDate extends Date {
return -1;
}
}
public static long parse(String value) {
try {
TemporalAccessor accessor = isoDateFormatter.parseBest(value,
@ -177,17 +485,35 @@ public class TbDate extends Date {
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;
}
}
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();
}
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;
}
}
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 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();
}
}

View File

@ -24,21 +24,16 @@ 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.LocalDateTime;
import java.time.DateTimeException;
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;
@ -46,6 +41,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 {
@ -75,6 +72,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 {
@ -118,27 +120,63 @@ class TbDateTest {
@Test
void testToISOStringThreadLocalStaticFormatter() throws ExecutionException, InterruptedException, TimeoutException {
executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1));
int hrs = 14;
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
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
Assert.assertEquals(ts, tbDate.parseSecondMilli());
int offsetLocalSecond = tbDate.getLocaleZoneOffset().getTotalSeconds(); // for example 7200 for GMT + 2
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);
assertThat(new TbDate(ts - offset).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(datePrefix);
assertThat(executor.submit(() -> new TbDate(ts - offset).toISOString()).get(30, TimeUnit.SECONDS))
.startsWith(datePrefixLocal);
assertThat(executor.submit(() -> new TbDate(ts + offsetLocalMilli).toISOString()).get(30, TimeUnit.SECONDS))
.as("new instance format in executor thread")
.startsWith(datePrefix);
.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-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"
/**
* For Java 11:
* String[2] { "vorm.", "nachm." }
* For Java 17:
* `{ "AM", "PM" }`
*/
s = "09:15:30 nachm., 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-04T21: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;
Assert.assertNotNull(d.toLocaleDateString());
@ -192,7 +230,6 @@ 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"));
@ -285,25 +322,479 @@ class TbDateTest {
.toString()));
}
private static String toLocalString(TbDate d, Locale locale, ZoneId tz) {
LocalDateTime ldt = d.toInstant().atZone(tz).toLocalDateTime();
@Test
void TestFromString () {
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:00";
d = new TbDate(stringDateTZ);
Assert.assertEquals("2023-09-05T21:04:05Z", d.toISOString());
stringDateTZ = "2023-09-06T01:04:05.00+04";
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);
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());
// new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter(locale)
String stringDateZ_error = "2023-09-06T01:04:05.00+045";
Exception actual = assertThrows(ConversionException.class, () -> {
new TbDate(stringDateZ_error);
});
String expectedMessage = "Cannot parse value";
assertTrue(actual.getMessage().contains(expectedMessage));
String formatPattern =
DateTimeFormatterBuilder.getLocalizedDateTimePattern(
FormatStyle.SHORT,
FormatStyle.MEDIUM,
IsoChronology.INSTANCE,
locale);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatPattern, locale);
return formatter.format(ldt);
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));
}
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 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
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);
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";
String stringDate = "1995-12-04 00:12:00.000";
Assert.assertNotEquals(-1L, TbDate.parse(stringDate, pattern));
}
@Test
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(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());
}
@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 = "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);
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
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 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);
localOffsetMilli = ZoneId.systemDefault().getRules().getOffset(beforeStartUTC.getInstant()).getTotalSeconds()*1000;
Assert.assertEquals((beforeStartUTC.valueOf() + localOffsetMilli), ddUTC.valueOf());
}
@Test
void TestMethodSetUTCFullYearMonthDate() {
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);
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);
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, "+02:00");
TbDate d2 = new TbDate(1975, 12, 31, 23, 15, 30, 567, "-02:00");
testResultChangeDateTime(d1);
testResultChangeDateTime(d2);
d1.setUTCHours(5);
d2.setUTCHours(23);
testResultChangeDateTime(d1);
testResultChangeDateTime(d2);
d1.setUTCHours(23, 45);
d2.setUTCHours(1, 5);
testResultChangeDateTime(d1);
testResultChangeDateTime(d2);
d1.setUTCHours(0, 12, 59);
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);
d2.setUTCMinutes(15);
testResultChangeDateTime(d1);
testResultChangeDateTime(d2);
d1.setUTCMinutes(5, 34);
d2.setUTCMinutes(25, 43);
testResultChangeDateTime(d1);
testResultChangeDateTime(d2);
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 TestMethodSetTime() {
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 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, "+02:00");
TbDate d2 = new TbDate(1975, 12, 31, 23, 15, 30, 567, "-02:00");
testResultChangeDateTime(d1);
testResultChangeDateTime(d2);
d1.setHours(5);
d2.setHours(23);
testResultChangeDateTime(d1);
testResultChangeDateTime(d2);
d1.setHours(23, 45);
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(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(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,"-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"));
}
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());
}
}

View File

@ -0,0 +1,92 @@
/**
* 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);
}
}