use date picker in visualization page

This commit is contained in:
2024-05-05 10:22:45 +02:00
parent a99a884423
commit 21a84b5223
13 changed files with 856 additions and 478 deletions

View File

@@ -25,78 +25,98 @@ public class DateTimeRangeParser {
private static OffsetDateTime parseInternal(final OffsetDateTime offsetTime, final String timeDefinition) {
final Pattern regex = Pattern.compile("(?<beginEnd>[BE]?)(?<amount>\\-?[0-9]*)(?<unit>[mHDWMY])");
final Pattern regex = Pattern.compile("(?<beginEnd>[BE])(?<amountUnit>(\\-?[0-9]*[mHDWMY])+)",
Pattern.MULTILINE);
final Matcher matcher = regex.matcher(timeDefinition);
if (matcher.matches()) {
final String beginEnd = matcher.group("beginEnd");
final boolean begin = "B".equals(beginEnd);
final String amountString = matcher.group("amount");
final int amount = amountString.equals("") ? 0 : Integer.parseInt(amountString);
final String unitString = matcher.group("unit");
switch (unitString) {
case "m": {
final ChronoUnit unit = ChronoUnit.MINUTES;
if (begin) {
return offsetTime.plus(amount, unit).truncatedTo(unit);
} else {
return offsetTime.plus(amount + 1, unit).truncatedTo(unit).minusSeconds(1);
OffsetDateTime result = offsetTime;
final String amountUnitString = matcher.group("amountUnit");
final Pattern regexAmountUnit = Pattern.compile("(?<amount>\\-?[0-9]*)(?<unit>[mHDWMY])");
final Matcher m = regexAmountUnit.matcher(amountUnitString);
while (m.find()) {
final String amountString = m.group("amount");
final String unitString = m.group("unit");
final int amount = amountString.equals("") ? 0 : Integer.parseInt(amountString);
switch (unitString) {
case "m": {
final ChronoUnit unit = ChronoUnit.MINUTES;
if (begin) {
result = result.plus(amount, unit).truncatedTo(unit);
} else {
result = result.plus(amount + 1, unit).truncatedTo(unit).minusSeconds(1);
}
break;
}
case "H": {
final ChronoUnit unit = ChronoUnit.HOURS;
if (begin) {
result = result.plus(amount, unit).truncatedTo(unit);
} else {
result = result.plus(amount + 1, unit).truncatedTo(unit).minusSeconds(1);
}
break;
}
case "D": {
final ChronoUnit unit = ChronoUnit.DAYS;
if (begin) {
result = result.plus(amount, unit).truncatedTo(unit);
} else {
result = result.plus(amount + 1, unit).truncatedTo(unit).minusSeconds(1);
}
break;
}
case "W": {
final DayOfWeek firstDayOfWeek = DayOfWeek.MONDAY;
final DayOfWeek lastDayOfWeek = DayOfWeek
.of(((firstDayOfWeek.getValue() - 1 + 6) % DayOfWeek.values().length) + 1); // weird
// computation,
// because
// DayOfWeek
// goes from 1
// to 7
final ChronoUnit unit = ChronoUnit.WEEKS;
if (begin) {
result = result.plus(amount, unit).with(TemporalAdjusters.previousOrSame(firstDayOfWeek))
.truncatedTo(ChronoUnit.DAYS);
} else {
result = result.plus(amount, unit).with(TemporalAdjusters.nextOrSame(lastDayOfWeek))
.plus(1, ChronoUnit.DAYS).truncatedTo(ChronoUnit.DAYS).minusSeconds(1);
}
break;
}
case "M": {
final ChronoUnit unit = ChronoUnit.MONTHS;
if (begin) {
result = result.plus(amount, unit).truncatedTo(ChronoUnit.DAYS).withDayOfMonth(1);
} else {
result = result.plus(amount, unit).truncatedTo(ChronoUnit.DAYS).withDayOfMonth(1)
.plus(1, ChronoUnit.MONTHS).minusSeconds(1);
}
break;
}
case "Y": {
final ChronoUnit unit = ChronoUnit.YEARS;
if (begin) {
result = result.plus(amount, unit).truncatedTo(ChronoUnit.DAYS).withDayOfYear(1);
} else {
result = result.plus(amount, unit).truncatedTo(ChronoUnit.DAYS).withDayOfYear(1)
.plus(1, ChronoUnit.YEARS).minusSeconds(1);
}
break;
}
default:
throw new IllegalArgumentException("Unexpected value: " + unitString);
}
}
case "H": {
final ChronoUnit unit = ChronoUnit.HOURS;
if (begin) {
return offsetTime.plus(amount, unit).truncatedTo(unit);
} else {
return offsetTime.plus(amount + 1, unit).truncatedTo(unit).minusSeconds(1);
}
}
case "D": {
final ChronoUnit unit = ChronoUnit.DAYS;
if (begin) {
return offsetTime.plus(amount, unit).truncatedTo(unit);
} else {
return offsetTime.plus(amount + 1, unit).truncatedTo(unit).minusSeconds(1);
}
}
case "W": {
final DayOfWeek firstDayOfWeek = DayOfWeek.MONDAY;
final DayOfWeek lastDayOfWeek = DayOfWeek
.of(((firstDayOfWeek.getValue() - 1 + 6) % DayOfWeek.values().length) + 1); // weird
// computation,
// because DayOfWeek
// goes from 1 to 7
final ChronoUnit unit = ChronoUnit.WEEKS;
if (begin) {
return offsetTime.plus(amount, unit).with(TemporalAdjusters.previousOrSame(firstDayOfWeek))
.truncatedTo(ChronoUnit.DAYS);
} else {
return offsetTime.plus(amount, unit).with(TemporalAdjusters.nextOrSame(lastDayOfWeek))
.plus(1, ChronoUnit.DAYS).truncatedTo(ChronoUnit.DAYS).minusSeconds(1);
}
}
case "M": {
final ChronoUnit unit = ChronoUnit.MONTHS;
if (begin) {
return offsetTime.plus(amount, unit).truncatedTo(ChronoUnit.DAYS).withDayOfMonth(1);
} else {
return offsetTime.plus(amount, unit).truncatedTo(ChronoUnit.DAYS).withDayOfMonth(1)
.plus(1, ChronoUnit.MONTHS).minusSeconds(1);
}
}
case "Y": {
final ChronoUnit unit = ChronoUnit.YEARS;
if (begin) {
return offsetTime.plus(amount, unit).truncatedTo(ChronoUnit.DAYS).withDayOfYear(1);
} else {
return offsetTime.plus(amount, unit).truncatedTo(ChronoUnit.DAYS).withDayOfYear(1)
.plus(1, ChronoUnit.YEARS).minusSeconds(1);
}
}
default:
throw new IllegalArgumentException("Unexpected value: " + unitString);
}
return result;
}
throw new IllegalArgumentException("invalid input: " + timeDefinition);

View File

@@ -0,0 +1,38 @@
package org.lucares.pdb.plot.api;
public class DateValue {
public enum DateType {
QUICK, RELATIVE, ABSOLUTE
}
private DateType type;
private String display;
private String value;
public DateType getType() {
return type;
}
public void setType(final DateType type) {
this.type = type;
}
public String getDisplay() {
return display;
}
public void setDisplay(final String display) {
this.display = display;
}
public String getValue() {
return value;
}
public void setValue(final String value) {
this.value = value;
}
}

View File

@@ -17,7 +17,7 @@ import org.lucares.utils.Preconditions;
public class PlotSettings {
private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private String query;
@@ -27,7 +27,7 @@ public class PlotSettings {
private int limit;
private String dateRangeAsString;
private DateValue dateValue;
private YAxisDefinition y1;
private YAxisDefinition y2;
@@ -80,30 +80,37 @@ public class PlotSettings {
this.limit = limit;
}
public String getDateRange() {
return dateRangeAsString;
public DateValue getDateRange() {
return dateValue;
}
public void setDateRange(final String dateRangeAsString) {
this.dateRangeAsString = dateRangeAsString;
public void setDateRange(final DateValue dateValue) {
this.dateValue = dateValue;
}
public DateTimeRange dateRange() {
final String[] startEnd = dateRangeAsString.split(Pattern.quote(" - "));
Preconditions.checkEqual(startEnd.length, 2, "invalid date range: ''{0}''", dateRangeAsString);
switch (this.dateValue.getType()) {
case RELATIVE:
case QUICK:
final DateTimeRange dateTimeRange = DateTimeRangeParser.parse(OffsetDateTime.now(), dateValue.getValue());
return dateTimeRange;
case ABSOLUTE:
final String[] startEnd = dateValue.getValue().split(Pattern.quote(" - "));
Preconditions.checkEqual(startEnd.length, 2, "invalid date range: ''{0}''", dateValue);
final OffsetDateTime startDate = LocalDateTime.parse(startEnd[0], DATE_FORMAT).atOffset(ZoneOffset.UTC);
final OffsetDateTime endDate = LocalDateTime.parse(startEnd[1], DATE_FORMAT).atOffset(ZoneOffset.UTC);
return new DateTimeRange(startDate, endDate);
final OffsetDateTime startDate = LocalDateTime.parse(startEnd[0], DATE_FORMAT).atOffset(ZoneOffset.UTC);
final OffsetDateTime endDate = LocalDateTime.parse(startEnd[1], DATE_FORMAT).atOffset(ZoneOffset.UTC);
return new DateTimeRange(startDate, endDate);
}
throw new UnsupportedOperationException();
}
@Override
public String toString() {
return "PlotSettings [query=" + query + ", groupBy=" + groupBy + ", limitBy=" + limitBy + ", limit=" + limit
+ ", dateRangeAsString=" + dateRangeAsString + ", y1=" + y1 + " y2=" + y2 + ", aggregates=" + aggregates
+ ", dateRangeAsString=" + dateValue + ", y1=" + y1 + " y2=" + y2 + ", aggregates=" + aggregates
+ ", renders=" + renders + "]";
}

View File

@@ -81,11 +81,10 @@ public class DateTimeRangeParserTest {
Arguments.of("2024-03-29 12:00:00", "BY/EY", "2024-01-01 00:00:00", "2024-12-31 23:59:59"),
// previous year
Arguments.of("2024-03-29 12:00:00", "B-1Y/E-1Y", "2023-01-01 00:00:00", "2023-12-31 23:59:59")
Arguments.of("2024-03-29 12:00:00", "B-1Y/E-1Y", "2023-01-01 00:00:00", "2023-12-31 23:59:59"),
//
// Arguments.of("2024-03-29 12:00:00", "B-1H-15m/Bm", "2024-03-29 10:45:00",
// "2024-03-29 12:00:00")
//
Arguments.of("2024-03-29 12:00:00", "B-1H-15m/Bm", "2024-03-29 10:45:00", "2024-03-29 12:00:00")
);
}
@@ -104,4 +103,31 @@ public class DateTimeRangeParserTest {
Assertions.assertEquals(expectedStart, actualStart, "start");
Assertions.assertEquals(expectedEnd, actualEnd, "end");
}
public static Stream<Arguments> providerDatePeriods_multiple() {
return Stream.of(//
//
Arguments.of("2024-03-29 12:00:00", "B-1H-15m/Bm", "2024-03-29 10:45:00", "2024-03-29 12:00:00"),
Arguments.of("2024-03-29 12:00:00", "B-1H-15m/EH15m", "2024-03-29 10:45:00", "2024-03-29 13:14:59")
);
}
@ParameterizedTest
@MethodSource("providerDatePeriods_multiple")
public void testDatePeriods_multiple(final String now, final String datePeriod, final String expectedStart,
final String expectedEnd) throws Exception {
final OffsetDateTime offsetTime = LocalDateTime.parse(now, PlotSettings.DATE_FORMAT).atOffset(ZoneOffset.UTC);
final DateTimeRange actual = DateTimeRangeParser.parse(offsetTime, datePeriod);
final String actualStart = PlotSettings.DATE_FORMAT.format(actual.getStart());
final String actualEnd = PlotSettings.DATE_FORMAT.format(actual.getEnd());
System.out.println("at " + now + " " + datePeriod + " -> " + actualStart + " - " + actualEnd);
Assertions.assertEquals(expectedStart, actualStart, "start");
Assertions.assertEquals(expectedEnd, actualEnd, "end");
}
}